aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/shared-bindings
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/shared-bindings
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/shared-bindings')
-rw-r--r--circuitpython/shared-bindings/__future__/__init__.c60
-rw-r--r--circuitpython/shared-bindings/__future__/__init__.h30
-rw-r--r--circuitpython/shared-bindings/_bleio/Adapter.c468
-rw-r--r--circuitpython/shared-bindings/_bleio/Adapter.h79
-rw-r--r--circuitpython/shared-bindings/_bleio/Address.c219
-rw-r--r--circuitpython/shared-bindings/_bleio/Address.h48
-rw-r--r--circuitpython/shared-bindings/_bleio/Attribute.c82
-rw-r--r--circuitpython/shared-bindings/_bleio/Attribute.h39
-rw-r--r--circuitpython/shared-bindings/_bleio/Characteristic.c334
-rw-r--r--circuitpython/shared-bindings/_bleio/Characteristic.h51
-rw-r--r--circuitpython/shared-bindings/_bleio/CharacteristicBuffer.c242
-rw-r--r--circuitpython/shared-bindings/_bleio/CharacteristicBuffer.h50
-rw-r--r--circuitpython/shared-bindings/_bleio/Connection.c260
-rw-r--r--circuitpython/shared-bindings/_bleio/Connection.h49
-rw-r--r--circuitpython/shared-bindings/_bleio/Descriptor.c216
-rw-r--r--circuitpython/shared-bindings/_bleio/Descriptor.h44
-rw-r--r--circuitpython/shared-bindings/_bleio/PacketBuffer.c239
-rw-r--r--circuitpython/shared-bindings/_bleio/PacketBuffer.h51
-rw-r--r--circuitpython/shared-bindings/_bleio/ScanEntry.c152
-rw-r--r--circuitpython/shared-bindings/_bleio/ScanEntry.h44
-rw-r--r--circuitpython/shared-bindings/_bleio/ScanResults.c71
-rw-r--r--circuitpython/shared-bindings/_bleio/ScanResults.h39
-rw-r--r--circuitpython/shared-bindings/_bleio/Service.c154
-rw-r--r--circuitpython/shared-bindings/_bleio/Service.h49
-rw-r--r--circuitpython/shared-bindings/_bleio/UUID.c300
-rw-r--r--circuitpython/shared-bindings/_bleio/UUID.h44
-rw-r--r--circuitpython/shared-bindings/_bleio/__init__.c205
-rw-r--r--circuitpython/shared-bindings/_bleio/__init__.h83
-rw-r--r--circuitpython/shared-bindings/_eve/__init__.c1109
-rw-r--r--circuitpython/shared-bindings/_eve/__init__.h86
-rw-r--r--circuitpython/shared-bindings/_pew/PewPew.c140
-rw-r--r--circuitpython/shared-bindings/_pew/PewPew.h33
-rw-r--r--circuitpython/shared-bindings/_pew/__init__.c67
-rw-r--r--circuitpython/shared-bindings/_stage/Layer.c129
-rw-r--r--circuitpython/shared-bindings/_stage/Layer.h34
-rw-r--r--circuitpython/shared-bindings/_stage/Text.c108
-rw-r--r--circuitpython/shared-bindings/_stage/Text.h34
-rw-r--r--circuitpython/shared-bindings/_stage/__init__.c111
-rw-r--r--circuitpython/shared-bindings/_stage/__init__.h32
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/__init__.c82
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/__init__.h32
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c288
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h51
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c140
-rw-r--r--circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h50
-rw-r--r--circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.c377
-rw-r--r--circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.h52
-rw-r--r--circuitpython/shared-bindings/adafruit_pixelbuf/__init__.c58
-rw-r--r--circuitpython/shared-bindings/adafruit_pixelbuf/__init__.h30
-rw-r--r--circuitpython/shared-bindings/aesio/__init__.c67
-rw-r--r--circuitpython/shared-bindings/aesio/__init__.h53
-rw-r--r--circuitpython/shared-bindings/aesio/aes.c268
-rw-r--r--circuitpython/shared-bindings/alarm/SleepMemory.c184
-rw-r--r--circuitpython/shared-bindings/alarm/SleepMemory.h40
-rw-r--r--circuitpython/shared-bindings/alarm/__init__.c261
-rw-r--r--circuitpython/shared-bindings/alarm/__init__.h67
-rw-r--r--circuitpython/shared-bindings/alarm/pin/PinAlarm.c127
-rw-r--r--circuitpython/shared-bindings/alarm/pin/PinAlarm.h43
-rw-r--r--circuitpython/shared-bindings/alarm/time/TimeAlarm.c140
-rw-r--r--circuitpython/shared-bindings/alarm/time/TimeAlarm.h39
-rw-r--r--circuitpython/shared-bindings/alarm/touch/TouchAlarm.c87
-rw-r--r--circuitpython/shared-bindings/alarm/touch/TouchAlarm.h40
-rw-r--r--circuitpython/shared-bindings/analogio/AnalogIn.c160
-rw-r--r--circuitpython/shared-bindings/analogio/AnalogIn.h41
-rw-r--r--circuitpython/shared-bindings/analogio/AnalogOut.c141
-rw-r--r--circuitpython/shared-bindings/analogio/AnalogOut.h40
-rw-r--r--circuitpython/shared-bindings/analogio/__init__.c83
-rw-r--r--circuitpython/shared-bindings/analogio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/atexit/__init__.c96
-rw-r--r--circuitpython/shared-bindings/audiobusio/I2SOut.c279
-rw-r--r--circuitpython/shared-bindings/audiobusio/I2SOut.h53
-rw-r--r--circuitpython/shared-bindings/audiobusio/PDMIn.c250
-rw-r--r--circuitpython/shared-bindings/audiobusio/PDMIn.h49
-rw-r--r--circuitpython/shared-bindings/audiobusio/__init__.c62
-rw-r--r--circuitpython/shared-bindings/audiobusio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/audiocore/RawSample.c190
-rw-r--r--circuitpython/shared-bindings/audiocore/RawSample.h45
-rw-r--r--circuitpython/shared-bindings/audiocore/WaveFile.c214
-rw-r--r--circuitpython/shared-bindings/audiocore/WaveFile.h47
-rw-r--r--circuitpython/shared-bindings/audiocore/__init__.c54
-rw-r--r--circuitpython/shared-bindings/audiocore/__init__.h34
-rw-r--r--circuitpython/shared-bindings/audioio/AudioOut.c269
-rw-r--r--circuitpython/shared-bindings/audioio/AudioOut.h49
-rw-r--r--circuitpython/shared-bindings/audioio/__init__.c65
-rw-r--r--circuitpython/shared-bindings/audioio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/audiomixer/Mixer.c294
-rw-r--r--circuitpython/shared-bindings/audiomixer/Mixer.h53
-rw-r--r--circuitpython/shared-bindings/audiomixer/MixerVoice.c168
-rw-r--r--circuitpython/shared-bindings/audiomixer/MixerVoice.h47
-rw-r--r--circuitpython/shared-bindings/audiomixer/__init__.c50
-rw-r--r--circuitpython/shared-bindings/audiomixer/__init__.h34
-rw-r--r--circuitpython/shared-bindings/audiomp3/MP3Decoder.c286
-rw-r--r--circuitpython/shared-bindings/audiomp3/MP3Decoder.h51
-rw-r--r--circuitpython/shared-bindings/audiomp3/__init__.c54
-rw-r--r--circuitpython/shared-bindings/audiomp3/__init__.h34
-rw-r--r--circuitpython/shared-bindings/audiopwmio/PWMAudioOut.c270
-rw-r--r--circuitpython/shared-bindings/audiopwmio/PWMAudioOut.h49
-rw-r--r--circuitpython/shared-bindings/audiopwmio/__init__.c61
-rw-r--r--circuitpython/shared-bindings/audiopwmio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/bitbangio/I2C.c351
-rw-r--r--circuitpython/shared-bindings/bitbangio/I2C.h65
-rw-r--r--circuitpython/shared-bindings/bitbangio/SPI.c383
-rw-r--r--circuitpython/shared-bindings/bitbangio/SPI.h62
-rw-r--r--circuitpython/shared-bindings/bitbangio/__init__.c88
-rw-r--r--circuitpython/shared-bindings/bitbangio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/bitmaptools/__init__.c766
-rw-r--r--circuitpython/shared-bindings/bitmaptools/__init__.h73
-rw-r--r--circuitpython/shared-bindings/bitops/__init__.c103
-rw-r--r--circuitpython/shared-bindings/bitops/__init__.h32
-rw-r--r--circuitpython/shared-bindings/board/__init__.c118
-rw-r--r--circuitpython/shared-bindings/board/__init__.h66
-rw-r--r--circuitpython/shared-bindings/busio/I2C.c372
-rw-r--r--circuitpython/shared-bindings/busio/I2C.h78
-rw-r--r--circuitpython/shared-bindings/busio/SPI.c463
-rw-r--r--circuitpython/shared-bindings/busio/SPI.h75
-rw-r--r--circuitpython/shared-bindings/busio/UART.c462
-rw-r--r--circuitpython/shared-bindings/busio/UART.h73
-rw-r--r--circuitpython/shared-bindings/busio/__init__.c103
-rw-r--r--circuitpython/shared-bindings/busio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/camera/Camera.c132
-rw-r--r--circuitpython/shared-bindings/camera/Camera.h40
-rw-r--r--circuitpython/shared-bindings/camera/ImageFormat.c92
-rw-r--r--circuitpython/shared-bindings/camera/ImageFormat.h49
-rw-r--r--circuitpython/shared-bindings/camera/__init__.c52
-rw-r--r--circuitpython/shared-bindings/canio/CAN.c360
-rw-r--r--circuitpython/shared-bindings/canio/CAN.h52
-rw-r--r--circuitpython/shared-bindings/canio/Listener.c178
-rw-r--r--circuitpython/shared-bindings/canio/Listener.h43
-rw-r--r--circuitpython/shared-bindings/canio/Match.c127
-rw-r--r--circuitpython/shared-bindings/canio/Match.h37
-rw-r--r--circuitpython/shared-bindings/canio/Message.c150
-rw-r--r--circuitpython/shared-bindings/canio/Message.h42
-rw-r--r--circuitpython/shared-bindings/canio/RemoteTransmissionRequest.c147
-rw-r--r--circuitpython/shared-bindings/canio/RemoteTransmissionRequest.h42
-rw-r--r--circuitpython/shared-bindings/canio/__init__.c128
-rw-r--r--circuitpython/shared-bindings/canio/__init__.h33
-rw-r--r--circuitpython/shared-bindings/countio/Counter.c149
-rw-r--r--circuitpython/shared-bindings/countio/Counter.h19
-rw-r--r--circuitpython/shared-bindings/countio/Edge.c67
-rw-r--r--circuitpython/shared-bindings/countio/Edge.h44
-rw-r--r--circuitpython/shared-bindings/countio/__init__.c35
-rw-r--r--circuitpython/shared-bindings/countio/__init__.h9
-rw-r--r--circuitpython/shared-bindings/digitalio/DigitalInOut.c363
-rw-r--r--circuitpython/shared-bindings/digitalio/DigitalInOut.h70
-rw-r--r--circuitpython/shared-bindings/digitalio/Direction.c84
-rw-r--r--circuitpython/shared-bindings/digitalio/Direction.h45
-rw-r--r--circuitpython/shared-bindings/digitalio/DriveMode.c73
-rw-r--r--circuitpython/shared-bindings/digitalio/DriveMode.h46
-rw-r--r--circuitpython/shared-bindings/digitalio/Pull.c87
-rw-r--r--circuitpython/shared-bindings/digitalio/Pull.h48
-rw-r--r--circuitpython/shared-bindings/digitalio/__init__.c100
-rw-r--r--circuitpython/shared-bindings/digitalio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/displayio/Bitmap.c370
-rw-r--r--circuitpython/shared-bindings/displayio/Bitmap.h50
-rw-r--r--circuitpython/shared-bindings/displayio/ColorConverter.c152
-rw-r--r--circuitpython/shared-bindings/displayio/ColorConverter.h47
-rw-r--r--circuitpython/shared-bindings/displayio/Colorspace.c77
-rw-r--r--circuitpython/shared-bindings/displayio/Display.c524
-rw-r--r--circuitpython/shared-bindings/displayio/Display.h74
-rw-r--r--circuitpython/shared-bindings/displayio/EPaperDisplay.c363
-rw-r--r--circuitpython/shared-bindings/displayio/EPaperDisplay.h62
-rw-r--r--circuitpython/shared-bindings/displayio/FourWire.c172
-rw-r--r--circuitpython/shared-bindings/displayio/FourWire.h56
-rw-r--r--circuitpython/shared-bindings/displayio/Group.c355
-rw-r--r--circuitpython/shared-bindings/displayio/Group.h53
-rw-r--r--circuitpython/shared-bindings/displayio/I2CDisplay.c134
-rw-r--r--circuitpython/shared-bindings/displayio/I2CDisplay.h52
-rw-r--r--circuitpython/shared-bindings/displayio/OnDiskBitmap.c161
-rw-r--r--circuitpython/shared-bindings/displayio/OnDiskBitmap.h43
-rw-r--r--circuitpython/shared-bindings/displayio/Palette.c216
-rw-r--r--circuitpython/shared-bindings/displayio/Palette.h43
-rw-r--r--circuitpython/shared-bindings/displayio/Shape.c117
-rw-r--r--circuitpython/shared-bindings/displayio/Shape.h41
-rw-r--r--circuitpython/shared-bindings/displayio/TileGrid.c502
-rw-r--r--circuitpython/shared-bindings/displayio/TileGrid.h71
-rw-r--r--circuitpython/shared-bindings/displayio/__init__.c106
-rw-r--r--circuitpython/shared-bindings/displayio/__init__.h68
-rw-r--r--circuitpython/shared-bindings/displayio/area.c0
-rw-r--r--circuitpython/shared-bindings/dualbank/__init__.c117
-rw-r--r--circuitpython/shared-bindings/dualbank/__init__.h35
-rw-r--r--circuitpython/shared-bindings/floppyio/__init__.c128
-rw-r--r--circuitpython/shared-bindings/floppyio/__init__.h32
-rw-r--r--circuitpython/shared-bindings/fontio/BuiltinFont.c120
-rw-r--r--circuitpython/shared-bindings/fontio/BuiltinFont.h38
-rw-r--r--circuitpython/shared-bindings/fontio/Glyph.c84
-rw-r--r--circuitpython/shared-bindings/fontio/Glyph.h34
-rw-r--r--circuitpython/shared-bindings/fontio/__init__.c60
-rw-r--r--circuitpython/shared-bindings/fontio/__init__.h31
-rw-r--r--circuitpython/shared-bindings/framebufferio/FramebufferDisplay.c378
-rw-r--r--circuitpython/shared-bindings/framebufferio/FramebufferDisplay.h67
-rw-r--r--circuitpython/shared-bindings/framebufferio/__init__.c54
-rw-r--r--circuitpython/shared-bindings/framebufferio/__init__.h0
-rw-r--r--circuitpython/shared-bindings/frequencyio/FrequencyIn.c234
-rw-r--r--circuitpython/shared-bindings/frequencyio/FrequencyIn.h46
-rw-r--r--circuitpython/shared-bindings/frequencyio/__init__.c76
-rw-r--r--circuitpython/shared-bindings/frequencyio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/gamepadshift/GamePadShift.c123
-rw-r--r--circuitpython/shared-bindings/gamepadshift/GamePadShift.h42
-rw-r--r--circuitpython/shared-bindings/gamepadshift/__init__.c51
-rw-r--r--circuitpython/shared-bindings/gamepadshift/__init__.h31
-rw-r--r--circuitpython/shared-bindings/getpass/__init__.c88
-rw-r--r--circuitpython/shared-bindings/gifio/GifWriter.c161
-rw-r--r--circuitpython/shared-bindings/gifio/GifWriter.h41
-rw-r--r--circuitpython/shared-bindings/gifio/__init__.c47
-rw-r--r--circuitpython/shared-bindings/gifio/__init__.h0
-rw-r--r--circuitpython/shared-bindings/gnss/GNSS.c185
-rw-r--r--circuitpython/shared-bindings/gnss/GNSS.h27
-rw-r--r--circuitpython/shared-bindings/gnss/PositionFix.c80
-rw-r--r--circuitpython/shared-bindings/gnss/PositionFix.h28
-rw-r--r--circuitpython/shared-bindings/gnss/SatelliteSystem.c113
-rw-r--r--circuitpython/shared-bindings/gnss/SatelliteSystem.h33
-rw-r--r--circuitpython/shared-bindings/gnss/__init__.c33
-rw-r--r--circuitpython/shared-bindings/help.rst31
-rw-r--r--circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.c436
-rw-r--r--circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.h60
-rw-r--r--circuitpython/shared-bindings/i2cperipheral/__init__.c108
-rw-r--r--circuitpython/shared-bindings/imagecapture/ParallelImageCapture.c200
-rw-r--r--circuitpython/shared-bindings/imagecapture/ParallelImageCapture.h46
-rw-r--r--circuitpython/shared-bindings/imagecapture/__init__.c49
-rw-r--r--circuitpython/shared-bindings/imagecapture/__init__.h27
-rw-r--r--circuitpython/shared-bindings/index.rst23
-rw-r--r--circuitpython/shared-bindings/ipaddress/IPv4Address.c194
-rw-r--r--circuitpython/shared-bindings/ipaddress/IPv4Address.h38
-rw-r--r--circuitpython/shared-bindings/ipaddress/__init__.c115
-rw-r--r--circuitpython/shared-bindings/ipaddress/__init__.h36
-rw-r--r--circuitpython/shared-bindings/is31fl3741/FrameBuffer.c301
-rw-r--r--circuitpython/shared-bindings/is31fl3741/FrameBuffer.h50
-rw-r--r--circuitpython/shared-bindings/is31fl3741/IS31FL3741.c180
-rw-r--r--circuitpython/shared-bindings/is31fl3741/IS31FL3741.h49
-rw-r--r--circuitpython/shared-bindings/is31fl3741/__init__.c50
-rw-r--r--circuitpython/shared-bindings/keypad/Event.c197
-rw-r--r--circuitpython/shared-bindings/keypad/Event.h41
-rw-r--r--circuitpython/shared-bindings/keypad/EventQueue.c152
-rw-r--r--circuitpython/shared-bindings/keypad/EventQueue.h45
-rw-r--r--circuitpython/shared-bindings/keypad/KeyMatrix.c236
-rw-r--r--circuitpython/shared-bindings/keypad/KeyMatrix.h45
-rw-r--r--circuitpython/shared-bindings/keypad/Keys.c168
-rw-r--r--circuitpython/shared-bindings/keypad/Keys.h39
-rw-r--r--circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c172
-rw-r--r--circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h39
-rw-r--r--circuitpython/shared-bindings/keypad/__init__.c108
-rw-r--r--circuitpython/shared-bindings/keypad/__init__.h44
-rw-r--r--circuitpython/shared-bindings/math/__init__.c479
-rw-r--r--circuitpython/shared-bindings/mdns/RemoteService.c136
-rw-r--r--circuitpython/shared-bindings/mdns/RemoteService.h41
-rw-r--r--circuitpython/shared-bindings/mdns/Server.c208
-rw-r--r--circuitpython/shared-bindings/mdns/Server.h43
-rw-r--r--circuitpython/shared-bindings/mdns/__init__.c56
-rw-r--r--circuitpython/shared-bindings/mdns/__init__.h27
-rw-r--r--circuitpython/shared-bindings/memorymonitor/AllocationAlarm.c137
-rw-r--r--circuitpython/shared-bindings/memorymonitor/AllocationAlarm.h39
-rw-r--r--circuitpython/shared-bindings/memorymonitor/AllocationSize.c182
-rw-r--r--circuitpython/shared-bindings/memorymonitor/AllocationSize.h42
-rw-r--r--circuitpython/shared-bindings/memorymonitor/__init__.c78
-rw-r--r--circuitpython/shared-bindings/memorymonitor/__init__.h49
-rw-r--r--circuitpython/shared-bindings/microcontroller/Pin.c196
-rw-r--r--circuitpython/shared-bindings/microcontroller/Pin.h57
-rw-r--r--circuitpython/shared-bindings/microcontroller/Processor.c165
-rw-r--r--circuitpython/shared-bindings/microcontroller/Processor.h44
-rw-r--r--circuitpython/shared-bindings/microcontroller/ResetReason.c82
-rw-r--r--circuitpython/shared-bindings/microcontroller/ResetReason.h46
-rw-r--r--circuitpython/shared-bindings/microcontroller/RunMode.c101
-rw-r--r--circuitpython/shared-bindings/microcontroller/RunMode.h50
-rw-r--r--circuitpython/shared-bindings/microcontroller/__init__.c198
-rw-r--r--circuitpython/shared-bindings/microcontroller/__init__.h68
-rw-r--r--circuitpython/shared-bindings/msgpack/ExtType.c120
-rw-r--r--circuitpython/shared-bindings/msgpack/ExtType.h40
-rw-r--r--circuitpython/shared-bindings/msgpack/__init__.c164
-rw-r--r--circuitpython/shared-bindings/msgpack/__init__.h34
-rw-r--r--circuitpython/shared-bindings/multiterminal/__init__.c110
-rw-r--r--circuitpython/shared-bindings/multiterminal/__init__.h37
-rw-r--r--circuitpython/shared-bindings/neopixel_write/__init__.c145
-rw-r--r--circuitpython/shared-bindings/neopixel_write/__init__.h37
-rw-r--r--circuitpython/shared-bindings/nvm/ByteArray.c178
-rw-r--r--circuitpython/shared-bindings/nvm/ByteArray.h43
-rw-r--r--circuitpython/shared-bindings/nvm/__init__.c53
-rw-r--r--circuitpython/shared-bindings/nvm/__init__.h30
-rw-r--r--circuitpython/shared-bindings/onewireio/OneWire.c170
-rw-r--r--circuitpython/shared-bindings/onewireio/OneWire.h43
-rw-r--r--circuitpython/shared-bindings/onewireio/__init__.c55
-rw-r--r--circuitpython/shared-bindings/onewireio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/os/__init__.c250
-rw-r--r--circuitpython/shared-bindings/os/__init__.h51
-rw-r--r--circuitpython/shared-bindings/paralleldisplay/ParallelBus.c160
-rw-r--r--circuitpython/shared-bindings/paralleldisplay/ParallelBus.h55
-rw-r--r--circuitpython/shared-bindings/paralleldisplay/__init__.c51
-rw-r--r--circuitpython/shared-bindings/paralleldisplay/__init__.h27
-rw-r--r--circuitpython/shared-bindings/ps2io/Ps2.c247
-rw-r--r--circuitpython/shared-bindings/ps2io/Ps2.h45
-rw-r--r--circuitpython/shared-bindings/ps2io/__init__.c63
-rw-r--r--circuitpython/shared-bindings/ps2io/__init__.h35
-rw-r--r--circuitpython/shared-bindings/pulseio/PulseIn.c312
-rw-r--r--circuitpython/shared-bindings/pulseio/PulseIn.h48
-rw-r--r--circuitpython/shared-bindings/pulseio/PulseOut.c170
-rw-r--r--circuitpython/shared-bindings/pulseio/PulseOut.h46
-rw-r--r--circuitpython/shared-bindings/pulseio/__init__.c62
-rw-r--r--circuitpython/shared-bindings/pulseio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/pwmio/PWMOut.c284
-rw-r--r--circuitpython/shared-bindings/pwmio/PWMOut.h67
-rw-r--r--circuitpython/shared-bindings/pwmio/__init__.c79
-rw-r--r--circuitpython/shared-bindings/pwmio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/qrio/PixelPolicy.c56
-rw-r--r--circuitpython/shared-bindings/qrio/PixelPolicy.h39
-rw-r--r--circuitpython/shared-bindings/qrio/QRDecoder.c149
-rw-r--r--circuitpython/shared-bindings/qrio/QRDecoder.h37
-rw-r--r--circuitpython/shared-bindings/qrio/QRInfo.c64
-rw-r--r--circuitpython/shared-bindings/qrio/QRInfo.h31
-rw-r--r--circuitpython/shared-bindings/qrio/__init__.c59
-rw-r--r--circuitpython/shared-bindings/qrio/__init__.h27
-rw-r--r--circuitpython/shared-bindings/rainbowio/__init__.c57
-rw-r--r--circuitpython/shared-bindings/rainbowio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/random/__init__.c191
-rw-r--r--circuitpython/shared-bindings/random/__init__.h40
-rw-r--r--circuitpython/shared-bindings/rgbmatrix/RGBMatrix.c447
-rw-r--r--circuitpython/shared-bindings/rgbmatrix/RGBMatrix.h42
-rw-r--r--circuitpython/shared-bindings/rgbmatrix/__init__.c49
-rw-r--r--circuitpython/shared-bindings/rotaryio/IncrementalEncoder.c188
-rw-r--r--circuitpython/shared-bindings/rotaryio/IncrementalEncoder.h46
-rw-r--r--circuitpython/shared-bindings/rotaryio/__init__.c60
-rw-r--r--circuitpython/shared-bindings/rotaryio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/rtc/RTC.c133
-rw-r--r--circuitpython/shared-bindings/rtc/RTC.h50
-rw-r--r--circuitpython/shared-bindings/rtc/__init__.c90
-rw-r--r--circuitpython/shared-bindings/rtc/__init__.h35
-rw-r--r--circuitpython/shared-bindings/sdcardio/SDCard.c206
-rw-r--r--circuitpython/shared-bindings/sdcardio/SDCard.h30
-rw-r--r--circuitpython/shared-bindings/sdcardio/__init__.c49
-rw-r--r--circuitpython/shared-bindings/sdcardio/__init__.h0
-rw-r--r--circuitpython/shared-bindings/sdioio/SDCard.c288
-rw-r--r--circuitpython/shared-bindings/sdioio/SDCard.h66
-rw-r--r--circuitpython/shared-bindings/sdioio/__init__.c49
-rw-r--r--circuitpython/shared-bindings/sdioio/__init__.h0
-rw-r--r--circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c95
-rw-r--r--circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h34
-rw-r--r--circuitpython/shared-bindings/sharpdisplay/__init__.c49
-rw-r--r--circuitpython/shared-bindings/sharpdisplay/__init__.h0
-rw-r--r--circuitpython/shared-bindings/socketpool/Socket.c404
-rw-r--r--circuitpython/shared-bindings/socketpool/Socket.h50
-rw-r--r--circuitpython/shared-bindings/socketpool/SocketPool.c166
-rw-r--r--circuitpython/shared-bindings/socketpool/SocketPool.h55
-rw-r--r--circuitpython/shared-bindings/socketpool/__init__.c58
-rw-r--r--circuitpython/shared-bindings/socketpool/__init__.h30
-rw-r--r--circuitpython/shared-bindings/ssl/SSLContext.c158
-rw-r--r--circuitpython/shared-bindings/ssl/SSLContext.h50
-rw-r--r--circuitpython/shared-bindings/ssl/SSLSocket.c318
-rw-r--r--circuitpython/shared-bindings/ssl/SSLSocket.h45
-rw-r--r--circuitpython/shared-bindings/ssl/__init__.c70
-rw-r--r--circuitpython/shared-bindings/ssl/__init__.h34
-rw-r--r--circuitpython/shared-bindings/storage/__init__.c283
-rw-r--r--circuitpython/shared-bindings/storage/__init__.h45
-rw-r--r--circuitpython/shared-bindings/struct/__init__.c181
-rw-r--r--circuitpython/shared-bindings/struct/__init__.h34
-rw-r--r--circuitpython/shared-bindings/supervisor/RunReason.c62
-rw-r--r--circuitpython/shared-bindings/supervisor/RunReason.h36
-rw-r--r--circuitpython/shared-bindings/supervisor/Runtime.c131
-rw-r--r--circuitpython/shared-bindings/supervisor/Runtime.h48
-rw-r--r--circuitpython/shared-bindings/supervisor/__init__.c337
-rw-r--r--circuitpython/shared-bindings/supervisor/__init__.h39
-rw-r--r--circuitpython/shared-bindings/support_matrix.rst34
-rw-r--r--circuitpython/shared-bindings/synthio/MidiTrack.c168
-rw-r--r--circuitpython/shared-bindings/synthio/MidiTrack.h43
-rw-r--r--circuitpython/shared-bindings/synthio/__init__.c138
-rw-r--r--circuitpython/shared-bindings/synthio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/terminalio/Terminal.c126
-rw-r--r--circuitpython/shared-bindings/terminalio/Terminal.h45
-rw-r--r--circuitpython/shared-bindings/terminalio/__init__.c65
-rw-r--r--circuitpython/shared-bindings/terminalio/__init__.h32
-rw-r--r--circuitpython/shared-bindings/time/__init__.c348
-rw-r--r--circuitpython/shared-bindings/time/__init__.h42
-rw-r--r--circuitpython/shared-bindings/touchio/TouchIn.c200
-rw-r--r--circuitpython/shared-bindings/touchio/TouchIn.h48
-rw-r--r--circuitpython/shared-bindings/touchio/__init__.c72
-rw-r--r--circuitpython/shared-bindings/touchio/__init__.h34
-rw-r--r--circuitpython/shared-bindings/traceback/__init__.c175
-rw-r--r--circuitpython/shared-bindings/uheap/__init__.c61
-rw-r--r--circuitpython/shared-bindings/uheap/__init__.h34
-rw-r--r--circuitpython/shared-bindings/usb/__init__.c52
-rw-r--r--circuitpython/shared-bindings/usb/__init__.h27
-rw-r--r--circuitpython/shared-bindings/usb/core/Device.c312
-rw-r--r--circuitpython/shared-bindings/usb/core/Device.h53
-rw-r--r--circuitpython/shared-bindings/usb/core/__init__.c193
-rw-r--r--circuitpython/shared-bindings/usb/core/__init__.h54
-rw-r--r--circuitpython/shared-bindings/usb_cdc/Serial.c303
-rw-r--r--circuitpython/shared-bindings/usb_cdc/Serial.h53
-rw-r--r--circuitpython/shared-bindings/usb_cdc/__init__.c143
-rw-r--r--circuitpython/shared-bindings/usb_cdc/__init__.h39
-rw-r--r--circuitpython/shared-bindings/usb_hid/Device.c289
-rw-r--r--circuitpython/shared-bindings/usb_hid/Device.h43
-rw-r--r--circuitpython/shared-bindings/usb_hid/__init__.c186
-rw-r--r--circuitpython/shared-bindings/usb_hid/__init__.h42
-rw-r--r--circuitpython/shared-bindings/usb_host/Port.c103
-rw-r--r--circuitpython/shared-bindings/usb_host/Port.h42
-rw-r--r--circuitpython/shared-bindings/usb_host/__init__.c53
-rw-r--r--circuitpython/shared-bindings/usb_host/__init__.h27
-rw-r--r--circuitpython/shared-bindings/usb_midi/PortIn.c124
-rw-r--r--circuitpython/shared-bindings/usb_midi/PortIn.h41
-rw-r--r--circuitpython/shared-bindings/usb_midi/PortOut.c105
-rw-r--r--circuitpython/shared-bindings/usb_midi/PortOut.h40
-rw-r--r--circuitpython/shared-bindings/usb_midi/__init__.c98
-rw-r--r--circuitpython/shared-bindings/usb_midi/__init__.h38
-rw-r--r--circuitpython/shared-bindings/ustack/__init__.c89
-rw-r--r--circuitpython/shared-bindings/ustack/__init__.h38
-rw-r--r--circuitpython/shared-bindings/util.c41
-rw-r--r--circuitpython/shared-bindings/util.h33
-rw-r--r--circuitpython/shared-bindings/vectorio/Circle.c141
-rw-r--r--circuitpython/shared-bindings/vectorio/Circle.h27
-rw-r--r--circuitpython/shared-bindings/vectorio/Polygon.c147
-rw-r--r--circuitpython/shared-bindings/vectorio/Polygon.h29
-rw-r--r--circuitpython/shared-bindings/vectorio/Rectangle.c173
-rw-r--r--circuitpython/shared-bindings/vectorio/Rectangle.h28
-rw-r--r--circuitpython/shared-bindings/vectorio/VectorShape.c223
-rw-r--r--circuitpython/shared-bindings/vectorio/VectorShape.h47
-rw-r--r--circuitpython/shared-bindings/vectorio/__init__.c49
-rw-r--r--circuitpython/shared-bindings/vectorio/__init__.h41
-rw-r--r--circuitpython/shared-bindings/watchdog/WatchDogMode.c98
-rw-r--r--circuitpython/shared-bindings/watchdog/WatchDogMode.h49
-rw-r--r--circuitpython/shared-bindings/watchdog/WatchDogTimer.c175
-rw-r--r--circuitpython/shared-bindings/watchdog/WatchDogTimer.h48
-rw-r--r--circuitpython/shared-bindings/watchdog/__init__.c107
-rw-r--r--circuitpython/shared-bindings/watchdog/__init__.h37
-rw-r--r--circuitpython/shared-bindings/wifi/AuthMode.c76
-rw-r--r--circuitpython/shared-bindings/wifi/AuthMode.h45
-rw-r--r--circuitpython/shared-bindings/wifi/Monitor.c171
-rw-r--r--circuitpython/shared-bindings/wifi/Monitor.h50
-rw-r--r--circuitpython/shared-bindings/wifi/Network.c134
-rw-r--r--circuitpython/shared-bindings/wifi/Network.h45
-rw-r--r--circuitpython/shared-bindings/wifi/Packet.c70
-rw-r--r--circuitpython/shared-bindings/wifi/Packet.h41
-rw-r--r--circuitpython/shared-bindings/wifi/Radio.c542
-rw-r--r--circuitpython/shared-bindings/wifi/Radio.h107
-rw-r--r--circuitpython/shared-bindings/wifi/ScannedNetworks.c72
-rw-r--r--circuitpython/shared-bindings/wifi/ScannedNetworks.h39
-rw-r--r--circuitpython/shared-bindings/wifi/__init__.c74
-rw-r--r--circuitpython/shared-bindings/wifi/__init__.h37
-rw-r--r--circuitpython/shared-bindings/zlib/__init__.c95
-rw-r--r--circuitpython/shared-bindings/zlib/__init__.h32
436 files changed, 47390 insertions, 0 deletions
diff --git a/circuitpython/shared-bindings/__future__/__init__.c b/circuitpython/shared-bindings/__future__/__init__.c
new file mode 100644
index 0000000..ad1bb3b
--- /dev/null
+++ b/circuitpython/shared-bindings/__future__/__init__.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "extmod/vfs.h"
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/__future__/__init__.h"
+
+//| """Language features module
+//|
+//| The `__future__` module is used by other Python implementations to
+//| enable forward compatibility for features enabled by default in an upcoming version.
+//| """
+//|
+//| annotations: Any
+//| """In CPython, ``from __future import annotations``
+//| indicates that evaluation of annotations is postponed, as described in PEP 563.
+//| CircuitPython (and MicroPython) ignore annotations entirely, whether or not this feature is imported.
+//| This is a limitation of CircuitPython and MicroPython for efficiency reasons.
+//| """
+
+STATIC const mp_rom_map_elem_t future_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR___future__) },
+
+ { MP_ROM_QSTR(MP_QSTR_annotations), mp_const_true },
+};
+
+STATIC MP_DEFINE_CONST_DICT(future_module_globals, future_module_globals_table);
+
+const mp_obj_module_t future_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&future_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR___future__, future_module, CIRCUITPY_FUTURE);
diff --git a/circuitpython/shared-bindings/__future__/__init__.h b/circuitpython/shared-bindings/__future__/__init__.h
new file mode 100644
index 0000000..c1dd0e1
--- /dev/null
+++ b/circuitpython/shared-bindings/__future__/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS___FUTURE_____INIT___H
diff --git a/circuitpython/shared-bindings/_bleio/Adapter.c b/circuitpython/shared-bindings/_bleio/Adapter.c
new file mode 100644
index 0000000..ce10809
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Adapter.c
@@ -0,0 +1,468 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-bindings/_bleio/Adapter.h"
+
+#define ADV_INTERVAL_MIN (0.02f)
+#define ADV_INTERVAL_MIN_STRING "0.02"
+#define ADV_INTERVAL_MAX (10.24f)
+#define ADV_INTERVAL_MAX_STRING "10.24"
+// 20ms is recommended by Apple
+#define ADV_INTERVAL_DEFAULT (0.1f)
+
+#define INTERVAL_DEFAULT (0.1f)
+#define INTERVAL_MIN (0.0025f)
+#define INTERVAL_MIN_STRING "0.0025"
+#define INTERVAL_MAX (40.959375f)
+#define INTERVAL_MAX_STRING "40.959375"
+#define WINDOW_DEFAULT (0.1f)
+
+//| class Adapter:
+//| """
+//| The BLE Adapter object manages the discovery and connection to other nearby Bluetooth Low Energy devices.
+//| This part of the Bluetooth Low Energy Specification is known as Generic Access Profile (GAP).
+//|
+//| Discovery of other devices happens during a scanning process that listens for small packets of
+//| information, known as advertisements, that are broadcast unencrypted. The advertising packets
+//| have two different uses. The first is to broadcast a small piece of data to anyone who cares and
+//| and nothing more. These are known as beacons. The second class of advertisement is to promote
+//| additional functionality available after the devices establish a connection. For example, a
+//| BLE heart rate monitor would advertise that it provides the standard BLE Heart Rate Service.
+//|
+//| The Adapter can do both parts of this process: it can scan for other device
+//| advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming
+//| connections and also initiate connections."""
+//|
+
+//| def __init__(self, *, uart: busio.UART, rts: digitalio.DigitalInOut, cts: digitalio.DigitalInOut) -> None:
+//| """On boards that do not have native BLE, you can use an HCI co-processor.
+//| Pass the uart and pins used to communicate with the co-processor, such as an Adafruit AirLift.
+//| The co-processor must have been reset and put into BLE mode beforehand
+//| by the appropriate pin manipulation.
+//| The ``uart``, ``rts``, and ``cts`` objects are used to
+//| communicate with the HCI co-processor in HCI mode.
+//| The `Adapter` object is enabled during this call.
+//|
+//| After instantiating an Adapter, call `_bleio.set_adapter()` to set `_bleio.adapter`
+//|
+//| On boards with native BLE, you cannot create an instance of `_bleio.Adapter`;
+//| this constructor will raise `NotImplementedError`.
+//| Use `_bleio.adapter` to access the sole instance already available.
+//| """
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ #if CIRCUITPY_BLEIO_HCI
+ bleio_adapter_obj_t *self = common_hal_bleio_allocate_adapter_or_raise();
+
+ enum { ARG_uart, ARG_rts, ARG_cts };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_uart, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ busio_uart_obj_t *uart = mp_arg_validate_type(args[ARG_uart].u_obj, &busio_uart_type, MP_QSTR_uart);
+
+ digitalio_digitalinout_obj_t *rts = mp_arg_validate_type(args[ARG_rts].u_obj, &digitalio_digitalinout_type, MP_QSTR_rts);
+ digitalio_digitalinout_obj_t *cts = mp_arg_validate_type(args[ARG_cts].u_obj, &digitalio_digitalinout_type, MP_QSTR_cts);
+
+ // Will enable the adapter.
+ common_hal_bleio_adapter_construct_hci_uart(self, uart, rts, cts);
+
+ return MP_OBJ_FROM_PTR(self);
+ #else
+ mp_raise_NotImplementedError(translate("Cannot create a new Adapter; use _bleio.adapter;"));
+ return mp_const_none;
+ #endif // CIRCUITPY_BLEIO_HCI
+}
+
+//|
+//| enabled: bool
+//| """State of the BLE adapter."""
+//|
+STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_enabled_obj, bleio_adapter_get_enabled);
+
+static mp_obj_t bleio_adapter_set_enabled(mp_obj_t self, mp_obj_t value) {
+ const bool enabled = mp_obj_is_true(value);
+
+ common_hal_bleio_adapter_set_enabled(self, enabled);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_enabled_obj, bleio_adapter_set_enabled);
+
+MP_PROPERTY_GETSET(bleio_adapter_enabled_obj,
+ (mp_obj_t)&bleio_adapter_get_enabled_obj,
+ (mp_obj_t)&bleio_adapter_set_enabled_obj);
+
+//| address: Address
+//| """MAC address of the BLE adapter."""
+//|
+STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) {
+ return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address(self));
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address);
+
+STATIC mp_obj_t bleio_adapter_set_address(mp_obj_t self, mp_obj_t new_address) {
+ if (!common_hal_bleio_adapter_set_address(self, new_address)) {
+ mp_raise_bleio_BluetoothError(translate("Could not set address"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_address_obj, bleio_adapter_set_address);
+
+MP_PROPERTY_GETSET(bleio_adapter_address_obj,
+ (mp_obj_t)&bleio_adapter_get_address_obj,
+ (mp_obj_t)&bleio_adapter_set_address_obj);
+
+//| name: str
+//| """name of the BLE adapter used once connected.
+//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``,
+//| to make it easy to distinguish multiple CircuitPython boards."""
+//|
+STATIC mp_obj_t bleio_adapter_get_name(mp_obj_t self) {
+ return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_name(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_name_obj, bleio_adapter_get_name);
+
+
+STATIC mp_obj_t bleio_adapter_set_name(mp_obj_t self, mp_obj_t new_name) {
+ common_hal_bleio_adapter_set_name(self, mp_obj_str_get_str(new_name));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_name_obj, bleio_adapter_set_name);
+
+MP_PROPERTY_GETSET(bleio_adapter_name_obj,
+ (mp_obj_t)&bleio_adapter_get_name_obj,
+ (mp_obj_t)&bleio_adapter_set_name_obj);
+
+//| def start_advertising(self, data: ReadableBuffer, *,
+//| scan_response: Optional[ReadableBuffer] = None, connectable: bool = True,
+//| anonymous: bool = False, timeout: int = 0, interval: float = 0.1,
+//| tx_power: int = 0, directed_to: Optional[Address] = None) -> None:
+//| """Starts advertising until `stop_advertising` is called or if connectable, another device
+//| connects to us.
+//|
+//| .. warning:: If data is longer than 31 bytes, then this will automatically advertise as an
+//| extended advertisement that older BLE 4.x clients won't be able to scan for.
+//|
+//| .. note:: If you set ``anonymous=True``, then a timeout must be specified. If no timeout is
+//| specified, then the maximum allowed timeout will be selected automatically.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer data: advertising data packet bytes
+//| :param ~circuitpython_typing.ReadableBuffer scan_response: scan response data packet bytes. ``None`` if no scan response is needed.
+//| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral.
+//| :param bool anonymous: If `True` then this device's MAC address is randomized before advertising.
+//| :param int timeout: If set, we will only advertise for this many seconds. Zero means no timeout.
+//| :param float interval: advertising interval, in seconds
+//| :param tx_power int: transmitter power while advertising in dBm
+//| :param directed_to Address: peer to advertise directly to"""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_anonymous, ARG_timeout, ARG_interval, ARG_tx_power, ARG_directed_to };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_anonymous, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_tx_power, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_directed_to, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t data_bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ);
+
+ // Pass an empty buffer if scan_response not provided.
+ mp_buffer_info_t scan_response_bufinfo = { 0 };
+ if (args[ARG_scan_response].u_obj != mp_const_none) {
+ mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ);
+ }
+
+ if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
+ args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT);
+ }
+
+ const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj);
+ if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) {
+ mp_raise_ValueError_varg(translate("interval must be in range %s-%s"),
+ ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING);
+ }
+
+ bool connectable = args[ARG_connectable].u_bool;
+ bool anonymous = args[ARG_anonymous].u_bool;
+ uint32_t timeout = args[ARG_timeout].u_int;
+ if (data_bufinfo.len > 31 && connectable && scan_response_bufinfo.len > 0) {
+ mp_raise_bleio_BluetoothError(translate("Cannot have scan responses for extended, connectable advertisements."));
+ }
+
+ const bleio_address_obj_t *address = NULL;
+ if (args[ARG_directed_to].u_obj != mp_const_none) {
+ if (!connectable) {
+ mp_raise_bleio_BluetoothError(translate("Only connectable advertisements can be directed"));
+ }
+ address = mp_arg_validate_type(args[ARG_directed_to].u_obj, &bleio_address_type, MP_QSTR_directed_to);
+ }
+
+ common_hal_bleio_adapter_start_advertising(self, connectable, anonymous, timeout, interval,
+ &data_bufinfo, &scan_response_bufinfo, args[ARG_tx_power].u_int, address);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_advertising_obj, 1, bleio_adapter_start_advertising);
+
+//| def stop_advertising(self) -> None:
+//| """Stop sending advertising packets."""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_stop_advertising(mp_obj_t self_in) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_bleio_adapter_stop_advertising(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_advertising_obj, bleio_adapter_stop_advertising);
+
+//| def start_scan(self, prefixes: ReadableBuffer = b"", *, buffer_size: int = 512, extended: bool = False, timeout: Optional[float] = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) -> Iterable[ScanEntry]:
+//| """Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are
+//| filtered and returned separately.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer prefixes: Sequence of byte string prefixes to filter advertising packets
+//| with. A packet without an advertising structure that matches one of the prefixes is
+//| ignored. Format is one byte for length (n) and n bytes of prefix and can be repeated.
+//| :param int buffer_size: the maximum number of advertising bytes to buffer.
+//| :param bool extended: When True, support extended advertising packets. Increasing buffer_size is recommended when this is set.
+//| :param float timeout: the scan timeout in seconds. If None or zero, will scan until `stop_scan` is called.
+//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows
+//| Must be in the range 0.0025 - 40.959375 seconds.
+//| :param float window: the duration (in seconds) to scan a single BLE channel.
+//| window must be <= interval.
+//| :param int minimum_rssi: the minimum rssi of entries to return.
+//| :param bool active: retrieve scan responses for scannable advertisements.
+//| :returns: an iterable of `_bleio.ScanEntry` objects
+//| :rtype: iterable"""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_prefixes, ARG_buffer_size, ARG_extended, ARG_timeout, ARG_interval, ARG_window, ARG_minimum_rssi, ARG_active };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_prefixes, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 512} },
+ { MP_QSTR_extended, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_minimum_rssi, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -80} },
+ { MP_QSTR_active, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_float_t timeout = 0.0f;
+ if (args[ARG_timeout].u_obj != mp_const_none) {
+ timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ }
+
+ if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
+ args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT);
+ }
+
+ if (args[ARG_window].u_obj == MP_OBJ_NULL) {
+ args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT);
+ }
+
+ const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj);
+ if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
+ mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING);
+ }
+
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
+ if (timeout != 0.0f && timeout < interval) {
+ mp_raise_ValueError(translate("non-zero timeout must be >= interval"));
+ }
+ #pragma GCC diagnostic pop
+
+ const mp_float_t window = mp_obj_get_float(args[ARG_window].u_obj);
+ if (window > interval) {
+ mp_raise_ValueError(translate("window must be <= interval"));
+ }
+
+ mp_buffer_info_t prefix_bufinfo;
+ prefix_bufinfo.len = 0;
+ if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) {
+ mp_get_buffer_raise(args[ARG_prefixes].u_obj, &prefix_bufinfo, MP_BUFFER_READ);
+ if (gc_nbytes(prefix_bufinfo.buf) == 0) {
+ mp_raise_ValueError(translate("Prefix buffer must be on the heap"));
+ }
+ }
+
+ return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, args[ARG_buffer_size].u_int, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter_start_scan);
+
+//| def stop_scan(self) -> None:
+//| """Stop the current scan."""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_stop_scan(mp_obj_t self_in) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_bleio_adapter_stop_scan(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_scan_obj, bleio_adapter_stop_scan);
+
+//| advertising: bool
+//| """True when the adapter is currently advertising. (read-only)"""
+//|
+STATIC mp_obj_t bleio_adapter_get_advertising(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_bleio_adapter_get_advertising(self));
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_advertising_obj, bleio_adapter_get_advertising);
+
+MP_PROPERTY_GETTER(bleio_adapter_advertising_obj,
+ (mp_obj_t)&bleio_adapter_get_advertising_obj);
+
+//| connected: bool
+//| """True when the adapter is connected to another device regardless of who initiated the
+//| connection. (read-only)"""
+//|
+STATIC mp_obj_t bleio_adapter_get_connected(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_bleio_adapter_get_connected(self));
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_connected_obj, bleio_adapter_get_connected);
+
+MP_PROPERTY_GETTER(bleio_adapter_connected_obj,
+ (mp_obj_t)&bleio_adapter_get_connected_obj);
+
+//| connections: Tuple[Connection]
+//| """Tuple of active connections including those initiated through
+//| :py:meth:`_bleio.Adapter.connect`. (read-only)"""
+//|
+STATIC mp_obj_t bleio_adapter_get_connections(mp_obj_t self) {
+ return common_hal_bleio_adapter_get_connections(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_connections_obj, bleio_adapter_get_connections);
+
+MP_PROPERTY_GETTER(bleio_adapter_connections_obj,
+ (mp_obj_t)&bleio_adapter_get_connections_obj);
+
+//| def connect(self, address: Address, *, timeout: float) -> Connection:
+//| """Attempts a connection to the device with the given address.
+//|
+//| :param Address address: The address of the peripheral to connect to
+//| :param float/int timeout: Try to connect for timeout seconds."""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_address, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_address_obj_t *address = mp_arg_validate_type(args[ARG_address].u_obj, &bleio_address_type, MP_QSTR_address);
+ mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+
+ return common_hal_bleio_adapter_connect(self, address, timeout);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_connect_obj, 1, bleio_adapter_connect);
+
+//| def erase_bonding(self) -> None:
+//| """Erase all bonding information stored in flash memory."""
+//| ...
+//|
+STATIC mp_obj_t bleio_adapter_erase_bonding(mp_obj_t self_in) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_bleio_adapter_erase_bonding(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_erase_bonding_obj, bleio_adapter_erase_bonding);
+
+STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&bleio_adapter_enabled_obj) },
+ { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_adapter_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_adapter_name_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_adapter_start_advertising_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_adapter_stop_advertising_obj) },
+ { MP_ROM_QSTR(MP_QSTR_advertising), MP_ROM_PTR(&bleio_adapter_advertising_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_scan), MP_ROM_PTR(&bleio_adapter_start_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_scan), MP_ROM_PTR(&bleio_adapter_stop_scan_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_adapter_connect_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_adapter_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connections), MP_ROM_PTR(&bleio_adapter_connections_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_erase_bonding), MP_ROM_PTR(&bleio_adapter_erase_bonding_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict_table);
+
+const mp_obj_type_t bleio_adapter_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Adapter,
+ .make_new = bleio_adapter_make_new,
+ .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_bleio/Adapter.h b/circuitpython/shared-bindings/_bleio/Adapter.h
new file mode 100644
index 0000000..1dce615
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Adapter.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
+
+#include <stdint.h>
+
+#include "common-hal/_bleio/Adapter.h"
+
+#include "py/objstr.h"
+#include "shared-module/_bleio/Address.h"
+
+extern const mp_obj_type_t bleio_adapter_type;
+
+#if CIRCUITPY_BLEIO_HCI
+void common_hal_bleio_adapter_construct_hci_uart(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, digitalio_digitalinout_obj_t *rts, digitalio_digitalinout_obj_t *cts);
+#endif // CIRCUITPY_BLEIO_HCI
+
+extern bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self);
+extern bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self);
+extern void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled);
+extern mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self);
+extern void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power);
+extern bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self);
+extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self);
+extern bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address);
+
+extern mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self);
+extern void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name);
+
+extern uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
+ bool connectable, bool anonymous, uint32_t timeout, float interval,
+ const uint8_t *advertising_data, uint16_t advertising_data_len,
+ const uint8_t *scan_response_data, uint16_t scan_response_data_len,
+ mp_int_t tx_power, const bleio_address_obj_t *directed_to);
+
+extern void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
+ bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval,
+ mp_buffer_info_t *advertising_data_bufinfo,
+ mp_buffer_info_t *scan_response_data_bufinfo,
+ mp_int_t tx_power, const bleio_address_obj_t *directed_to);
+extern void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self);
+
+extern mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t *prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active);
+extern void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self);
+
+extern bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self);
+extern mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self);
+extern mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout);
+
+extern void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self);
+extern bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
diff --git a/circuitpython/shared-bindings/_bleio/Address.c b/circuitpython/shared-bindings/_bleio/Address.c
new file mode 100644
index 0000000..9673642
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Address.c
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-module/_bleio/Address.h"
+
+//| class Address:
+//| """Encapsulates the address of a BLE device."""
+//|
+
+//| def __init__(self, address: ReadableBuffer, address_type: int) -> None:
+//| """Create a new Address object encapsulating the address value.
+//| The value itself can be one of:
+//|
+//| :param ~circuitpython_typing.ReadableBuffer address: The address value to encapsulate. A buffer object (bytearray, bytes) of 6 bytes.
+//| :param int address_type: one of the integer values: `PUBLIC`, `RANDOM_STATIC`,
+//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`."""
+//| ...
+//|
+STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_address, ARG_address_type };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_address_type, MP_ARG_INT, {.u_int = BLEIO_ADDRESS_TYPE_PUBLIC } },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_address_obj_t *self = m_new_obj(bleio_address_obj_t);
+ self->base.type = &bleio_address_type;
+
+ const mp_obj_t address = args[ARG_address].u_obj;
+ mp_buffer_info_t buf_info;
+ mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ);
+ if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) {
+ mp_raise_ValueError_varg(translate("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES);
+ }
+
+ const mp_int_t address_type = args[ARG_address_type].u_int;
+ if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) {
+ mp_raise_ValueError(translate("Address type out of range"));
+ }
+
+ common_hal_bleio_address_construct(self, buf_info.buf, address_type);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| address_bytes: bytes
+//| """The bytes that make up the device address (read-only).
+//|
+//| Note that the ``bytes`` object returned is in little-endian order:
+//| The least significant byte is ``address_bytes[0]``. So the address will
+//| appear to be reversed if you print the raw ``bytes`` object. If you print
+//| or use `str()` on the :py:class:`~_bleio.Attribute` object itself, the address will be printed
+//| in the expected order. For example:
+//|
+//| .. code-block:: python
+//|
+//| >>> import _bleio
+//| >>> _bleio.adapter.address
+//| <Address c8:1d:f5:ed:a8:35>
+//| >>> _bleio.adapter.address.address_bytes
+//| b'5\\xa8\\xed\\xf5\\x1d\\xc8'"""
+//|
+STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) {
+ bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_bleio_address_get_address_bytes(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_address_bytes_obj, bleio_address_get_address_bytes);
+
+MP_PROPERTY_GETTER(bleio_address_address_bytes_obj,
+ (mp_obj_t)&bleio_address_get_address_bytes_obj);
+
+//| type: int
+//| """The address type (read-only).
+//|
+//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`, `RANDOM_PRIVATE_RESOLVABLE`,
+//| or `RANDOM_PRIVATE_NON_RESOLVABLE`."""
+//|
+STATIC mp_obj_t bleio_address_get_type(mp_obj_t self_in) {
+ bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_address_get_type(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_type_obj, bleio_address_get_type);
+
+MP_PROPERTY_GETTER(bleio_address_type_obj,
+ (mp_obj_t)&bleio_address_get_type_obj);
+
+//| def __eq__(self, other: object) -> bool:
+//| """Two Address objects are equal if their addresses and address types are equal."""
+//| ...
+//|
+STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ switch (op) {
+ // Two Addresses are equal if their address bytes and address_type are equal
+ case MP_BINARY_OP_EQUAL:
+ if (mp_obj_is_type(rhs_in, &bleio_address_type)) {
+ bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in);
+ bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in);
+ return mp_obj_new_bool(
+ mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs),
+ common_hal_bleio_address_get_address_bytes(rhs)) &&
+ common_hal_bleio_address_get_type(lhs) ==
+ common_hal_bleio_address_get_type(rhs));
+
+ } else {
+ return mp_const_false;
+ }
+
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the Address data."""
+//| ...
+//|
+STATIC mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ switch (op) {
+ // Two Addresses are equal if their address bytes and address_type are equal
+ case MP_UNARY_OP_HASH: {
+ mp_obj_t bytes = common_hal_bleio_address_get_address_bytes(MP_OBJ_TO_PTR(self_in));
+ GET_STR_HASH(bytes, h);
+ if (h == 0) {
+ GET_STR_DATA_LEN(bytes, data, len);
+ h = qstr_compute_hash(data, len);
+ }
+ h ^= common_hal_bleio_address_get_type(MP_OBJ_TO_PTR(self_in));
+ return MP_OBJ_NEW_SMALL_INT(h);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t buf_info;
+ mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self);
+ mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ);
+
+ const uint8_t *buf = (uint8_t *)buf_info.buf;
+ mp_printf(print, "<Address %02x:%02x:%02x:%02x:%02x:%02x>",
+ buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
+}
+
+//| PUBLIC: int
+//| """A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits)."""
+//|
+//| RANDOM_STATIC: int
+//| """A randomly generated address that does not change often. It may never change or may change after
+//| a power cycle."""
+//|
+//| RANDOM_PRIVATE_RESOLVABLE: int
+//| """An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK)."""
+//|
+//| RANDOM_PRIVATE_NON_RESOLVABLE: int
+//| """A randomly generated address that changes on every connection."""
+//|
+STATIC const mp_rom_map_elem_t bleio_address_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) },
+ { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) },
+ // These match the BLE_GAP_ADDR_TYPES values used by the nRF library.
+ { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_INT(0) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_INT(1) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_INT(2) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_INT(3) },
+
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_address_locals_dict, bleio_address_locals_dict_table);
+
+const mp_obj_type_t bleio_address_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Address,
+ .make_new = bleio_address_make_new,
+ .print = bleio_address_print,
+ .locals_dict = (mp_obj_dict_t *)&bleio_address_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = bleio_address_unary_op,
+ .binary_op = bleio_address_binary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/_bleio/Address.h b/circuitpython/shared-bindings/_bleio/Address.h
new file mode 100644
index 0000000..98b6f80
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Address.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H
+
+#include "py/objtype.h"
+#include "shared-module/_bleio/Address.h"
+
+#define BLEIO_ADDRESS_TYPE_PUBLIC (0)
+#define BLEIO_ADDRESS_TYPE_RANDOM_STATIC (1)
+#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE (2)
+#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE (3)
+
+#define BLEIO_ADDRESS_TYPE_MIN BLEIO_ADDRESS_TYPE_PUBLIC
+#define BLEIO_ADDRESS_TYPE_MAX BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE
+
+extern const mp_obj_type_t bleio_address_type;
+
+extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type);
+extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self);
+extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H
diff --git a/circuitpython/shared-bindings/_bleio/Attribute.c b/circuitpython/shared-bindings/_bleio/Attribute.c
new file mode 100644
index 0000000..d639f2a
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Attribute.c
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| class Attribute:
+//| """Definitions associated with all BLE attributes: characteristics, descriptors, etc.
+//|
+//| :py:class:`~_bleio.Attribute` is, notionally, a superclass of
+//| :py:class:`~Characteristic` and :py:class:`~Descriptor`,
+//| but is not defined as a Python superclass of those classes."""
+//|
+//| def __init__(self) -> None:
+//| """You cannot create an instance of :py:class:`~_bleio.Attribute`."""
+//| ...
+//|
+
+STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = {
+
+//| NO_ACCESS: int
+//| """security mode: access not allowed"""
+//|
+//| OPEN: int
+//| """security_mode: no security (link is not encrypted)"""
+//|
+//| ENCRYPT_NO_MITM: int
+//| """security_mode: unauthenticated encryption, without man-in-the-middle protection"""
+//|
+//| ENCRYPT_WITH_MITM: int
+//| """security_mode: authenticated encryption, with man-in-the-middle protection"""
+//|
+//| LESC_ENCRYPT_WITH_MITM: int
+//| """security_mode: LESC encryption, with man-in-the-middle protection"""
+//|
+//| SIGNED_NO_MITM: int
+//| """security_mode: unauthenticated data signing, without man-in-the-middle protection"""
+//|
+//| SIGNED_WITH_MITM: int
+//| """security_mode: authenticated data signing, without man-in-the-middle protection"""
+//|
+ { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SECURITY_MODE_NO_ACCESS) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SECURITY_MODE_OPEN) },
+ { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SECURITY_MODE_ENC_NO_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_ENC_WITH_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_LESC_ENC_WITH_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_NO_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_WITH_MITM) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table);
+
+const mp_obj_type_t bleio_attribute_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Attribute,
+ .locals_dict = (mp_obj_dict_t *)&bleio_attribute_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_bleio/Attribute.h b/circuitpython/shared-bindings/_bleio/Attribute.h
new file mode 100644
index 0000000..a0ce045
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Attribute.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H
+
+#include "py/obj.h"
+
+#include "common-hal/_bleio/Attribute.h"
+#include "shared-module/_bleio/Attribute.h"
+
+extern const mp_obj_type_t bleio_attribute_type;
+
+extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H
diff --git a/circuitpython/shared-bindings/_bleio/Characteristic.c b/circuitpython/shared-bindings/_bleio/Characteristic.c
new file mode 100644
index 0000000..4ff37f0
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Characteristic.c
@@ -0,0 +1,334 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Attribute.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/Service.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| class Characteristic:
+//| """Stores information about a BLE service characteristic and allows reading
+//| and writing of the characteristic's value."""
+//|
+//| def __init__(self) -> None:
+//| """There is no regular constructor for a Characteristic. A new local Characteristic can be created
+//| and attached to a Service by calling `add_to_service()`.
+//| Remote Characteristic objects are created by `Connection.discover_remote_services()`
+//| as part of remote Services."""
+//| ...
+//|
+
+//| def add_to_service(self, service: Service, uuid: UUID, *, properties: int = 0,
+//| read_perm: int = Attribute.OPEN, write_perm: int = Attribute.OPEN,
+//| max_length: int = 20, fixed_length: bool = False,
+//| initial_value: Optional[ReadableBuffer] = None,
+//| user_description: Optional[str] = None) -> Characteristic:
+//| """Create a new Characteristic object, and add it to this Service.
+//|
+//| :param Service service: The service that will provide this characteristic
+//| :param UUID uuid: The uuid of the characteristic
+//| :param int properties: The properties of the characteristic,
+//| specified as a bitmask of these values bitwise-or'd together:
+//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`.
+//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which
+//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which
+//| security mode is required. Values allowed are the same as ``read_perm``.
+//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is
+//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+//| number of data bytes that fit in a single BLE 4.x ATT packet.
+//| :param bool fixed_length: True if the characteristic value is of fixed length.
+//| :param ~circuitpython_typing.ReadableBuffer initial_value: The initial value for this characteristic. If not given, will be
+//| filled with zeros.
+//| :param str user_description: User friendly description of the characteristic
+//|
+//| :return: the new Characteristic."""
+//| ...
+//|
+STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // class is arg[0], which we can ignore.
+
+ enum { ARG_service, ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm,
+ ARG_max_length, ARG_fixed_length, ARG_initial_value, ARG_user_description };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_service, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_properties, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_read_perm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_write_perm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_max_length, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 20} },
+ { MP_QSTR_fixed_length, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_initial_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_user_description, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_service_obj_t *service = mp_arg_validate_type(args[ARG_service].u_obj, &bleio_service_type, MP_QSTR_service);
+
+ bleio_uuid_obj_t *uuid = mp_arg_validate_type(args[ARG_uuid].u_obj, &bleio_uuid_type, MP_QSTR_uuid);
+
+ const bleio_characteristic_properties_t properties = args[ARG_properties].u_int;
+ if (properties & ~CHAR_PROP_ALL) {
+ mp_raise_ValueError(translate("Invalid properties"));
+ }
+
+ const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(read_perm);
+
+ const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(write_perm);
+
+ const mp_int_t max_length_int = args[ARG_max_length].u_int;
+ if (max_length_int < 0) {
+ mp_raise_ValueError(translate("max_length must be >= 0"));
+ }
+ const size_t max_length = (size_t)max_length_int;
+ const bool fixed_length = args[ARG_fixed_length].u_bool;
+ mp_obj_t initial_value = args[ARG_initial_value].u_obj;
+
+ mp_buffer_info_t initial_value_bufinfo;
+ if (initial_value == mp_const_none) {
+ if (fixed_length && max_length > 0) {
+ initial_value = mp_obj_new_bytes_of_zeros(max_length);
+ } else {
+ initial_value = mp_const_empty_bytes;
+ }
+ }
+
+ mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ);
+ if (initial_value_bufinfo.len > max_length ||
+ (fixed_length && initial_value_bufinfo.len != max_length)) {
+ mp_raise_ValueError(translate("initial_value length is wrong"));
+ }
+
+ const char *user_description = NULL;
+ if (args[ARG_user_description].u_obj != mp_const_none) {
+ user_description = mp_obj_str_get_str(args[ARG_user_description].u_obj);
+ }
+
+ bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
+ characteristic->base.type = &bleio_characteristic_type;
+
+ // Range checking on max_length arg is done by the common_hal layer, because
+ // it may vary depending on underlying BLE implementation.
+ common_hal_bleio_characteristic_construct(
+ characteristic, service, 0, uuid,
+ properties, read_perm, write_perm,
+ max_length, fixed_length, &initial_value_bufinfo,
+ user_description);
+
+ return MP_OBJ_FROM_PTR(characteristic);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 1, bleio_characteristic_add_to_service);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_characteristic_add_to_service_obj, MP_ROM_PTR(&bleio_characteristic_add_to_service_fun_obj));
+
+
+
+//| properties: int
+//| """An int bitmask representing which properties are set, specified as bitwise or'ing of
+//| of these possible values.
+//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`."""
+//|
+STATIC mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties);
+
+MP_PROPERTY_GETTER(bleio_characteristic_properties_obj,
+ (mp_obj_t)&bleio_characteristic_get_properties_obj);
+
+//| uuid: Optional[UUID]
+//| """The UUID of this characteristic. (read-only)
+//|
+//| Will be ``None`` if the 128-bit UUID for this characteristic is not known."""
+//|
+STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ bleio_uuid_obj_t *uuid = common_hal_bleio_characteristic_get_uuid(self);
+ return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_uuid_obj, bleio_characteristic_get_uuid);
+
+MP_PROPERTY_GETTER(bleio_characteristic_uuid_obj,
+ (mp_obj_t)&bleio_characteristic_get_uuid_obj);
+
+//| value: bytearray
+//| """The value of this characteristic."""
+//|
+STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ uint8_t temp[512];
+ size_t actual_len = common_hal_bleio_characteristic_get_value(self, temp, sizeof(temp));
+ return mp_obj_new_bytearray(actual_len, temp);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value);
+
+STATIC mp_obj_t bleio_characteristic_set_value(mp_obj_t self_in, mp_obj_t value_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ);
+
+ common_hal_bleio_characteristic_set_value(self, &bufinfo);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_value_obj, bleio_characteristic_set_value);
+
+MP_PROPERTY_GETSET(bleio_characteristic_value_obj,
+ (mp_obj_t)&bleio_characteristic_get_value_obj,
+ (mp_obj_t)&bleio_characteristic_set_value_obj);
+
+//| max_length: int
+//| """The max length of this characteristic."""
+//|
+STATIC mp_obj_t bleio_characteristic_get_max_length(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_max_length(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_max_length_obj, bleio_characteristic_get_max_length);
+
+MP_PROPERTY_GETTER(bleio_characteristic_max_length_obj,
+ (mp_obj_t)&bleio_characteristic_get_max_length_obj);
+
+//| descriptors: Descriptor
+//| """A tuple of :py:class:`Descriptor` objects related to this characteristic. (read-only)"""
+//|
+STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ // Return list as a tuple so user won't be able to change it.
+ return MP_OBJ_FROM_PTR(common_hal_bleio_characteristic_get_descriptors(self));
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors);
+
+MP_PROPERTY_GETTER(bleio_characteristic_descriptors_obj,
+ (mp_obj_t)&bleio_characteristic_get_descriptors_obj);
+
+//| service: Service
+//| """The Service this Characteristic is a part of."""
+//|
+STATIC mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_bleio_characteristic_get_service(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_service_obj, bleio_characteristic_get_service);
+
+MP_PROPERTY_GETTER(bleio_characteristic_service_obj,
+ (mp_obj_t)&bleio_characteristic_get_service_obj);
+
+//| def set_cccd(self, *, notify: bool = False, indicate: bool = False) -> None:
+//| """Set the remote characteristic's CCCD to enable or disable notification and indication.
+//|
+//| :param bool notify: True if Characteristic should receive notifications of remote writes
+//| :param float indicate: True if Characteristic should receive indications of remote writes"""
+//| ...
+//|
+STATIC mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_notify, ARG_indicate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_notify, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_indicate, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ common_hal_bleio_characteristic_set_cccd(self, args[ARG_notify].u_bool, args[ARG_indicate].u_bool);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd);
+
+STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) },
+ { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_properties_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) },
+
+ // Bitmask constants to represent properties
+//| BROADCAST: int
+//| """property: allowed in advertising packets"""
+//|
+//| INDICATE: int
+//| """property: server will indicate to the client when the value is set and wait for a response"""
+//|
+//| NOTIFY: int
+//| """property: server will notify the client when the value is set"""
+//|
+//| READ: int
+//| """property: clients may read this characteristic"""
+//|
+//| WRITE: int
+//| """property: clients may write this characteristic; a response will be sent back"""
+//|
+//| WRITE_NO_RESPONSE: int
+//| """property: clients may write this characteristic; no response will be sent back"""
+//|
+ { MP_ROM_QSTR(MP_QSTR_BROADCAST), MP_ROM_INT(CHAR_PROP_BROADCAST) },
+ { MP_ROM_QSTR(MP_QSTR_INDICATE), MP_ROM_INT(CHAR_PROP_INDICATE) },
+ { MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(CHAR_PROP_NOTIFY) },
+ { MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(CHAR_PROP_READ) },
+ { MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(CHAR_PROP_WRITE) },
+ { MP_ROM_QSTR(MP_QSTR_WRITE_NO_RESPONSE), MP_ROM_INT(CHAR_PROP_WRITE_NO_RESPONSE) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table);
+
+STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->uuid) {
+ mp_printf(print, "Characteristic(");
+ bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind);
+ mp_printf(print, ")");
+ } else {
+ mp_printf(print, "<Characteristic with Unregistered UUID>");
+ }
+}
+
+const mp_obj_type_t bleio_characteristic_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Characteristic,
+ .print = bleio_characteristic_print,
+ .locals_dict = (mp_obj_dict_t *)&bleio_characteristic_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_bleio/Characteristic.h b/circuitpython/shared-bindings/_bleio/Characteristic.h
new file mode 100644
index 0000000..349dd5f
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Characteristic.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
+
+#include "py/objtuple.h"
+#include "shared-bindings/_bleio/Attribute.h"
+#include "shared-bindings/_bleio/Descriptor.h"
+#include "shared-module/_bleio/Characteristic.h"
+#include "common-hal/_bleio/Characteristic.h"
+#include "common-hal/_bleio/Service.h"
+
+extern const mp_obj_type_t bleio_characteristic_type;
+
+extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self);
+extern mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self);
+extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self);
+extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self);
+extern size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristic_obj_t *self);
+extern size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len);
+extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor);
+extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo, const char *user_description);
+extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
+extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
diff --git a/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.c b/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.c
new file mode 100644
index 0000000..78ff07f
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.c
@@ -0,0 +1,242 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mperrno.h"
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/CharacteristicBuffer.h"
+#include "shared-bindings/_bleio/UUID.h"
+#include "shared-bindings/util.h"
+
+STATIC void raise_error_if_not_connected(bleio_characteristic_buffer_obj_t *self) {
+ if (!common_hal_bleio_characteristic_buffer_connected(self)) {
+ mp_raise_ConnectionError(translate("Not connected"));
+ }
+}
+
+//| class CharacteristicBuffer:
+//| """Accumulates a Characteristic's incoming values in a FIFO buffer."""
+//|
+//| def __init__(self, characteristic: Characteristic, *, timeout: int = 1, buffer_size: int = 64) -> None:
+//|
+//| """Monitor the given Characteristic. Each time a new value is written to the Characteristic
+//| add the newly-written bytes to a FIFO buffer.
+//|
+//| :param Characteristic characteristic: The Characteristic to monitor.
+//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic
+//| in a remote Service that a Central has connected to.
+//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters.
+//| :param int buffer_size: Size of ring buffer that stores incoming data coming from client.
+//| Must be >= 1."""
+//| ...
+//|
+STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_characteristic, ARG_timeout, ARG_buffer_size, };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} },
+ { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_characteristic_obj_t *characteristic = mp_arg_validate_type(args[ARG_characteristic].u_obj, &bleio_characteristic_type, MP_QSTR_characteristic);
+
+ mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ if (timeout < 0.0f) {
+ mp_raise_ValueError(translate("timeout must be >= 0.0"));
+ }
+
+ const int buffer_size = args[ARG_buffer_size].u_int;
+ if (buffer_size < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size);
+ }
+
+ bleio_characteristic_buffer_obj_t *self = m_new_obj(bleio_characteristic_buffer_obj_t);
+ self->base.type = &bleio_characteristic_buffer_type;
+
+ common_hal_bleio_characteristic_buffer_construct(self, characteristic, timeout, buffer_size);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void check_for_deinit(bleio_characteristic_buffer_obj_t *self) {
+ if (common_hal_bleio_characteristic_buffer_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+// These are standard stream methods. Code is in py/stream.c.
+//
+//| def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+//| """Read characters. If ``nbytes`` is specified then read at most that many
+//| bytes. Otherwise, read everything that arrives until the connection
+//| times out. Providing the number of bytes expected is highly recommended
+//| because it will be faster.
+//|
+//| :return: Data read
+//| :rtype: bytes or None"""
+//| ...
+//|
+//| def readinto(self, buf: WriteableBuffer) -> Optional[int]:
+//| """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: int or None (on a non-blocking error)"""
+//| ...
+//|
+//| def readline(self) -> bytes:
+//| """Read a line, ending in a newline character.
+//|
+//| :return: the line read
+//| :rtype: int or None"""
+//| ...
+//|
+
+// These three methods are used by the shared stream methods.
+STATIC mp_uint_t bleio_characteristic_buffer_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ raise_error_if_not_connected(self);
+ byte *buf = buf_in;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ return common_hal_bleio_characteristic_buffer_read(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ mp_raise_NotImplementedError(translate("CharacteristicBuffer writing not provided"));
+ return 0;
+}
+
+STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ raise_error_if_not_connected(self);
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_bleio_characteristic_buffer_rx_characters_available(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+// No writing provided.
+// if ((flags & MP_IOCTL_POLL_WR) && common_hal_busio_uart_ready_to_tx(self)) {
+// ret |= MP_IOCTL_POLL_WR;
+// }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+//| in_waiting: int
+//| """The number of bytes in the input buffer, available to be read"""
+//|
+STATIC mp_obj_t bleio_characteristic_buffer_obj_get_in_waiting(mp_obj_t self_in) {
+ bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_buffer_rx_characters_available(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_get_in_waiting_obj, bleio_characteristic_buffer_obj_get_in_waiting);
+
+MP_PROPERTY_GETTER(bleio_characteristic_buffer_in_waiting_obj,
+ (mp_obj_t)&bleio_characteristic_buffer_get_in_waiting_obj);
+
+//| def reset_input_buffer(self) -> None:
+//| """Discard any unread characters in the input buffer."""
+//| ...
+//|
+STATIC mp_obj_t bleio_characteristic_buffer_obj_reset_input_buffer(mp_obj_t self_in) {
+ bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_bleio_characteristic_buffer_clear_rx_buffer(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_reset_input_buffer_obj, bleio_characteristic_buffer_obj_reset_input_buffer);
+
+//| def deinit(self) -> None:
+//| """Disable permanently."""
+//| ...
+//|
+STATIC mp_obj_t bleio_characteristic_buffer_deinit(mp_obj_t self_in) {
+ bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_bleio_characteristic_buffer_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_deinit_obj, bleio_characteristic_buffer_deinit);
+
+STATIC const mp_rom_map_elem_t bleio_characteristic_buffer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_characteristic_buffer_deinit_obj) },
+
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ // CharacteristicBuffer is currently read-only.
+ // { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&bleio_characteristic_buffer_reset_input_buffer_obj) },
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&bleio_characteristic_buffer_in_waiting_obj) },
+
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_buffer_locals_dict, bleio_characteristic_buffer_locals_dict_table);
+
+STATIC const mp_stream_p_t characteristic_buffer_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = bleio_characteristic_buffer_read,
+ .write = bleio_characteristic_buffer_write,
+ .ioctl = bleio_characteristic_buffer_ioctl,
+ .is_text = false,
+ // Disallow readinto() size parameter.
+ .pyserial_readinto_compatibility = true,
+};
+
+
+const mp_obj_type_t bleio_characteristic_buffer_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_CharacteristicBuffer,
+ .make_new = bleio_characteristic_buffer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&bleio_characteristic_buffer_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &characteristic_buffer_stream_p,
+ ),
+};
diff --git a/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.h b/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.h
new file mode 100644
index 0000000..de85f01
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/CharacteristicBuffer.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H
+
+#include "common-hal/_bleio/CharacteristicBuffer.h"
+
+extern const mp_obj_type_t bleio_characteristic_buffer_type;
+
+void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self,
+ bleio_characteristic_obj_t *characteristic,
+ mp_float_t timeout,
+ uint8_t *buffer, size_t buffer_size,
+ void *static_handler_entry);
+void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self,
+ bleio_characteristic_obj_t *characteristic,
+ mp_float_t timeout,
+ size_t buffer_size);
+uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode);
+uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self);
+void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self);
+bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self);
+void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self);
+bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H
diff --git a/circuitpython/shared-bindings/_bleio/Connection.c b/circuitpython/shared-bindings/_bleio/Connection.c
new file mode 100644
index 0000000..7a85ccd
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Connection.c
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2016 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/_bleio/Connection.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "py/objarray.h"
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/Adapter.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/Service.h"
+
+//| class Connection:
+//| """A BLE connection to another device. Used to discover and interact with services on the other
+//| device.
+//|
+//| Usage::
+//|
+//| import _bleio
+//|
+//| my_entry = None
+//| for entry in _bleio.adapter.scan(2.5):
+//| if entry.name is not None and entry.name == 'InterestingPeripheral':
+//| my_entry = entry
+//| break
+//|
+//| if not my_entry:
+//| raise Exception("'InterestingPeripheral' not found")
+//|
+//| connection = _bleio.adapter.connect(my_entry.address, timeout=10)"""
+//|
+
+void bleio_connection_ensure_connected(bleio_connection_obj_t *self) {
+ if (!common_hal_bleio_connection_get_connected(self)) {
+ mp_raise_ConnectionError(translate("Connection has been disconnected and can no longer be used. Create a new connection."));
+ }
+}
+
+//| def __init__(self) -> None:
+//| """Connections cannot be made directly. Instead, to initiate a connection use `Adapter.connect`.
+//| Connections may also be made when another device initiates a connection. To use a Connection
+//| created by a peer, read the `Adapter.connections` property."""
+//| ...
+//|
+//| def disconnect(self) -> None:
+//| """Disconnects from the remote peripheral. Does nothing if already disconnected."""
+//| ...
+//|
+STATIC mp_obj_t bleio_connection_disconnect(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ // common_hal_bleio_connection_disconnect() does nothing if already disconnected.
+ common_hal_bleio_connection_disconnect(self->connection);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_disconnect_obj, bleio_connection_disconnect);
+
+
+//| def pair(self, *, bond: bool = True) -> None:
+//| """Pair to the peer to improve security."""
+//| ...
+//|
+STATIC mp_obj_t bleio_connection_pair(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_bond };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bond, MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_connection_ensure_connected(self);
+
+ common_hal_bleio_connection_pair(self->connection, args[ARG_bond].u_bool);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_connection_pair_obj, 1, bleio_connection_pair);
+
+//| def discover_remote_services(self, service_uuids_whitelist: Optional[Iterable[UUID]] = None) -> Tuple[Service, ...]:
+//| """Do BLE discovery for all services or for the given service UUIDS,
+//| to find their handles and characteristics, and return the discovered services.
+//| `Connection.connected` must be True.
+//|
+//| :param iterable service_uuids_whitelist:
+//|
+//| an iterable of :py:class:`UUID` objects for the services provided by the peripheral
+//| that you want to use.
+//|
+//| The peripheral may provide more services, but services not listed are ignored
+//| and will not be returned.
+//|
+//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be
+//| slow.
+//|
+//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you
+//| you must have already created a :py:class:`UUID` object for that UUID in order for the
+//| service or characteristic to be discovered. Creating the UUID causes the UUID to be
+//| registered for use. (This restriction may be lifted in the future.)
+//|
+//| :return: A tuple of `_bleio.Service` objects provided by the remote peripheral."""
+//| ...
+//|
+STATIC mp_obj_t bleio_connection_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_service_uuids_whitelist };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_connection_ensure_connected(self);
+
+ return MP_OBJ_FROM_PTR(common_hal_bleio_connection_discover_remote_services(
+ self,
+ args[ARG_service_uuids_whitelist].u_obj));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_connection_discover_remote_services_obj, 1, bleio_connection_discover_remote_services);
+
+//| connected: bool
+//| """True if connected to the remote peer."""
+//|
+STATIC mp_obj_t bleio_connection_get_connected(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_connection_get_connected(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_connected_obj, bleio_connection_get_connected);
+
+MP_PROPERTY_GETTER(bleio_connection_connected_obj,
+ (mp_obj_t)&bleio_connection_get_connected_obj);
+
+
+//| paired: bool
+//| """True if paired to the remote peer."""
+//|
+STATIC mp_obj_t bleio_connection_get_paired(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_connection_get_paired(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_paired_obj, bleio_connection_get_paired);
+
+MP_PROPERTY_GETTER(bleio_connection_paired_obj,
+ (mp_obj_t)&bleio_connection_get_paired_obj);
+
+
+//| connection_interval: float
+//| """Time between transmissions in milliseconds. Will be multiple of 1.25ms. Lower numbers
+//| increase speed and decrease latency but increase power consumption.
+//|
+//| When setting connection_interval, the peer may reject the new interval and
+//| `connection_interval` will then remain the same.
+//|
+//| Apple has additional guidelines that dictate should be a multiple of 15ms except if HID is
+//| available. When HID is available Apple devices may accept 11.25ms intervals."""
+//|
+STATIC mp_obj_t bleio_connection_get_connection_interval(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ bleio_connection_ensure_connected(self);
+ return mp_obj_new_float(common_hal_bleio_connection_get_connection_interval(self->connection));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_connection_interval_obj, bleio_connection_get_connection_interval);
+
+//| max_packet_length: int
+//| """The maximum number of data bytes that can be sent in a single transmission,
+//| not including overhead bytes.
+//|
+//| This is the maximum number of bytes that can be sent in a notification,
+//| which must be sent in a single packet.
+//| But for a regular characteristic read or write, may be sent in multiple packets,
+//| so this limit does not apply."""
+//|
+STATIC mp_obj_t bleio_connection_get_max_packet_length(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ bleio_connection_ensure_connected(self);
+ return mp_obj_new_int(common_hal_bleio_connection_get_max_packet_length(self->connection));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_max_packet_length_obj, bleio_connection_get_max_packet_length);
+
+
+STATIC mp_obj_t bleio_connection_set_connection_interval(mp_obj_t self_in, mp_obj_t interval_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_float_t interval = mp_obj_get_float(interval_in);
+
+ bleio_connection_ensure_connected(self);
+ common_hal_bleio_connection_set_connection_interval(self->connection, interval);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_connection_set_connection_interval_obj, bleio_connection_set_connection_interval);
+
+MP_PROPERTY_GETSET(bleio_connection_connection_interval_obj,
+ (mp_obj_t)&bleio_connection_get_connection_interval_obj,
+ (mp_obj_t)&bleio_connection_set_connection_interval_obj);
+
+MP_PROPERTY_GETTER(bleio_connection_max_packet_length_obj,
+ (mp_obj_t)&bleio_connection_get_max_packet_length_obj);
+
+STATIC const mp_rom_map_elem_t bleio_connection_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_connection_pair_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_connection_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_connection_discover_remote_services_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_connection_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paired), MP_ROM_PTR(&bleio_connection_paired_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connection_interval), MP_ROM_PTR(&bleio_connection_connection_interval_obj) },
+ { MP_ROM_QSTR(MP_QSTR_max_packet_length), MP_ROM_PTR(&bleio_connection_max_packet_length_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_connection_locals_dict, bleio_connection_locals_dict_table);
+
+const mp_obj_type_t bleio_connection_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Connection,
+ .locals_dict = (mp_obj_dict_t *)&bleio_connection_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_generic_unary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/_bleio/Connection.h b/circuitpython/shared-bindings/_bleio/Connection.h
new file mode 100644
index 0000000..a5313a9
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Connection.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
+
+#include "py/objtuple.h"
+#include "common-hal/_bleio/Connection.h"
+#include "common-hal/_bleio/Service.h"
+
+extern const mp_obj_type_t bleio_connection_type;
+
+void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond);
+void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self);
+bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self);
+mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self);
+bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self);
+mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist);
+
+mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self);
+void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval);
+
+void bleio_connection_ensure_connected(bleio_connection_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
diff --git a/circuitpython/shared-bindings/_bleio/Descriptor.c b/circuitpython/shared-bindings/_bleio/Descriptor.c
new file mode 100644
index 0000000..f2ef6b4
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Descriptor.c
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Attribute.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/Descriptor.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| class Descriptor:
+//| """Stores information about a BLE descriptor.
+//|
+//| Descriptors are attached to BLE characteristics and provide contextual
+//| information about the characteristic."""
+//|
+//| def __init__(self) -> None:
+//| """There is no regular constructor for a Descriptor. A new local Descriptor can be created
+//| and attached to a Characteristic by calling `add_to_characteristic()`.
+//| Remote Descriptor objects are created by `Connection.discover_remote_services()`
+//| as part of remote Characteristics in the remote Services that are discovered."""
+//|
+//| @classmethod
+//| def add_to_characteristic(cls, characteristic: Characteristic, uuid: UUID, *, read_perm: int = Attribute.OPEN, write_perm: int = Attribute.OPEN, max_length: int = 20, fixed_length: bool = False, initial_value: ReadableBuffer = b'') -> Descriptor:
+//| """Create a new Descriptor object, and add it to this Service.
+//|
+//| :param Characteristic characteristic: The characteristic that will hold this descriptor
+//| :param UUID uuid: The uuid of the descriptor
+//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which
+//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which
+//| security mode is required. Values allowed are the same as ``read_perm``.
+//| :param int max_length: Maximum length in bytes of the descriptor value. The maximum allowed is
+//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+//| number of data bytes that fit in a single BLE 4.x ATT packet.
+//| :param bool fixed_length: True if the descriptor value is of fixed length.
+//| :param ~circuitpython_typing.ReadableBuffer initial_value: The initial value for this descriptor.
+//|
+//| :return: the new Descriptor."""
+//| ...
+//|
+STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ // class is arg[0], which we can ignore.
+
+ enum { ARG_characteristic, ARG_uuid, ARG_read_perm, ARG_write_perm,
+ ARG_max_length, ARG_fixed_length, ARG_initial_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_read_perm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_write_perm, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_max_length, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 20} },
+ { MP_QSTR_fixed_length, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_initial_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_characteristic_obj_t *characteristic = mp_arg_validate_type(args[ARG_characteristic].u_obj, &bleio_characteristic_type, MP_QSTR_characteristic);
+
+ bleio_uuid_obj_t *uuid = mp_arg_validate_type(args[ARG_uuid].u_obj, &bleio_uuid_type, MP_QSTR_uuid);
+
+ const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(read_perm);
+
+ const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(write_perm);
+
+ const mp_int_t max_length_int = args[ARG_max_length].u_int;
+ if (max_length_int < 0) {
+ mp_raise_ValueError(translate("max_length must be >= 0"));
+ }
+ const size_t max_length = (size_t)max_length_int;
+ const bool fixed_length = args[ARG_fixed_length].u_bool;
+ mp_obj_t initial_value = args[ARG_initial_value].u_obj;
+
+ mp_buffer_info_t initial_value_bufinfo;
+ if (initial_value == mp_const_none) {
+ if (fixed_length && max_length > 0) {
+ initial_value = mp_obj_new_bytes_of_zeros(max_length);
+ } else {
+ initial_value = mp_const_empty_bytes;
+ }
+ }
+ mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ);
+ if (initial_value_bufinfo.len > max_length ||
+ (fixed_length && initial_value_bufinfo.len != max_length)) {
+ mp_raise_ValueError(translate("initial_value length is wrong"));
+ }
+
+ bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t);
+ descriptor->base.type = &bleio_descriptor_type;
+
+ // Range checking on max_length arg is done by the common_hal layer, because
+ // it may vary depending on underlying BLE implementation.
+ common_hal_bleio_descriptor_construct(
+ descriptor, characteristic, uuid,
+ read_perm, write_perm,
+ max_length, fixed_length, &initial_value_bufinfo);
+
+ common_hal_bleio_characteristic_add_descriptor(characteristic, descriptor);
+
+ return MP_OBJ_FROM_PTR(descriptor);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_descriptor_add_to_characteristic_fun_obj, 1, bleio_descriptor_add_to_characteristic);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_descriptor_add_to_characteristic_obj, MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_fun_obj));
+
+//| uuid: UUID
+//| """The descriptor uuid. (read-only)"""
+//|
+STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ bleio_uuid_obj_t *uuid = common_hal_bleio_descriptor_get_uuid(self);
+ return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_uuid_obj, bleio_descriptor_get_uuid);
+
+MP_PROPERTY_GETTER(bleio_descriptor_uuid_obj,
+ (mp_obj_t)&bleio_descriptor_get_uuid_obj);
+
+//| characteristic: Characteristic
+//| """The Characteristic this Descriptor is a part of."""
+//|
+STATIC mp_obj_t bleio_descriptor_get_characteristic(mp_obj_t self_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_bleio_descriptor_get_characteristic(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_characteristic_obj, bleio_descriptor_get_characteristic);
+
+MP_PROPERTY_GETTER(bleio_descriptor_characteristic_obj,
+ (mp_obj_t)&bleio_descriptor_get_characteristic_obj);
+
+//| value: bytearray
+//| """The value of this descriptor."""
+//|
+STATIC mp_obj_t bleio_descriptor_get_value(mp_obj_t self_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ uint8_t temp[512];
+ size_t actual_len = common_hal_bleio_descriptor_get_value(self, temp, sizeof(temp));
+ return mp_obj_new_bytearray(actual_len, temp);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_value_obj, bleio_descriptor_get_value);
+
+STATIC mp_obj_t bleio_descriptor_set_value(mp_obj_t self_in, mp_obj_t value_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ);
+
+ common_hal_bleio_descriptor_set_value(self, &bufinfo);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_descriptor_set_value_obj, bleio_descriptor_set_value);
+
+MP_PROPERTY_GETSET(bleio_descriptor_value_obj,
+ (mp_obj_t)&bleio_descriptor_get_value_obj,
+ (mp_obj_t)&bleio_descriptor_set_value_obj);
+
+STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_add_to_characteristic), MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_characteristic), MP_ROM_PTR(&bleio_descriptor_characteristic_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_descriptor_value_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_descriptor_locals_dict, bleio_descriptor_locals_dict_table);
+
+STATIC void bleio_descriptor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->uuid) {
+ mp_printf(print, "Descriptor(");
+ bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind);
+ mp_printf(print, ")");
+ } else {
+ mp_printf(print, "<Descriptor with Unregistered UUID>");
+ }
+}
+
+const mp_obj_type_t bleio_descriptor_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Descriptor,
+ .print = bleio_descriptor_print,
+ .locals_dict = (mp_obj_dict_t *)&bleio_descriptor_locals_dict
+};
diff --git a/circuitpython/shared-bindings/_bleio/Descriptor.h b/circuitpython/shared-bindings/_bleio/Descriptor.h
new file mode 100644
index 0000000..bda381e
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Descriptor.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
+
+#include "shared-module/_bleio/Attribute.h"
+#include "common-hal/_bleio/Characteristic.h"
+#include "common-hal/_bleio/Descriptor.h"
+#include "common-hal/_bleio/UUID.h"
+
+extern const mp_obj_type_t bleio_descriptor_type;
+
+extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo);
+extern bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self);
+extern bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self);
+extern size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len);
+extern void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
diff --git a/circuitpython/shared-bindings/_bleio/PacketBuffer.c b/circuitpython/shared-bindings/_bleio/PacketBuffer.c
new file mode 100644
index 0000000..9e64661
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/PacketBuffer.c
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mperrno.h"
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/PacketBuffer.h"
+#include "shared-bindings/_bleio/UUID.h"
+#include "shared-bindings/util.h"
+
+//| class PacketBuffer:
+//| """Accumulates a Characteristic's incoming packets in a FIFO buffer and facilitates packet aware
+//| outgoing writes. A packet's size is either the characteristic length or the maximum transmission
+//| unit (MTU) minus overhead, whichever is smaller. The MTU can change so check `incoming_packet_length`
+//| and `outgoing_packet_length` before creating a buffer to store data.
+//|
+//| When we're the server, we ignore all connections besides the first to subscribe to
+//| notifications."""
+//|
+//| def __init__(self, characteristic: Characteristic, *, buffer_size: int, max_packet_size: Optional[int] = None) -> None:
+//| """Monitor the given Characteristic. Each time a new value is written to the Characteristic
+//| add the newly-written bytes to a FIFO buffer.
+//|
+//| Monitor the given Characteristic. Each time a new value is written to the Characteristic
+//| add the newly-written packet of bytes to a FIFO buffer.
+//|
+//| :param Characteristic characteristic: The Characteristic to monitor.
+//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic
+//| in a remote Service that a Central has connected to.
+//| :param int buffer_size: Size of ring buffer (in packets of the Characteristic's maximum
+//| length) that stores incoming packets coming from the peer.
+//| :param int max_packet_size: Maximum size of packets. Overrides value from the characteristic.
+//| (Remote characteristics may not have the correct length.)"""
+//| ...
+//|
+STATIC mp_obj_t bleio_packet_buffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_characteristic, ARG_buffer_size, ARG_max_packet_size };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_max_packet_size, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_characteristic_obj_t *characteristic = mp_arg_validate_type(args[ARG_characteristic].u_obj, &bleio_characteristic_type, MP_QSTR_characteristic);
+
+ const mp_int_t buffer_size = args[ARG_buffer_size].u_int;
+ if (buffer_size < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size);
+ }
+
+ size_t max_packet_size = common_hal_bleio_characteristic_get_max_length(characteristic);
+ if (args[ARG_max_packet_size].u_obj != mp_const_none) {
+ max_packet_size = mp_obj_get_int(args[ARG_max_packet_size].u_obj);
+ }
+
+ bleio_packet_buffer_obj_t *self = m_new_obj(bleio_packet_buffer_obj_t);
+ self->base.type = &bleio_packet_buffer_type;
+
+ common_hal_bleio_packet_buffer_construct(self, characteristic, buffer_size, max_packet_size);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void check_for_deinit(bleio_packet_buffer_obj_t *self) {
+ if (common_hal_bleio_packet_buffer_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def readinto(self, buf: WriteableBuffer) -> int:
+//| """Reads a single BLE packet into the ``buf``. Raises an exception if the next packet is longer
+//| than the given buffer. Use `incoming_packet_length` to read the maximum length of a single packet.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: int"""
+//| ...
+//|
+STATIC mp_obj_t bleio_packet_buffer_readinto(mp_obj_t self_in, mp_obj_t buffer_obj) {
+ bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buffer_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ mp_int_t size = common_hal_bleio_packet_buffer_readinto(self, bufinfo.buf, bufinfo.len);
+ if (size < 0) {
+ mp_raise_ValueError_varg(translate("Buffer too short by %d bytes"), size * -1);
+ }
+
+ return MP_OBJ_NEW_SMALL_INT(size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_packet_buffer_readinto_obj, bleio_packet_buffer_readinto);
+
+//| def write(self, data: ReadableBuffer, *, header: Optional[bytes] = None) -> int:
+//| """Writes all bytes from data into the same outgoing packet. The bytes from header are included
+//| before data when the pending packet is currently empty.
+//|
+//| This does not block until the data is sent. It only blocks until the data is pending.
+//|
+//| :return: number of bytes written. May include header bytes when packet is empty.
+//| :rtype: int"""
+//| ...
+//|
+// TODO: Add a kwarg `merge=False` to dictate whether subsequent writes are merged into a pending
+// one.
+STATIC mp_obj_t bleio_packet_buffer_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_data, ARG_header };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_header, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+
+ mp_buffer_info_t data_bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ);
+
+ mp_buffer_info_t header_bufinfo;
+ header_bufinfo.len = 0;
+ if (args[ARG_header].u_obj != mp_const_none) {
+ mp_get_buffer_raise(args[ARG_header].u_obj, &header_bufinfo, MP_BUFFER_READ);
+ }
+
+ mp_int_t num_bytes_written = common_hal_bleio_packet_buffer_write(
+ self, data_bufinfo.buf, data_bufinfo.len, header_bufinfo.buf, header_bufinfo.len);
+ if (num_bytes_written < 0) {
+ // TODO: Raise an error if not connected. Right now the not-connected error
+ // is unreliable, because common_hal_bleio_packet_buffer_write()
+ // checks for conn_handle being set, but setting that
+ // can be delayed because conn_handle is discovered by spying on
+ // gatts write events, which may not have been sent yet.
+ //
+ // IDEAL:
+ // mp_raise_ConnectionError(translate("Not connected"));
+ // TEMPORARY:
+ num_bytes_written = 0;
+ }
+ return MP_OBJ_NEW_SMALL_INT(num_bytes_written);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_packet_buffer_write_obj, 1, bleio_packet_buffer_write);
+
+//| def deinit(self) -> None:
+//| """Disable permanently."""
+//| ...
+STATIC mp_obj_t bleio_packet_buffer_deinit(mp_obj_t self_in) {
+ bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_bleio_packet_buffer_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_deinit_obj, bleio_packet_buffer_deinit);
+
+//| incoming_packet_length: int
+//| """Maximum length in bytes of a packet we are reading."""
+//|
+STATIC mp_obj_t bleio_packet_buffer_get_incoming_packet_length(mp_obj_t self_in) {
+ bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t size = common_hal_bleio_packet_buffer_get_incoming_packet_length(self);
+ if (size < 0) {
+ mp_raise_ValueError(translate("No connection: length cannot be determined"));
+ }
+ return MP_OBJ_NEW_SMALL_INT(size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_get_incoming_packet_length_obj, bleio_packet_buffer_get_incoming_packet_length);
+
+MP_PROPERTY_GETTER(bleio_packet_buffer_incoming_packet_length_obj,
+ (mp_obj_t)&bleio_packet_buffer_get_incoming_packet_length_obj);
+
+//| outgoing_packet_length: int
+//| """Maximum length in bytes of a packet we are writing."""
+//|
+STATIC mp_obj_t bleio_packet_buffer_get_outgoing_packet_length(mp_obj_t self_in) {
+ bleio_packet_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t size = common_hal_bleio_packet_buffer_get_outgoing_packet_length(self);
+ if (size < 0) {
+ mp_raise_ValueError(translate("No connection: length cannot be determined"));
+ }
+ return MP_OBJ_NEW_SMALL_INT(size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_packet_buffer_get_outgoing_packet_length_obj, bleio_packet_buffer_get_outgoing_packet_length);
+
+MP_PROPERTY_GETTER(bleio_packet_buffer_outgoing_packet_length_obj,
+ (mp_obj_t)&bleio_packet_buffer_get_outgoing_packet_length_obj);
+
+STATIC const mp_rom_map_elem_t bleio_packet_buffer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_packet_buffer_deinit_obj) },
+
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bleio_packet_buffer_readinto_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&bleio_packet_buffer_write_obj) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_incoming_packet_length), MP_ROM_PTR(&bleio_packet_buffer_incoming_packet_length_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_outgoing_packet_length), MP_ROM_PTR(&bleio_packet_buffer_outgoing_packet_length_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_packet_buffer_locals_dict, bleio_packet_buffer_locals_dict_table);
+
+
+const mp_obj_type_t bleio_packet_buffer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PacketBuffer,
+ .make_new = bleio_packet_buffer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&bleio_packet_buffer_locals_dict
+};
diff --git a/circuitpython/shared-bindings/_bleio/PacketBuffer.h b/circuitpython/shared-bindings/_bleio/PacketBuffer.h
new file mode 100644
index 0000000..adead29
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/PacketBuffer.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PACKETBUFFER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PACKETBUFFER_H
+
+#include "common-hal/_bleio/PacketBuffer.h"
+
+extern const mp_obj_type_t bleio_packet_buffer_type;
+
+void common_hal_bleio_packet_buffer_construct(
+ bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic,
+ size_t buffer_size, size_t max_packet_size);
+// Allocation free
+void _common_hal_bleio_packet_buffer_construct(
+ bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic,
+ uint32_t *incoming_buffer, size_t incoming_buffer_size,
+ uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t outgoing_buffer_size,
+ void *static_handler_entry);
+mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len);
+mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len);
+mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self);
+mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self);
+void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self);
+bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self);
+void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PACKETBUFFER_H
diff --git a/circuitpython/shared-bindings/_bleio/ScanEntry.c b/circuitpython/shared-bindings/_bleio/ScanEntry.c
new file mode 100644
index 0000000..d9434f3
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/ScanEntry.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-bindings/_bleio/ScanEntry.h"
+#include "shared-bindings/_bleio/UUID.h"
+#include "shared-module/_bleio/ScanEntry.h"
+
+//| class ScanEntry:
+//| """Encapsulates information about a device that was received during scanning. It can be
+//| advertisement or scan response data. This object may only be created by a `_bleio.ScanResults`:
+//| it has no user-visible constructor."""
+//|
+
+//| def __init__(self) -> None:
+//| """Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`."""
+//| ...
+//|
+//| def matches(self, prefixes: ScanEntry, *, match_all: bool = True) -> bool:
+//| """Returns True if the ScanEntry matches all prefixes when ``match_all`` is True. This is stricter
+//| than the scan filtering which accepts any advertisements that match any of the prefixes
+//| where ``match_all`` is False.
+//|
+//| ``all`` also works for ``match_all`` but will be removed in CircuitPython 8."""
+//| ...
+//|
+STATIC mp_obj_t bleio_scanentry_matches(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_prefixes, ARG_all, ARG_match_all };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_prefixes, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_all, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_match_all, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bool match_all = args[ARG_all].u_bool && args[ARG_match_all].u_bool;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_prefixes].u_obj, &bufinfo, MP_BUFFER_READ);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_matches(self, bufinfo.buf, bufinfo.len, match_all));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanentry_matches_obj, 1, bleio_scanentry_matches);
+
+//| address: Address
+//| """The address of the device (read-only), of type `_bleio.Address`."""
+//|
+STATIC mp_obj_t bleio_scanentry_get_address(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_bleio_scanentry_get_address(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_address_obj, bleio_scanentry_get_address);
+
+MP_PROPERTY_GETTER(bleio_scanentry_address_obj,
+ (mp_obj_t)&bleio_scanentry_get_address_obj);
+
+//| advertisement_bytes: bytes
+//| """All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only)"""
+//|
+STATIC mp_obj_t scanentry_get_advertisement_bytes(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_bleio_scanentry_get_advertisement_bytes(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_advertisement_bytes_obj, scanentry_get_advertisement_bytes);
+
+MP_PROPERTY_GETTER(bleio_scanentry_advertisement_bytes_obj,
+ (mp_obj_t)&bleio_scanentry_get_advertisement_bytes_obj);
+
+//| rssi: int
+//| """The signal strength of the device at the time of the scan, in integer dBm. (read-only)"""
+//|
+STATIC mp_obj_t scanentry_get_rssi(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_bleio_scanentry_get_rssi(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_rssi_obj, scanentry_get_rssi);
+
+MP_PROPERTY_GETTER(bleio_scanentry_rssi_obj,
+ (mp_obj_t)&bleio_scanentry_get_rssi_obj);
+
+//| connectable: bool
+//| """True if the device can be connected to. (read-only)"""
+//|
+STATIC mp_obj_t scanentry_get_connectable(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_get_connectable(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_connectable_obj, scanentry_get_connectable);
+
+MP_PROPERTY_GETTER(bleio_scanentry_connectable_obj,
+ (mp_obj_t)&bleio_scanentry_get_connectable_obj);
+
+//| scan_response: bool
+//| """True if the entry was a scan response. (read-only)"""
+//|
+STATIC mp_obj_t scanentry_get_scan_response(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_get_scan_response(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_scan_response_obj, scanentry_get_scan_response);
+
+MP_PROPERTY_GETTER(bleio_scanentry_scan_response_obj,
+ (mp_obj_t)&bleio_scanentry_get_scan_response_obj);
+
+STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_advertisement_bytes), MP_ROM_PTR(&bleio_scanentry_advertisement_bytes_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connectable), MP_ROM_PTR(&bleio_scanentry_connectable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan_response), MP_ROM_PTR(&bleio_scanentry_scan_response_obj) },
+ { MP_ROM_QSTR(MP_QSTR_matches), MP_ROM_PTR(&bleio_scanentry_matches_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table);
+
+const mp_obj_type_t bleio_scanentry_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ScanEntry,
+ .locals_dict = (mp_obj_dict_t *)&bleio_scanentry_locals_dict
+};
diff --git a/circuitpython/shared-bindings/_bleio/ScanEntry.h b/circuitpython/shared-bindings/_bleio/ScanEntry.h
new file mode 100644
index 0000000..b376433
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/ScanEntry.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H
+
+#include "py/obj.h"
+#include "shared-module/_bleio/ScanEntry.h"
+
+extern const mp_obj_type_t bleio_scanentry_type;
+
+mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self);
+mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self);
+mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_get_connectable(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_get_scan_response(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_matches(bleio_scanentry_obj_t *self, const uint8_t *prefixes, size_t prefixes_len, bool match_all);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H
diff --git a/circuitpython/shared-bindings/_bleio/ScanResults.c b/circuitpython/shared-bindings/_bleio/ScanResults.c
new file mode 100644
index 0000000..bee6cfa
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/ScanResults.c
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/ScanResults.h"
+
+//| class ScanResults:
+//| """Iterates over advertising data received while scanning. This object is always created
+//| by a `_bleio.Adapter`: it has no user-visible constructor."""
+//|
+STATIC mp_obj_t scanresults_iternext(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &bleio_scanresults_type));
+ bleio_scanresults_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t scan_entry = common_hal_bleio_scanresults_next(self);
+ if (scan_entry != mp_const_none) {
+ return scan_entry;
+ }
+ return MP_OBJ_STOP_ITERATION;
+}
+
+//| def __init__(self) -> None:
+//| """Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`."""
+//| ...
+//|
+//| def __iter__(self) -> Iterator[ScanEntry]:
+//| """Returns itself since it is the iterator."""
+//| ...
+//|
+//| def __next__(self) -> ScanEntry:
+//| """Returns the next `_bleio.ScanEntry`. Blocks if none have been received and scanning is still
+//| active. Raises `StopIteration` if scanning is finished and no other results are available."""
+//| ...
+//|
+
+const mp_obj_type_t bleio_scanresults_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_ScanResults,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = scanresults_iternext,
+ ),
+};
diff --git a/circuitpython/shared-bindings/_bleio/ScanResults.h b/circuitpython/shared-bindings/_bleio/ScanResults.h
new file mode 100644
index 0000000..a8c88c2
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/ScanResults.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
+
+#include "py/obj.h"
+#include "shared-module/_bleio/ScanResults.h"
+
+extern const mp_obj_type_t bleio_scanresults_type;
+
+mp_obj_t common_hal_bleio_scanresults_next(bleio_scanresults_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
diff --git a/circuitpython/shared-bindings/_bleio/Service.c b/circuitpython/shared-bindings/_bleio/Service.c
new file mode 100644
index 0000000..ddbdecd
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Service.c
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/Service.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| class Service:
+//| """Stores information about a BLE service and its characteristics."""
+//|
+//| def __init__(self, uuid: UUID, *, secondary: bool = False) -> None:
+//| """Create a new Service identified by the specified UUID. It can be accessed by all
+//| connections. This is known as a Service server. Client Service objects are created via
+//| `Connection.discover_remote_services`.
+//|
+//| To mark the Service as secondary, pass `True` as :py:data:`secondary`.
+//|
+//| :param UUID uuid: The uuid of the service
+//| :param bool secondary: If the service is a secondary one
+//|
+//| :return: the new Service"""
+//| ...
+//|
+STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_uuid, ARG_secondary };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bleio_uuid_obj_t *uuid = mp_arg_validate_type(args[ARG_uuid].u_obj, &bleio_uuid_type, MP_QSTR_uuid);
+
+ const bool is_secondary = args[ARG_secondary].u_bool;
+
+ bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
+ service->base.type = &bleio_service_type;
+
+ common_hal_bleio_service_construct(service, uuid, is_secondary);
+
+ return MP_OBJ_FROM_PTR(service);
+}
+
+//| characteristics: Tuple[Characteristic, ...]
+//| """A tuple of :py:class:`Characteristic` designating the characteristics that are offered by
+//| this service. (read-only)"""
+//|
+STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_FROM_PTR(common_hal_bleio_service_get_characteristics(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics);
+
+MP_PROPERTY_GETTER(bleio_service_characteristics_obj,
+ (mp_obj_t)&bleio_service_get_characteristics_obj);
+
+//| remote: bool
+//| """True if this is a service provided by a remote device. (read-only)"""
+//|
+STATIC mp_obj_t bleio_service_get_remote(mp_obj_t self_in) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_service_get_is_remote(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_remote_obj, bleio_service_get_remote);
+
+MP_PROPERTY_GETTER(bleio_service_remote_obj,
+ (mp_obj_t)&bleio_service_get_remote_obj);
+
+//| secondary: bool
+//| """True if this is a secondary service. (read-only)"""
+//|
+STATIC mp_obj_t bleio_service_get_secondary(mp_obj_t self_in) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_service_get_is_secondary(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_secondary_obj, bleio_service_get_secondary);
+
+MP_PROPERTY_GETTER(bleio_service_secondary_obj,
+ (mp_obj_t)&bleio_service_get_secondary_obj);
+
+//| uuid: Optional[UUID]
+//| """The UUID of this service. (read-only)
+//|
+//| Will be ``None`` if the 128-bit UUID for this service is not known."""
+//|
+STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ bleio_uuid_obj_t *uuid = common_hal_bleio_service_get_uuid(self);
+ return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_uuid_obj, bleio_service_get_uuid);
+
+MP_PROPERTY_GETTER(bleio_service_uuid_obj,
+ (mp_obj_t)&bleio_service_get_uuid_obj);
+
+
+STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) },
+ { MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remote), MP_ROM_PTR(&bleio_service_remote_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table);
+
+STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->uuid) {
+ mp_printf(print, "Service(");
+ bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind);
+ mp_printf(print, ")");
+ } else {
+ mp_printf(print, "<Service with unregistered UUID>");
+ }
+}
+
+const mp_obj_type_t bleio_service_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Service,
+ .make_new = bleio_service_make_new,
+ .print = bleio_service_print,
+ .locals_dict = (mp_obj_dict_t *)&bleio_service_locals_dict
+};
diff --git a/circuitpython/shared-bindings/_bleio/Service.h b/circuitpython/shared-bindings/_bleio/Service.h
new file mode 100644
index 0000000..eb1d29b
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/Service.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
+
+#include "common-hal/_bleio/Characteristic.h"
+#include "common-hal/_bleio/Connection.h"
+#include "common-hal/_bleio/Service.h"
+
+#include "py/objtuple.h"
+
+extern const mp_obj_type_t bleio_service_type;
+
+// Private version that doesn't allocate on the heap
+extern uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t *characteristic_list);
+extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary);
+extern void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, bleio_connection_obj_t *connection, bleio_uuid_obj_t *uuid, bool is_secondary);
+extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self);
+extern mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self);
+extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self);
+extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self);
+extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo, const char *user_description);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
diff --git a/circuitpython/shared-bindings/_bleio/UUID.c b/circuitpython/shared-bindings/_bleio/UUID.c
new file mode 100644
index 0000000..599a89a
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/UUID.c
@@ -0,0 +1,300 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| class UUID:
+//| """A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more."""
+//|
+//| def __init__(self, value: Union[int, ReadableBuffer, str]) -> None:
+//| """Create a new UUID or UUID object encapsulating the uuid value.
+//| The value can be one of:
+//|
+//| - an `int` value in range 0 to 0xFFFF (Bluetooth SIG 16-bit UUID)
+//| - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID)
+//| - a string of hex digits of the form 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+//|
+//| Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a
+//| temporary 16-bit UUID that can be used in place of the full 128-bit UUID.
+//|
+//| :param value: The uuid value to encapsulate
+//| :type value: int, ~circuitpython_typing.ReadableBuffer or str"""
+//| ...
+//|
+STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ bleio_uuid_obj_t *self = m_new_obj(bleio_uuid_obj_t);
+ self->base.type = type;
+
+ const mp_obj_t value = all_args[0];
+ uint8_t uuid128[16];
+
+ if (mp_obj_is_int(value)) {
+ mp_int_t uuid16 = mp_obj_get_int(value);
+ if (uuid16 < 0 || uuid16 > 0xffff) {
+ mp_raise_ValueError(translate("UUID integer value must be 0-0xffff"));
+ }
+
+ // NULL means no 128-bit value.
+ common_hal_bleio_uuid_construct(self, uuid16, NULL);
+
+ } else {
+ if (mp_obj_is_str(value)) {
+ // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+ GET_STR_DATA_LEN(value, chars, len);
+ char hex[32];
+ // Validate length, hyphens, and hex digits.
+ bool good_uuid =
+ len == 36 && chars[8] == '-' && chars[13] == '-' && chars[18] == '-' && chars[23] == '-';
+ if (good_uuid) {
+ size_t hex_idx = 0;
+ for (size_t i = 0; i < len; i++) {
+ if (unichar_isxdigit(chars[i])) {
+ hex[hex_idx] = chars[i];
+ hex_idx++;
+ }
+ }
+ good_uuid = hex_idx == 32;
+ }
+ if (!good_uuid) {
+ mp_raise_ValueError(translate("UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'"));
+ }
+
+ size_t hex_idx = 0;
+ for (int i = 15; i >= 0; i--) {
+ uuid128[i] = (unichar_xdigit_value(hex[hex_idx]) << 4) | unichar_xdigit_value(hex[hex_idx + 1]);
+ hex_idx += 2;
+ }
+ } else {
+ // Last possibility is that it's a buf.
+ mp_buffer_info_t bufinfo;
+ if (!mp_get_buffer(value, &bufinfo, MP_BUFFER_READ)) {
+ mp_raise_ValueError(translate("UUID value is not str, int or byte buffer"));
+ }
+
+ if (bufinfo.len != 16) {
+ mp_raise_ValueError(translate("Byte buffer must be 16 bytes."));
+ }
+
+ memcpy(uuid128, bufinfo.buf, 16);
+ }
+
+ // Str and bytes both get constructed the same way here.
+ uint32_t uuid16 = (uuid128[13] << 8) | uuid128[12];
+ uuid128[12] = 0;
+ uuid128[13] = 0;
+ common_hal_bleio_uuid_construct(self, uuid16, uuid128);
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| uuid16: int
+//| """The 16-bit part of the UUID. (read-only)
+//|
+//| :type: int"""
+//|
+STATIC mp_obj_t bleio_uuid_get_uuid16(mp_obj_t self_in) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid16_obj, bleio_uuid_get_uuid16);
+
+MP_PROPERTY_GETTER(bleio_uuid_uuid16_obj,
+ (mp_obj_t)&bleio_uuid_get_uuid16_obj);
+
+//| uuid128: bytes
+//| """The 128-bit value of the UUID
+//| Raises AttributeError if this is a 16-bit UUID. (read-only)
+//|
+//| :type: bytes"""
+//|
+STATIC mp_obj_t bleio_uuid_get_uuid128(mp_obj_t self_in) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ uint8_t uuid128[16];
+ if (common_hal_bleio_uuid_get_size(self) != 128) {
+ mp_raise_AttributeError(translate("not a 128-bit UUID"));
+ }
+ common_hal_bleio_uuid_get_uuid128(self, uuid128);
+ return mp_obj_new_bytes(uuid128, 16);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid128_obj, bleio_uuid_get_uuid128);
+
+MP_PROPERTY_GETTER(bleio_uuid_uuid128_obj,
+ (mp_obj_t)&bleio_uuid_get_uuid128_obj);
+
+//| size: int
+//| """128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a
+//| 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported.
+//|
+//| :type: int"""
+//|
+STATIC mp_obj_t bleio_uuid_get_size(mp_obj_t self_in) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_size(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_size_obj, bleio_uuid_get_size);
+
+MP_PROPERTY_GETTER(bleio_uuid_size_obj,
+ (mp_obj_t)&bleio_uuid_get_size_obj);
+
+
+//| def pack_into(self, buffer: WriteableBuffer, offset: int = 0) -> None:
+//| """Packs the UUID into the given buffer at the given offset."""
+//| ...
+//|
+STATIC mp_obj_t bleio_uuid_pack_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_buffer, ARG_offset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ size_t offset = args[ARG_offset].u_int;
+ if (offset + common_hal_bleio_uuid_get_size(self) / 8 > bufinfo.len) {
+ mp_raise_ValueError(translate("Buffer + offset too small %d %d %d"));
+ }
+
+ common_hal_bleio_uuid_pack_into(self, bufinfo.buf + offset);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_uuid_pack_into_obj, 1, bleio_uuid_pack_into);
+
+STATIC const mp_rom_map_elem_t bleio_uuid_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_uuid16), MP_ROM_PTR(&bleio_uuid_uuid16_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uuid128), MP_ROM_PTR(&bleio_uuid_uuid128_obj) },
+ { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&bleio_uuid_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&bleio_uuid_pack_into_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_uuid_locals_dict, bleio_uuid_locals_dict_table);
+
+STATIC mp_obj_t bleio_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_HASH:
+ if (common_hal_bleio_uuid_get_size(self) == 16) {
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self));
+ } else {
+ union {
+ uint8_t uuid128_bytes[16];
+ uint16_t uuid128_uint16[8];
+ } uuid128;
+ common_hal_bleio_uuid_get_uuid128(self, uuid128.uuid128_bytes);
+ int hash = 0;
+ for (size_t i = 0; i < MP_ARRAY_SIZE(uuid128.uuid128_uint16); i++) {
+ hash += uuid128.uuid128_uint16[i];
+ }
+ return MP_OBJ_NEW_SMALL_INT(hash);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __eq__(self, other: object) -> bool:
+//| """Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit."""
+//| ...
+//|
+STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ switch (op) {
+ // Two UUID's are equal if their uuid16 values match or their uuid128 values match.
+ case MP_BINARY_OP_EQUAL:
+ if (mp_obj_is_type(rhs_in, &bleio_uuid_type)) {
+ if (common_hal_bleio_uuid_get_size(lhs_in) == 16 &&
+ common_hal_bleio_uuid_get_size(rhs_in) == 16) {
+ return mp_obj_new_bool(common_hal_bleio_uuid_get_uuid16(lhs_in) ==
+ common_hal_bleio_uuid_get_uuid16(rhs_in));
+ }
+ uint8_t lhs[16];
+ uint8_t rhs[16];
+ common_hal_bleio_uuid_get_uuid128(lhs_in, lhs);
+ common_hal_bleio_uuid_get_uuid128(rhs_in, rhs);
+ return mp_obj_new_bool(memcmp(lhs, rhs, sizeof(lhs)) == 0);
+ } else {
+ return mp_const_false;
+ }
+
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint32_t size = common_hal_bleio_uuid_get_size(self);
+ if (size == 16) {
+ mp_printf(print, "UUID(0x%04x)", common_hal_bleio_uuid_get_uuid16(self));
+ } else {
+ uint8_t uuid128[16];
+ common_hal_bleio_uuid_get_uuid128(self, uuid128);
+ mp_printf(print, "UUID('"
+ "%02x%02x%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x')",
+ uuid128[15], uuid128[14], uuid128[13], uuid128[12],
+ uuid128[11], uuid128[10],
+ uuid128[9], uuid128[8],
+ uuid128[7], uuid128[6],
+ uuid128[5], uuid128[4], uuid128[3], uuid128[2], uuid128[1], uuid128[0]);
+ }
+}
+
+const mp_obj_type_t bleio_uuid_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_UUID,
+ .print = bleio_uuid_print,
+ .make_new = bleio_uuid_make_new,
+ .locals_dict = (mp_obj_dict_t *)&bleio_uuid_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = bleio_uuid_unary_op,
+ .binary_op = bleio_uuid_binary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/_bleio/UUID.h b/circuitpython/shared-bindings/_bleio/UUID.h
new file mode 100644
index 0000000..d07e903
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/UUID.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H
+
+#include "common-hal/_bleio/UUID.h"
+
+void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
+
+extern const mp_obj_type_t bleio_uuid_type;
+
+extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]);
+extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self);
+extern void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]);
+extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self);
+
+void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t *buf);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H
diff --git a/circuitpython/shared-bindings/_bleio/__init__.c b/circuitpython/shared-bindings/_bleio/__init__.c
new file mode 100644
index 0000000..72d9684
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/__init__.c
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2016 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#include "py/objexcept.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-bindings/_bleio/Attribute.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/CharacteristicBuffer.h"
+#include "shared-bindings/_bleio/Connection.h"
+#include "shared-bindings/_bleio/Descriptor.h"
+#include "shared-bindings/_bleio/PacketBuffer.h"
+#include "shared-bindings/_bleio/ScanEntry.h"
+#include "shared-bindings/_bleio/ScanResults.h"
+#include "shared-bindings/_bleio/Service.h"
+#include "shared-bindings/_bleio/UUID.h"
+
+//| """Bluetooth Low Energy (BLE) communication
+//|
+//| The `_bleio` module provides necessary low-level functionality for communicating
+//| using Bluetooth Low Energy (BLE). The '_' prefix indicates this module is meant
+//| for internal use by libraries but not by the end user. Its API may change incompatibly
+//| between minor versions of CircuitPython.
+//| Please use the
+//| `adafruit_ble <https://circuitpython.readthedocs.io/projects/ble/en/latest/>`_
+//| CircuitPython library instead, which builds on `_bleio`, and
+//| provides higher-level convenience functionality, including predefined beacons, clients,
+//| servers."""
+//|
+
+//| adapter: Adapter
+//| """BLE Adapter used to manage device discovery and connections.
+//| This object is the sole instance of `_bleio.Adapter`."""
+//|
+
+//| class BluetoothError(Exception):
+//| """Catchall exception for Bluetooth related errors."""
+//| ...
+MP_DEFINE_BLEIO_EXCEPTION(BluetoothError, Exception)
+NORETURN void mp_raise_bleio_BluetoothError(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_BluetoothError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+//| class RoleError(BluetoothError):
+//| """Raised when a resource is used as the mismatched role. For example, if a local CCCD is
+//| attempted to be set but they can only be set when remote."""
+//| ...
+//|
+MP_DEFINE_BLEIO_EXCEPTION(RoleError, bleio_BluetoothError)
+NORETURN void mp_raise_bleio_RoleError(const compressed_string_t *msg) {
+ mp_raise_msg(&mp_type_bleio_RoleError, msg);
+}
+
+//| class SecurityError(BluetoothError):
+//| """Raised when a security related error occurs."""
+//| ...
+//|
+MP_DEFINE_BLEIO_EXCEPTION(SecurityError, bleio_BluetoothError)
+NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_SecurityError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+// Called when _bleio is imported.
+STATIC mp_obj_t bleio___init__(void) {
+// HCI cannot be enabled on import, because we need to setup the HCI adapter first.
+ #if !CIRCUITPY_BLEIO_HCI
+ common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true);
+ #endif
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(bleio___init___obj, bleio___init__);
+
+
+// Need a forward reference due to mutual references.
+#if CIRCUITPY_BLEIO_HCI
+STATIC mp_obj_dict_t bleio_module_globals;
+#endif
+
+//| def set_adapter(adapter: Optional[_bleio.Adapter]) -> None:
+//| """Set the adapter to use for BLE, such as when using an HCI adapter.
+//| Raises `NotImplementedError` when the adapter is a singleton and cannot be set."""
+//| ...
+//|
+mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj) {
+ #if CIRCUITPY_BLEIO_HCI
+ if (adapter_obj != mp_const_none && !mp_obj_is_type(adapter_obj, &bleio_adapter_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), bleio_adapter_type.name);
+ }
+
+ // Equivalent of:
+ // bleio.adapter = adapter_obj
+ mp_map_elem_t *elem = mp_map_lookup(&bleio_module_globals.map, MP_ROM_QSTR(MP_QSTR_adapter), MP_MAP_LOOKUP);
+ if (elem) {
+ elem->value = adapter_obj;
+ }
+ #else
+ mp_raise_NotImplementedError(translate("Not settable"));
+ #endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_set_adapter_obj, bleio_set_adapter);
+
+#if CIRCUITPY_BLEIO_HCI
+// Make the module dictionary be in RAM, so that _bleio.adapter can be set.
+// Use a local macro to define how table entries should be converted.
+#define OBJ_FROM_PTR MP_OBJ_FROM_PTR
+STATIC mp_map_elem_t bleio_module_globals_table[] = {
+#else
+#define OBJ_FROM_PTR MP_ROM_PTR
+STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = {
+ #endif
+ // Name must be the first entry so that the exception printing below is correct.
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bleio) },
+ { MP_ROM_QSTR(MP_QSTR_Adapter), OBJ_FROM_PTR(&bleio_adapter_type) },
+ { MP_ROM_QSTR(MP_QSTR_Address), OBJ_FROM_PTR(&bleio_address_type) },
+ { MP_ROM_QSTR(MP_QSTR_Attribute), OBJ_FROM_PTR(&bleio_attribute_type) },
+ { MP_ROM_QSTR(MP_QSTR_Connection), OBJ_FROM_PTR(&bleio_connection_type) },
+ { MP_ROM_QSTR(MP_QSTR_Characteristic), OBJ_FROM_PTR(&bleio_characteristic_type) },
+ { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), OBJ_FROM_PTR(&bleio_characteristic_buffer_type) },
+ { MP_ROM_QSTR(MP_QSTR_Descriptor), OBJ_FROM_PTR(&bleio_descriptor_type) },
+ { MP_ROM_QSTR(MP_QSTR_PacketBuffer), OBJ_FROM_PTR(&bleio_packet_buffer_type) },
+ { MP_ROM_QSTR(MP_QSTR_ScanEntry), OBJ_FROM_PTR(&bleio_scanentry_type) },
+ { MP_ROM_QSTR(MP_QSTR_ScanResults), OBJ_FROM_PTR(&bleio_scanresults_type) },
+ { MP_ROM_QSTR(MP_QSTR_Service), OBJ_FROM_PTR(&bleio_service_type) },
+ { MP_ROM_QSTR(MP_QSTR_UUID), OBJ_FROM_PTR(&bleio_uuid_type) },
+
+ #if CIRCUITPY_BLEIO_HCI
+ // For HCI, _bleio.adapter is settable, and starts as None.
+ { MP_ROM_QSTR(MP_QSTR_adapter), mp_const_none },
+ { MP_ROM_QSTR(MP_QSTR_set_adapter), (mp_obj_t)&bleio_set_adapter_obj },
+ #else
+ // For non-HCI _bleio.adapter is a fixed singleton, and is not settable.
+ // _bleio.set_adapter will raise NotImplementedError.
+ { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_adapter), MP_ROM_PTR(&bleio_set_adapter_obj) },
+ #endif
+
+ // Errors
+ { MP_ROM_QSTR(MP_QSTR_BluetoothError), OBJ_FROM_PTR(&mp_type_bleio_BluetoothError) },
+ { MP_ROM_QSTR(MP_QSTR_RoleError), OBJ_FROM_PTR(&mp_type_bleio_RoleError) },
+ { MP_ROM_QSTR(MP_QSTR_SecurityError), OBJ_FROM_PTR(&mp_type_bleio_SecurityError) },
+
+ // Initialization
+ { MP_ROM_QSTR(MP_QSTR___init__), OBJ_FROM_PTR(&bleio___init___obj) },
+};
+
+#if CIRCUITPY_BLEIO_HCI
+// Module dict is mutable to allow setting _bleio.adapter.
+STATIC MP_DEFINE_MUTABLE_DICT(bleio_module_globals, bleio_module_globals_table);
+#else
+STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table);
+#endif
+
+void bleio_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
+ bool is_subclass = kind & PRINT_EXC_SUBCLASS;
+ if (!is_subclass && (k == PRINT_EXC)) {
+ mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(bleio_module_globals_table[0].value)));
+ mp_print_str(print, ".");
+ }
+ mp_obj_exception_print(print, o_in, kind);
+}
+
+const mp_obj_module_t bleio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&bleio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__bleio, bleio_module, CIRCUITPY_BLEIO);
diff --git a/circuitpython/shared-bindings/_bleio/__init__.h b/circuitpython/shared-bindings/_bleio/__init__.h
new file mode 100644
index 0000000..f34df30
--- /dev/null
+++ b/circuitpython/shared-bindings/_bleio/__init__.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2016 Glenn Ruben Bakke
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
+
+#include "py/objlist.h"
+
+#include "shared-bindings/_bleio/Adapter.h"
+
+#include "common-hal/_bleio/__init__.h"
+#include "common-hal/_bleio/Adapter.h"
+
+extern bleio_adapter_obj_t common_hal_bleio_adapter_obj;
+
+void bleio_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
+
+#define MP_DEFINE_BLEIO_EXCEPTION(exc_name, base_name) \
+ const mp_obj_type_t mp_type_bleio_##exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_##exc_name, \
+ .print = bleio_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .attr = mp_obj_exception_attr, \
+ .parent = &mp_type_##base_name, \
+ };
+
+extern const mp_obj_type_t mp_type_bleio_BluetoothError;
+extern const mp_obj_type_t mp_type_bleio_RoleError;
+extern const mp_obj_type_t mp_type_bleio_SecurityError;
+
+// Resets all user created BLE state in preparation for the heap disappearing.
+// It will maintain BLE workflow and connections.
+void bleio_user_reset(void);
+
+// Completely resets the BLE stack including BLE connections.
+void bleio_reset(void);
+
+extern mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj);
+
+NORETURN void mp_raise_bleio_BluetoothError(const compressed_string_t *msg, ...);
+NORETURN void mp_raise_bleio_RoleError(const compressed_string_t *msg);
+NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t *msg, ...);
+
+bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void);
+void common_hal_bleio_check_connected(uint16_t conn_handle);
+
+uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device);
+void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist);
+
+size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len);
+void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo);
+size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len);
+void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response);
+
+void common_hal_bleio_gc_collect(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
diff --git a/circuitpython/shared-bindings/_eve/__init__.c b/circuitpython/shared-bindings/_eve/__init__.c
new file mode 100644
index 0000000..13e51cb
--- /dev/null
+++ b/circuitpython/shared-bindings/_eve/__init__.c
@@ -0,0 +1,1109 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/binary.h"
+
+#include "shared-module/_eve/__init__.h"
+#include "shared-bindings/_eve/__init__.h"
+
+//| """Low-level BridgeTek EVE bindings
+//|
+//| The `_eve` module provides a class _EVE which
+//| contains methods for constructing EVE command
+//| buffers and appending basic graphics commands."""
+//|
+
+//| class _EVE:
+//|
+
+typedef struct _mp_obj__EVE_t {
+ mp_obj_base_t base;
+ common_hal__eve_t _eve;
+} mp_obj__EVE_t;
+
+STATIC const mp_obj_type_t _EVE_type;
+
+#define EVEHAL(s) \
+ (&((mp_obj__EVE_t *)mp_obj_cast_to_native_base((s), &_EVE_type))->_eve)
+
+//| def register(self, o: object) -> None:
+//| ...
+//|
+STATIC mp_obj_t _register(mp_obj_t self, mp_obj_t o) {
+ common_hal__eve_t *eve = EVEHAL(self);
+ mp_load_method(o, MP_QSTR_write, eve->dest);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(register_obj, _register);
+
+//| def flush(self) -> None:
+//| """Send any queued drawing commands directly to the hardware.
+//|
+//| :param int width: The width of the grid in tiles, or 1 for sprites."""
+//| ...
+//|
+STATIC mp_obj_t _flush(mp_obj_t self) {
+ common_hal__eve_flush(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(flush_obj, _flush);
+
+//| def cc(self, b: ReadableBuffer) -> None:
+//| """Append bytes to the command FIFO.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer b: The bytes to add"""
+//| ...
+//|
+STATIC mp_obj_t _cc(mp_obj_t self, mp_obj_t b) {
+ mp_buffer_info_t buffer_info;
+ mp_get_buffer_raise(b, &buffer_info, MP_BUFFER_READ);
+ common_hal__eve_add(EVEHAL(self), buffer_info.len, buffer_info.buf);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc_obj, _cc);
+
+// {
+
+//| def AlphaFunc(self, func: int, ref: int) -> None:
+//| """Set the alpha test function
+//|
+//| :param int func: specifies the test function, one of ``NEVER``, ``LESS``, ``LEQUAL``, ``GREATER``, ``GEQUAL``, ``EQUAL``, ``NOTEQUAL``, or ``ALWAYS``. Range 0-7. The initial value is ALWAYS(7)
+//| :param int ref: specifies the reference value for the alpha test. Range 0-255. The initial value is 0
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _alphafunc(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t func = mp_obj_get_int_truncated(a0);
+ uint32_t ref = mp_obj_get_int_truncated(a1);
+ common_hal__eve_AlphaFunc(EVEHAL(self), func, ref);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(alphafunc_obj, _alphafunc);
+
+//| def Begin(self, prim: int) -> None:
+//| """Begin drawing a graphics primitive
+//|
+//| :param int prim: graphics primitive.
+//|
+//| Valid primitives are ``BITMAPS``, ``POINTS``, ``LINES``, ``LINE_STRIP``, ``EDGE_STRIP_R``, ``EDGE_STRIP_L``, ``EDGE_STRIP_A``, ``EDGE_STRIP_B`` and ``RECTS``."""
+//| ...
+//|
+
+STATIC mp_obj_t _begin(mp_obj_t self, mp_obj_t a0) {
+ uint32_t prim = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Begin(EVEHAL(self), prim);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(begin_obj, _begin);
+
+//| def BitmapExtFormat(self, format: int) -> None:
+//| """Set the bitmap format
+//|
+//| :param int format: bitmap pixel format."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmapextformat(mp_obj_t self, mp_obj_t a0) {
+ uint32_t fmt = mp_obj_get_int_truncated(a0);
+ common_hal__eve_BitmapExtFormat(EVEHAL(self), fmt);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bitmapextformat_obj, _bitmapextformat);
+
+//| def BitmapHandle(self, handle: int) -> None:
+//| """Set the bitmap handle
+//|
+//| :param int handle: bitmap handle. Range 0-31. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaphandle(mp_obj_t self, mp_obj_t a0) {
+ uint32_t handle = mp_obj_get_int_truncated(a0);
+ common_hal__eve_BitmapHandle(EVEHAL(self), handle);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bitmaphandle_obj, _bitmaphandle);
+
+//| def BitmapLayoutH(self, linestride: int, height: int) -> None:
+//| """Set the source bitmap memory format and layout for the current handle. high bits for large bitmaps
+//|
+//| :param int linestride: high part of bitmap line stride, in bytes. Range 0-7
+//| :param int height: high part of bitmap height, in lines. Range 0-3"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaplayouth(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t linestride = mp_obj_get_int_truncated(a0);
+ uint32_t height = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapLayoutH(EVEHAL(self), linestride, height);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmaplayouth_obj, _bitmaplayouth);
+
+//| def BitmapLayout(self, format: int, linestride: int, height: int) -> None:
+//| """Set the source bitmap memory format and layout for the current handle
+//|
+//| :param int format: bitmap pixel format, or GLFORMAT to use BITMAP_EXT_FORMAT instead. Range 0-31
+//| :param int linestride: bitmap line stride, in bytes. Range 0-1023
+//| :param int height: bitmap height, in lines. Range 0-511"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaplayout(size_t n_args, const mp_obj_t *args) {
+ uint32_t format = mp_obj_get_int_truncated(args[1]);
+ uint32_t linestride = mp_obj_get_int_truncated(args[2]);
+ uint32_t height = mp_obj_get_int_truncated(args[3]);
+ common_hal__eve_BitmapLayout(EVEHAL(args[0]), format, linestride, height);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitmaplayout_obj, 4, 4, _bitmaplayout);
+
+//| def BitmapSizeH(self, width: int, height: int) -> None:
+//| """Set the screen drawing of bitmaps for the current handle. high bits for large bitmaps
+//|
+//| :param int width: high part of drawn bitmap width, in pixels. Range 0-3
+//| :param int height: high part of drawn bitmap height, in pixels. Range 0-3"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmapsizeh(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t width = mp_obj_get_int_truncated(a0);
+ uint32_t height = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapSizeH(EVEHAL(self), width, height);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmapsizeh_obj, _bitmapsizeh);
+
+//| def BitmapSize(self, filter: int, wrapx: int, wrapy: int, width: int, height: int) -> None:
+//| """Set the screen drawing of bitmaps for the current handle
+//|
+//| :param int filter: bitmap filtering mode, one of ``NEAREST`` or ``BILINEAR``. Range 0-1
+//| :param int wrapx: bitmap :math:`x` wrap mode, one of ``REPEAT`` or ``BORDER``. Range 0-1
+//| :param int wrapy: bitmap :math:`y` wrap mode, one of ``REPEAT`` or ``BORDER``. Range 0-1
+//| :param int width: drawn bitmap width, in pixels. Range 0-511
+//| :param int height: drawn bitmap height, in pixels. Range 0-511"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmapsize(size_t n_args, const mp_obj_t *args) {
+ uint32_t filter = mp_obj_get_int_truncated(args[1]);
+ uint32_t wrapx = mp_obj_get_int_truncated(args[2]);
+ uint32_t wrapy = mp_obj_get_int_truncated(args[3]);
+ uint32_t width = mp_obj_get_int_truncated(args[4]);
+ uint32_t height = mp_obj_get_int_truncated(args[5]);
+ common_hal__eve_BitmapSize(EVEHAL(args[0]), filter, wrapx, wrapy, width, height);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitmapsize_obj, 6, 6, _bitmapsize);
+
+//| def BitmapSource(self, addr: int) -> None:
+//| """Set the source address for bitmap graphics
+//|
+//| :param int addr: Bitmap start address, pixel-aligned. May be in SRAM or flash. Range 0-16777215"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmapsource(mp_obj_t self, mp_obj_t a0) {
+ uint32_t addr = mp_obj_get_int_truncated(a0);
+ common_hal__eve_BitmapSource(EVEHAL(self), addr);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bitmapsource_obj, _bitmapsource);
+
+//| def BitmapSwizzle(self, r: int, g: int, b: int, a: int) -> None:
+//| """Set the source for the r,g,b and a channels of a bitmap
+//|
+//| :param int r: red component source channel. Range 0-7
+//| :param int g: green component source channel. Range 0-7
+//| :param int b: blue component source channel. Range 0-7
+//| :param int a: alpha component source channel. Range 0-7"""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmapswizzle(size_t n_args, const mp_obj_t *args) {
+ uint32_t r = mp_obj_get_int_truncated(args[1]);
+ uint32_t g = mp_obj_get_int_truncated(args[2]);
+ uint32_t b = mp_obj_get_int_truncated(args[3]);
+ uint32_t a = mp_obj_get_int_truncated(args[4]);
+ common_hal__eve_BitmapSwizzle(EVEHAL(args[0]), r, g, b, a);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitmapswizzle_obj, 5, 5, _bitmapswizzle);
+
+//| def BitmapTransformA(self, p: int, v: int) -> None:
+//| """Set the :math:`a` component of the bitmap transform matrix
+//|
+//| :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+//| :param int v: The :math:`a` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 256
+//|
+//| The initial value is **p** = 0, **v** = 256. This represents the value 1.0.
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransforma(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t p = mp_obj_get_int_truncated(a0);
+ uint32_t v = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapTransformA(EVEHAL(self), p, v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmaptransforma_obj, _bitmaptransforma);
+
+//| def BitmapTransformB(self, p: int, v: int) -> None:
+//| """Set the :math:`b` component of the bitmap transform matrix
+//|
+//| :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+//| :param int v: The :math:`b` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 0
+//|
+//| The initial value is **p** = 0, **v** = 0. This represents the value 0.0.
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransformb(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t p = mp_obj_get_int_truncated(a0);
+ uint32_t v = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapTransformB(EVEHAL(self), p, v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmaptransformb_obj, _bitmaptransformb);
+
+//| def BitmapTransformC(self, v: int) -> None:
+//| """Set the :math:`c` component of the bitmap transform matrix
+//|
+//| :param int v: The :math:`c` component of the bitmap transform matrix, in signed 15.8 bit fixed-point form. Range 0-16777215. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransformc(mp_obj_t self, mp_obj_t a0) {
+ uint32_t v = mp_obj_get_int_truncated(a0);
+ common_hal__eve_BitmapTransformC(EVEHAL(self), v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bitmaptransformc_obj, _bitmaptransformc);
+
+//| def BitmapTransformD(self, p: int, v: int) -> None:
+//| """Set the :math:`d` component of the bitmap transform matrix
+//|
+//| :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+//| :param int v: The :math:`d` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 0
+//|
+//| The initial value is **p** = 0, **v** = 0. This represents the value 0.0.
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransformd(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t p = mp_obj_get_int_truncated(a0);
+ uint32_t v = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapTransformD(EVEHAL(self), p, v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmaptransformd_obj, _bitmaptransformd);
+
+//| def BitmapTransformE(self, p: int, v: int) -> None:
+//| """Set the :math:`e` component of the bitmap transform matrix
+//|
+//| :param int p: precision control: 0 is 8.8, 1 is 1.15. Range 0-1. The initial value is 0
+//| :param int v: The :math:`e` component of the bitmap transform matrix, in signed 8.8 or 1.15 bit fixed-point form. Range 0-131071. The initial value is 256
+//|
+//| The initial value is **p** = 0, **v** = 256. This represents the value 1.0.
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransforme(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t p = mp_obj_get_int_truncated(a0);
+ uint32_t v = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BitmapTransformE(EVEHAL(self), p, v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(bitmaptransforme_obj, _bitmaptransforme);
+
+//| def BitmapTransformF(self, v: int) -> None:
+//| """Set the :math:`f` component of the bitmap transform matrix
+//|
+//| :param int v: The :math:`f` component of the bitmap transform matrix, in signed 15.8 bit fixed-point form. Range 0-16777215. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _bitmaptransformf(mp_obj_t self, mp_obj_t a0) {
+ uint32_t v = mp_obj_get_int_truncated(a0);
+ common_hal__eve_BitmapTransformF(EVEHAL(self), v);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bitmaptransformf_obj, _bitmaptransformf);
+
+//| def BlendFunc(self, src: int, dst: int) -> None:
+//| """Set pixel arithmetic
+//|
+//| :param int src: specifies how the source blending factor is computed. One of ``ZERO``, ``ONE``, ``SRC_ALPHA``, ``DST_ALPHA``, ``ONE_MINUS_SRC_ALPHA`` or ``ONE_MINUS_DST_ALPHA``. Range 0-7. The initial value is SRC_ALPHA(2)
+//| :param int dst: specifies how the destination blending factor is computed, one of the same constants as **src**. Range 0-7. The initial value is ONE_MINUS_SRC_ALPHA(4)
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _blendfunc(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t src = mp_obj_get_int_truncated(a0);
+ uint32_t dst = mp_obj_get_int_truncated(a1);
+ common_hal__eve_BlendFunc(EVEHAL(self), src, dst);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(blendfunc_obj, _blendfunc);
+
+//| def Call(self, dest: int) -> None:
+//| """Execute a sequence of commands at another location in the display list
+//|
+//| :param int dest: display list address. Range 0-65535"""
+//| ...
+//|
+
+STATIC mp_obj_t _call(mp_obj_t self, mp_obj_t a0) {
+ uint32_t dest = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Call(EVEHAL(self), dest);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(call_obj, _call);
+
+//| def Cell(self, cell: int) -> None:
+//| """Set the bitmap cell number for the vertex2f command
+//|
+//| :param int cell: bitmap cell number. Range 0-127. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _cell(mp_obj_t self, mp_obj_t a0) {
+ uint32_t cell = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Cell(EVEHAL(self), cell);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cell_obj, _cell);
+
+//| def ClearColorA(self, alpha: int) -> None:
+//| """Set clear value for the alpha channel
+//|
+//| :param int alpha: alpha value used when the color buffer is cleared. Range 0-255. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _clearcolora(mp_obj_t self, mp_obj_t a0) {
+ uint32_t alpha = mp_obj_get_int_truncated(a0);
+ common_hal__eve_ClearColorA(EVEHAL(self), alpha);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(clearcolora_obj, _clearcolora);
+
+//| def ClearColorRGB(self, red: int, green: int, blue: int) -> None:
+//| """Set clear values for red, green and blue channels
+//|
+//| :param int red: red value used when the color buffer is cleared. Range 0-255. The initial value is 0
+//| :param int green: green value used when the color buffer is cleared. Range 0-255. The initial value is 0
+//| :param int blue: blue value used when the color buffer is cleared. Range 0-255. The initial value is 0
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _clearcolorrgb(size_t n_args, const mp_obj_t *args) {
+ uint32_t red = mp_obj_get_int_truncated(args[1]);
+ uint32_t green = mp_obj_get_int_truncated(args[2]);
+ uint32_t blue = mp_obj_get_int_truncated(args[3]);
+ common_hal__eve_ClearColorRGB(EVEHAL(args[0]), red, green, blue);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(clearcolorrgb_obj, 4, 4, _clearcolorrgb);
+
+//| def Clear(self, c: int, s: int, t: int) -> None:
+//| """Clear buffers to preset values
+//|
+//| :param int c: clear color buffer. Range 0-1
+//| :param int s: clear stencil buffer. Range 0-1
+//| :param int t: clear tag buffer. Range 0-1"""
+//| ...
+//|
+
+STATIC mp_obj_t _clear(size_t n_args, const mp_obj_t *args) {
+ uint32_t c = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 1;
+ uint32_t s = (n_args > 2) ? mp_obj_get_int_truncated(args[2]) : 1;
+ uint32_t t = (n_args > 3) ? mp_obj_get_int_truncated(args[3]) : 1;
+ common_hal__eve_Clear(EVEHAL(args[0]), c, s, t);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(clear_obj, 1, 4, _clear);
+
+//| def ClearStencil(self, s: int) -> None:
+//| """Set clear value for the stencil buffer
+//|
+//| :param int s: value used when the stencil buffer is cleared. Range 0-255. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _clearstencil(mp_obj_t self, mp_obj_t a0) {
+ uint32_t s = mp_obj_get_int_truncated(a0);
+ common_hal__eve_ClearStencil(EVEHAL(self), s);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(clearstencil_obj, _clearstencil);
+
+//| def ClearTag(self, s: int) -> None:
+//| """Set clear value for the tag buffer
+//|
+//| :param int s: value used when the tag buffer is cleared. Range 0-255. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//|
+
+STATIC mp_obj_t _cleartag(mp_obj_t self, mp_obj_t a0) {
+ uint32_t s = mp_obj_get_int_truncated(a0);
+ common_hal__eve_ClearTag(EVEHAL(self), s);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cleartag_obj, _cleartag);
+
+//| def ColorA(self, alpha: int) -> None:
+//| """Set the current color alpha
+//|
+//| :param int alpha: alpha for the current color. Range 0-255. The initial value is 255
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _colora(mp_obj_t self, mp_obj_t a0) {
+ uint32_t alpha = mp_obj_get_int_truncated(a0);
+ common_hal__eve_ColorA(EVEHAL(self), alpha);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(colora_obj, _colora);
+
+//| def ColorMask(self, r: int, g: int, b: int, a: int) -> None:
+//| """Enable and disable writing of frame buffer color components
+//|
+//| :param int r: allow updates to the frame buffer red component. Range 0-1. The initial value is 1
+//| :param int g: allow updates to the frame buffer green component. Range 0-1. The initial value is 1
+//| :param int b: allow updates to the frame buffer blue component. Range 0-1. The initial value is 1
+//| :param int a: allow updates to the frame buffer alpha component. Range 0-1. The initial value is 1
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _colormask(size_t n_args, const mp_obj_t *args) {
+ uint32_t r = mp_obj_get_int_truncated(args[1]);
+ uint32_t g = mp_obj_get_int_truncated(args[2]);
+ uint32_t b = mp_obj_get_int_truncated(args[3]);
+ uint32_t a = mp_obj_get_int_truncated(args[4]);
+ common_hal__eve_ColorMask(EVEHAL(args[0]), r, g, b, a);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(colormask_obj, 5, 5, _colormask);
+
+//| def ColorRGB(self, red: int, green: int, blue: int) -> None:
+//| """Set the drawing color
+//|
+//| :param int red: red value for the current color. Range 0-255. The initial value is 255
+//| :param int green: green for the current color. Range 0-255. The initial value is 255
+//| :param int blue: blue for the current color. Range 0-255. The initial value is 255
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _colorrgb(size_t n_args, const mp_obj_t *args) {
+ uint32_t red = mp_obj_get_int_truncated(args[1]);
+ uint32_t green = mp_obj_get_int_truncated(args[2]);
+ uint32_t blue = mp_obj_get_int_truncated(args[3]);
+ common_hal__eve_ColorRGB(EVEHAL(args[0]), red, green, blue);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(colorrgb_obj, 4, 4, _colorrgb);
+
+//| def Display(self) -> None:
+//| """End the display list"""
+//| ...
+
+STATIC mp_obj_t _display(mp_obj_t self) {
+
+ common_hal__eve_Display(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(display_obj, _display);
+
+//| def End(self) -> None:
+//| """End drawing a graphics primitive
+//|
+//| :meth:`Vertex2ii` and :meth:`Vertex2f` calls are ignored until the next :meth:`Begin`."""
+//| ...
+//|
+
+STATIC mp_obj_t _end(mp_obj_t self) {
+
+ common_hal__eve_End(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(end_obj, _end);
+
+//| def Jump(self, dest: int) -> None:
+//| """Execute commands at another location in the display list
+//|
+//| :param int dest: display list address. Range 0-65535"""
+//| ...
+//|
+
+STATIC mp_obj_t _jump(mp_obj_t self, mp_obj_t a0) {
+ uint32_t dest = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Jump(EVEHAL(self), dest);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(jump_obj, _jump);
+
+//| def Macro(self, m: int) -> None:
+//| """Execute a single command from a macro register
+//|
+//| :param int m: macro register to read. Range 0-1"""
+//| ...
+//|
+
+STATIC mp_obj_t _macro(mp_obj_t self, mp_obj_t a0) {
+ uint32_t m = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Macro(EVEHAL(self), m);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(macro_obj, _macro);
+
+//| def Nop(self) -> None:
+//| """No operation"""
+//| ...
+//|
+
+STATIC mp_obj_t _nop(mp_obj_t self) {
+
+ common_hal__eve_Nop(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(nop_obj, _nop);
+
+//| def PaletteSource(self, addr: int) -> None:
+//| """Set the base address of the palette
+//|
+//| :param int addr: Address in graphics SRAM, 2-byte aligned. Range 0-4194303. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _palettesource(mp_obj_t self, mp_obj_t a0) {
+ uint32_t addr = mp_obj_get_int_truncated(a0);
+ common_hal__eve_PaletteSource(EVEHAL(self), addr);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(palettesource_obj, _palettesource);
+
+//| def RestoreContext(self) -> None:
+//| """Restore the current graphics context from the context stack"""
+//| ...
+//|
+
+STATIC mp_obj_t _restorecontext(mp_obj_t self) {
+
+ common_hal__eve_RestoreContext(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(restorecontext_obj, _restorecontext);
+
+//| def Return(self) -> None:
+//| """Return from a previous call command"""
+//| ...
+//|
+
+STATIC mp_obj_t _return(mp_obj_t self) {
+
+ common_hal__eve_Return(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(return_obj, _return);
+
+//| def SaveContext(self) -> None:
+//| """Push the current graphics context on the context stack"""
+//| ...
+//|
+
+STATIC mp_obj_t _savecontext(mp_obj_t self) {
+
+ common_hal__eve_SaveContext(EVEHAL(self));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(savecontext_obj, _savecontext);
+
+//| def ScissorSize(self, width: int, height: int) -> None:
+//| """Set the size of the scissor clip rectangle
+//|
+//| :param int width: The width of the scissor clip rectangle, in pixels. Range 0-4095. The initial value is hsize
+//| :param int height: The height of the scissor clip rectangle, in pixels. Range 0-4095. The initial value is 2048
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _scissorsize(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t width = mp_obj_get_int_truncated(a0);
+ uint32_t height = mp_obj_get_int_truncated(a1);
+ common_hal__eve_ScissorSize(EVEHAL(self), width, height);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(scissorsize_obj, _scissorsize);
+
+//| def ScissorXY(self, x: int, y: int) -> None:
+//| """Set the top left corner of the scissor clip rectangle
+//|
+//| :param int x: The :math:`x` coordinate of the scissor clip rectangle, in pixels. Range 0-2047. The initial value is 0
+//| :param int y: The :math:`y` coordinate of the scissor clip rectangle, in pixels. Range 0-2047. The initial value is 0
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _scissorxy(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t x = mp_obj_get_int_truncated(a0);
+ uint32_t y = mp_obj_get_int_truncated(a1);
+ common_hal__eve_ScissorXY(EVEHAL(self), x, y);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(scissorxy_obj, _scissorxy);
+
+//| def StencilFunc(self, func: int, ref: int, mask: int) -> None:
+//| """Set function and reference value for stencil testing
+//|
+//| :param int func: specifies the test function, one of ``NEVER``, ``LESS``, ``LEQUAL``, ``GREATER``, ``GEQUAL``, ``EQUAL``, ``NOTEQUAL``, or ``ALWAYS``. Range 0-7. The initial value is ALWAYS(7)
+//| :param int ref: specifies the reference value for the stencil test. Range 0-255. The initial value is 0
+//| :param int mask: specifies a mask that is ANDed with the reference value and the stored stencil value. Range 0-255. The initial value is 255
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _stencilfunc(size_t n_args, const mp_obj_t *args) {
+ uint32_t func = mp_obj_get_int_truncated(args[1]);
+ uint32_t ref = mp_obj_get_int_truncated(args[2]);
+ uint32_t mask = mp_obj_get_int_truncated(args[3]);
+ common_hal__eve_StencilFunc(EVEHAL(args[0]), func, ref, mask);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stencilfunc_obj, 4, 4, _stencilfunc);
+
+//| def StencilMask(self, mask: int) -> None:
+//| """Control the writing of individual bits in the stencil planes
+//|
+//| :param int mask: the mask used to enable writing stencil bits. Range 0-255. The initial value is 255
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _stencilmask(mp_obj_t self, mp_obj_t a0) {
+ uint32_t mask = mp_obj_get_int_truncated(a0);
+ common_hal__eve_StencilMask(EVEHAL(self), mask);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(stencilmask_obj, _stencilmask);
+
+//| def StencilOp(self, sfail: int, spass: int) -> None:
+//| """Set stencil test actions
+//|
+//| :param int sfail: specifies the action to take when the stencil test fails, one of ``KEEP``, ``ZERO``, ``REPLACE``, ``INCR``, ``INCR_WRAP``, ``DECR``, ``DECR_WRAP``, and ``INVERT``. Range 0-7. The initial value is KEEP(1)
+//| :param int spass: specifies the action to take when the stencil test passes, one of the same constants as **sfail**. Range 0-7. The initial value is KEEP(1)
+//|
+//| These values are part of the graphics context and are saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _stencilop(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ uint32_t sfail = mp_obj_get_int_truncated(a0);
+ uint32_t spass = mp_obj_get_int_truncated(a1);
+ common_hal__eve_StencilOp(EVEHAL(self), sfail, spass);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(stencilop_obj, _stencilop);
+
+//| def TagMask(self, mask: int) -> None:
+//| """Control the writing of the tag buffer
+//|
+//| :param int mask: allow updates to the tag buffer. Range 0-1. The initial value is 1
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _tagmask(mp_obj_t self, mp_obj_t a0) {
+ uint32_t mask = mp_obj_get_int_truncated(a0);
+ common_hal__eve_TagMask(EVEHAL(self), mask);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(tagmask_obj, _tagmask);
+
+//| def Tag(self, s: int) -> None:
+//| """Set the current tag value
+//|
+//| :param int s: tag value. Range 0-255. The initial value is 255
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _tag(mp_obj_t self, mp_obj_t a0) {
+ uint32_t s = mp_obj_get_int_truncated(a0);
+ common_hal__eve_Tag(EVEHAL(self), s);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(tag_obj, _tag);
+
+STATIC mp_obj_t _vertexformat(mp_obj_t self, mp_obj_t a0) {
+ uint32_t frac = mp_obj_get_int_truncated(a0);
+ common_hal__eve_VertexFormat(EVEHAL(self), frac);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vertexformat_obj, _vertexformat);
+
+//| def Vertex2ii(self, x: int, y: int, handle: int, cell: int) -> None:
+//| """:param int x: x-coordinate in pixels. Range 0-511
+//| :param int y: y-coordinate in pixels. Range 0-511
+//| :param int handle: bitmap handle. Range 0-31
+//| :param int cell: cell number. Range 0-127
+//|
+//| This method is an alternative to :meth:`Vertex2f`."""
+//| ...
+//|
+
+STATIC mp_obj_t _vertex2ii(size_t n_args, const mp_obj_t *args) {
+ uint32_t x = mp_obj_get_int_truncated(args[1]);
+ uint32_t y = mp_obj_get_int_truncated(args[2]);
+ uint32_t handle = (n_args > 3) ? mp_obj_get_int_truncated(args[3]) : 0;
+ uint32_t cell = (n_args > 4) ? mp_obj_get_int_truncated(args[4]) : 0;
+ common_hal__eve_Vertex2ii(EVEHAL(args[0]), x, y, handle, cell);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vertex2ii_obj, 3, 5, _vertex2ii);
+
+#define ROM_DECLS \
+ { MP_ROM_QSTR(MP_QSTR_AlphaFunc), MP_ROM_PTR(&alphafunc_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Begin), MP_ROM_PTR(&begin_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapExtFormat), MP_ROM_PTR(&bitmapextformat_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapHandle), MP_ROM_PTR(&bitmaphandle_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapLayoutH), MP_ROM_PTR(&bitmaplayouth_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapLayout), MP_ROM_PTR(&bitmaplayout_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapSizeH), MP_ROM_PTR(&bitmapsizeh_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapSize), MP_ROM_PTR(&bitmapsize_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapSource), MP_ROM_PTR(&bitmapsource_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapSwizzle), MP_ROM_PTR(&bitmapswizzle_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformA), MP_ROM_PTR(&bitmaptransforma_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformB), MP_ROM_PTR(&bitmaptransformb_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformC), MP_ROM_PTR(&bitmaptransformc_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformD), MP_ROM_PTR(&bitmaptransformd_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformE), MP_ROM_PTR(&bitmaptransforme_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BitmapTransformF), MP_ROM_PTR(&bitmaptransformf_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_BlendFunc), MP_ROM_PTR(&blendfunc_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Call), MP_ROM_PTR(&call_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Cell), MP_ROM_PTR(&cell_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ClearColorA), MP_ROM_PTR(&clearcolora_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ClearColorRGB), MP_ROM_PTR(&clearcolorrgb_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Clear), MP_ROM_PTR(&clear_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ClearStencil), MP_ROM_PTR(&clearstencil_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ClearTag), MP_ROM_PTR(&cleartag_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ColorA), MP_ROM_PTR(&colora_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ColorMask), MP_ROM_PTR(&colormask_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ColorRGB), MP_ROM_PTR(&colorrgb_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&display_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_End), MP_ROM_PTR(&end_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Jump), MP_ROM_PTR(&jump_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_LineWidth), MP_ROM_PTR(&linewidth_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Macro), MP_ROM_PTR(&macro_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Nop), MP_ROM_PTR(&nop_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_PaletteSource), MP_ROM_PTR(&palettesource_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_PointSize), MP_ROM_PTR(&pointsize_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_RestoreContext), MP_ROM_PTR(&restorecontext_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Return), MP_ROM_PTR(&return_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_SaveContext), MP_ROM_PTR(&savecontext_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ScissorSize), MP_ROM_PTR(&scissorsize_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_ScissorXY), MP_ROM_PTR(&scissorxy_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_StencilFunc), MP_ROM_PTR(&stencilfunc_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_StencilMask), MP_ROM_PTR(&stencilmask_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_StencilOp), MP_ROM_PTR(&stencilop_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_TagMask), MP_ROM_PTR(&tagmask_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Tag), MP_ROM_PTR(&tag_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_VertexTranslateX), MP_ROM_PTR(&vertextranslatex_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_VertexTranslateY), MP_ROM_PTR(&vertextranslatey_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_VertexFormat), MP_ROM_PTR(&vertexformat_obj) }, \
+ { MP_ROM_QSTR(MP_QSTR_Vertex2ii), MP_ROM_PTR(&vertex2ii_obj) }
+
+// }
+
+// Hand-written functions {
+
+//| def Vertex2f(self, b: float) -> None:
+//| """Draw a point.
+//|
+//| :param float x: pixel x-coordinate
+//| :param float y: pixel y-coordinate"""
+//| ...
+//|
+STATIC mp_obj_t _vertex2f(mp_obj_t self, mp_obj_t a0, mp_obj_t a1) {
+ mp_float_t x = mp_obj_get_float(a0);
+ mp_float_t y = mp_obj_get_float(a1);
+ common_hal__eve_Vertex2f(EVEHAL(self), x, y);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vertex2f_obj, _vertex2f);
+
+//| def LineWidth(self, width: float) -> None:
+//| """Set the width of rasterized lines
+//|
+//| :param float width: line width in pixels. Range 0-511. The initial value is 1
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _linewidth(mp_obj_t self, mp_obj_t a0) {
+ mp_float_t width = mp_obj_get_float(a0);
+ common_hal__eve_LineWidth(EVEHAL(self), width);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(linewidth_obj, _linewidth);
+
+//| def PointSize(self, size: float) -> None:
+//| """Set the diameter of rasterized points
+//|
+//| :param float size: point diameter in pixels. Range 0-1023. The initial value is 1
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _pointsize(mp_obj_t self, mp_obj_t a0) {
+ mp_float_t size = mp_obj_get_float(a0);
+ common_hal__eve_PointSize(EVEHAL(self), size);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pointsize_obj, _pointsize);
+
+//| def VertexTranslateX(self, x: float) -> None:
+//| """Set the vertex transformation's x translation component
+//|
+//| :param float x: signed x-coordinate in pixels. Range ±4095. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+STATIC mp_obj_t _vertextranslatex(mp_obj_t self, mp_obj_t a0) {
+ mp_float_t x = mp_obj_get_float(a0);
+ common_hal__eve_VertexTranslateX(EVEHAL(self), x);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vertextranslatex_obj, _vertextranslatex);
+
+//| def VertexTranslateY(self, y: float) -> None:
+//| """Set the vertex transformation's y translation component
+//|
+//| :param float y: signed y-coordinate in pixels. Range ±4095. The initial value is 0
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+
+STATIC mp_obj_t _vertextranslatey(mp_obj_t self, mp_obj_t a0) {
+ mp_float_t y = mp_obj_get_float(a0);
+ common_hal__eve_VertexTranslateY(EVEHAL(self), y);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vertextranslatey_obj, _vertextranslatey);
+
+//| def VertexFormat(self, frac: int) -> None:
+//| """Set the precision of vertex2f coordinates
+//|
+//| :param int frac: Number of fractional bits in X,Y coordinates, 0-4. Range 0-7. The initial value is 4
+//|
+//| This value is part of the graphics context and is saved and restored by :meth:`SaveContext` and :meth:`RestoreContext`."""
+//| ...
+//|
+
+// }
+
+// Append an object x to the FIFO
+#define ADD_X(self, x) \
+ common_hal__eve_add(EVEHAL(self), sizeof(x), &(x));
+
+//| def cmd0(self, n: int) -> None:
+//| """Append the command word n to the FIFO
+//|
+//| :param int n: The command code
+//|
+//| This method is used by the ``eve`` module to efficiently add
+//| commands to the FIFO."""
+//| ...
+//|
+
+STATIC mp_obj_t _cmd0(mp_obj_t self, mp_obj_t n) {
+ uint32_t code = 0xffffff00 | mp_obj_get_int_truncated(n);
+ ADD_X(self, code);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cmd0_obj, _cmd0);
+
+//| def cmd(self, n: int, fmt: str, args: Tuple[str, ...]) -> None:
+//| """Append a command packet to the FIFO.
+//|
+//| :param int n: The command code
+//| :param str fmt: The command format `struct` layout
+//| :param args: The command's arguments
+//| :type args: tuple(str, ...)
+//|
+//| Supported format codes: h, H, i, I.
+//|
+//| This method is used by the ``eve`` module to efficiently add
+//| commands to the FIFO."""
+//| ...
+//|
+STATIC mp_obj_t _cmd(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t self = args[0];
+ mp_obj_t num = args[1];
+ mp_buffer_info_t fmt;
+ mp_get_buffer_raise(args[2], &fmt, MP_BUFFER_READ);
+ size_t len;
+ mp_obj_t *items;
+ mp_obj_tuple_get(args[3], &len, &items);
+
+ // Count how many 32-bit words required
+ size_t n = 0;
+ for (size_t i = 0; i < fmt.len; n++) {
+ switch (((char *)fmt.buf)[i]) {
+ case 'I':
+ case 'i':
+ i += 1;
+ break;
+ case 'H':
+ case 'h':
+ i += 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ uint32_t buf[16];
+ uint32_t *p = buf;
+ *p++ = 0xffffff00 | mp_obj_get_int_truncated(num);
+ mp_obj_t *a = items;
+ uint32_t lo;
+
+ for (size_t i = 0; i < fmt.len;) {
+ switch (((char *)fmt.buf)[i]) {
+ case 'I':
+ case 'i':
+ *p++ = mp_obj_get_int_truncated(*a++);
+ i += 1;
+ break;
+ case 'H':
+ case 'h':
+ lo = mp_obj_get_int_truncated(*a++) & 0xffff;
+ *p++ = lo | (mp_obj_get_int_truncated(*a++) << 16);
+ i += 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ common_hal__eve_add(EVEHAL(self), sizeof(uint32_t) * (1 + n), buf);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(cmd_obj, 4, 4, _cmd);
+
+STATIC const mp_rom_map_elem_t _EVE_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&register_obj) },
+ { MP_ROM_QSTR(MP_QSTR_cc), MP_ROM_PTR(&cc_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&flush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_Vertex2f), MP_ROM_PTR(&vertex2f_obj) },
+ { MP_ROM_QSTR(MP_QSTR_cmd), MP_ROM_PTR(&cmd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_cmd0), MP_ROM_PTR(&cmd0_obj) },
+ ROM_DECLS
+};
+STATIC MP_DEFINE_CONST_DICT(_EVE_locals_dict, _EVE_locals_dict_table);
+
+STATIC mp_obj_t _EVE_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // mp_arg_check_num(n_args, kw_args, 1, 1, false);
+ mp_obj__EVE_t *o = m_new_obj(mp_obj__EVE_t);
+ o->base.type = &_EVE_type;
+ o->_eve.n = 0;
+ o->_eve.vscale = 16;
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC const mp_obj_type_t _EVE_type = {
+ { &mp_type_type },
+ .name = MP_QSTR__EVE,
+ .make_new = _EVE_make_new,
+ .locals_dict = (void *)&_EVE_locals_dict,
+};
+
+STATIC const mp_rom_map_elem_t mp_module__eve_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__eve) },
+ { MP_ROM_QSTR(MP_QSTR__EVE), MP_OBJ_FROM_PTR(&_EVE_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module__eve_globals, mp_module__eve_globals_table);
+
+const mp_obj_module_t _eve_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module__eve_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__eve, _eve_module, CIRCUITPY__EVE);
diff --git a/circuitpython/shared-bindings/_eve/__init__.h b/circuitpython/shared-bindings/_eve/__init__.h
new file mode 100644
index 0000000..96a10f0
--- /dev/null
+++ b/circuitpython/shared-bindings/_eve/__init__.h
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 James Bowman for Excamera Labs
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS__EVE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS__EVE___INIT___H
+
+#include "shared-module/_eve/__init__.h"
+
+void common_hal__eve_flush(common_hal__eve_t *eve);
+void common_hal__eve_add(common_hal__eve_t *eve, size_t len, void *buf);
+void common_hal__eve_Vertex2f(common_hal__eve_t *eve, mp_float_t x, mp_float_t y);
+
+void common_hal__eve_AlphaFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref);
+void common_hal__eve_Begin(common_hal__eve_t *eve, uint32_t prim);
+void common_hal__eve_BitmapExtFormat(common_hal__eve_t *eve, uint32_t fmt);
+void common_hal__eve_BitmapHandle(common_hal__eve_t *eve, uint32_t handle);
+void common_hal__eve_BitmapLayoutH(common_hal__eve_t *eve, uint32_t linestride, uint32_t height);
+void common_hal__eve_BitmapLayout(common_hal__eve_t *eve, uint32_t format, uint32_t linestride, uint32_t height);
+void common_hal__eve_BitmapSizeH(common_hal__eve_t *eve, uint32_t width, uint32_t height);
+void common_hal__eve_BitmapSize(common_hal__eve_t *eve, uint32_t filter, uint32_t wrapx, uint32_t wrapy, uint32_t width, uint32_t height);
+void common_hal__eve_BitmapSource(common_hal__eve_t *eve, uint32_t addr);
+void common_hal__eve_BitmapSwizzle(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a);
+void common_hal__eve_BitmapTransformA(common_hal__eve_t *eve, uint32_t p, uint32_t v);
+void common_hal__eve_BitmapTransformB(common_hal__eve_t *eve, uint32_t p, uint32_t v);
+void common_hal__eve_BitmapTransformC(common_hal__eve_t *eve, uint32_t v);
+void common_hal__eve_BitmapTransformD(common_hal__eve_t *eve, uint32_t p, uint32_t v);
+void common_hal__eve_BitmapTransformE(common_hal__eve_t *eve, uint32_t p, uint32_t v);
+void common_hal__eve_BitmapTransformF(common_hal__eve_t *eve, uint32_t v);
+void common_hal__eve_BlendFunc(common_hal__eve_t *eve, uint32_t src, uint32_t dst);
+void common_hal__eve_Call(common_hal__eve_t *eve, uint32_t dest);
+void common_hal__eve_Cell(common_hal__eve_t *eve, uint32_t cell);
+void common_hal__eve_ClearColorA(common_hal__eve_t *eve, uint32_t alpha);
+void common_hal__eve_ClearColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue);
+void common_hal__eve_Clear(common_hal__eve_t *eve, uint32_t c, uint32_t s, uint32_t t);
+void common_hal__eve_ClearStencil(common_hal__eve_t *eve, uint32_t s);
+void common_hal__eve_ClearTag(common_hal__eve_t *eve, uint32_t s);
+void common_hal__eve_ColorA(common_hal__eve_t *eve, uint32_t alpha);
+void common_hal__eve_ColorMask(common_hal__eve_t *eve, uint32_t r, uint32_t g, uint32_t b, uint32_t a);
+void common_hal__eve_ColorRGB(common_hal__eve_t *eve, uint32_t red, uint32_t green, uint32_t blue);
+void common_hal__eve_Display(common_hal__eve_t *eve);
+void common_hal__eve_End(common_hal__eve_t *eve);
+void common_hal__eve_Jump(common_hal__eve_t *eve, uint32_t dest);
+void common_hal__eve_LineWidth(common_hal__eve_t *eve, mp_float_t width);
+void common_hal__eve_Macro(common_hal__eve_t *eve, uint32_t m);
+void common_hal__eve_Nop(common_hal__eve_t *eve);
+void common_hal__eve_PaletteSource(common_hal__eve_t *eve, uint32_t addr);
+void common_hal__eve_PointSize(common_hal__eve_t *eve, mp_float_t size);
+void common_hal__eve_RestoreContext(common_hal__eve_t *eve);
+void common_hal__eve_Return(common_hal__eve_t *eve);
+void common_hal__eve_SaveContext(common_hal__eve_t *eve);
+void common_hal__eve_ScissorSize(common_hal__eve_t *eve, uint32_t width, uint32_t height);
+void common_hal__eve_ScissorXY(common_hal__eve_t *eve, uint32_t x, uint32_t y);
+void common_hal__eve_StencilFunc(common_hal__eve_t *eve, uint32_t func, uint32_t ref, uint32_t mask);
+void common_hal__eve_StencilMask(common_hal__eve_t *eve, uint32_t mask);
+void common_hal__eve_StencilOp(common_hal__eve_t *eve, uint32_t sfail, uint32_t spass);
+void common_hal__eve_TagMask(common_hal__eve_t *eve, uint32_t mask);
+void common_hal__eve_Tag(common_hal__eve_t *eve, uint32_t s);
+void common_hal__eve_VertexTranslateX(common_hal__eve_t *eve, mp_float_t x);
+void common_hal__eve_VertexTranslateY(common_hal__eve_t *eve, mp_float_t y);
+void common_hal__eve_VertexFormat(common_hal__eve_t *eve, uint32_t frac);
+void common_hal__eve_Vertex2ii(common_hal__eve_t *eve, uint32_t x, uint32_t y, uint32_t handle, uint32_t cell);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS__EVE___INIT___H
diff --git a/circuitpython/shared-bindings/_pew/PewPew.c b/circuitpython/shared-bindings/_pew/PewPew.c
new file mode 100644
index 0000000..4015d31
--- /dev/null
+++ b/circuitpython/shared-bindings/_pew/PewPew.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Radomir Dopieralski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/gc.h"
+#include "py/mpstate.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/util.h"
+#include "PewPew.h"
+#include "common-hal/_pew/PewPew.h"
+#include "supervisor/shared/translate.h"
+
+//| class PewPew:
+//| """This is an internal module to be used by the ``pew.py`` library from
+//| https://github.com/pewpew-game/pew-pewpew-standalone-10.x to handle the
+//| LED matrix display and buttons on the ``pewpew10`` board.
+//|
+//| Usage::
+//|
+//| This singleton class is instantiated by the ``pew`` library, and
+//| used internally by it. All user-visible interactions are done through
+//| that library."""
+//|
+//| def __init__(
+//| self,
+//| buffer: ReadableBuffer,
+//| rows: List[digitalio.DigitalInOut],
+//| cols: List[digitalio.DigitalInOut],
+//| buttons: digitalio.DigitalInOut,
+//| ) -> None:
+//| """Initializes matrix scanning routines.
+//|
+//| The ``buffer`` is a 64 byte long ``bytearray`` that stores what should
+//| be displayed on the matrix. ``rows`` and ``cols`` are both lists of
+//| eight ``DigitalInputOutput`` objects that are connected to the matrix
+//| rows and columns. ``buttons`` is a ``DigitalInputOutput`` object that
+//| is connected to the common side of all buttons (the other sides of the
+//| buttons are connected to rows of the matrix)."""
+//| ...
+//|
+STATIC mp_obj_t pewpew_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_buffer, ARG_rows, ARG_cols, ARG_buttons };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_rows, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_cols, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_buttons, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args),
+ allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ size_t rows_size = 0;
+ mp_obj_t *rows;
+ mp_obj_get_array(args[ARG_rows].u_obj, &rows_size, &rows);
+
+ size_t cols_size = 0;
+ mp_obj_t *cols;
+ mp_obj_get_array(args[ARG_cols].u_obj, &cols_size, &cols);
+
+ if (bufinfo.len != rows_size * cols_size) {
+ mp_raise_ValueError(translate("Incorrect buffer size"));
+ }
+
+ for (size_t i = 0; i < rows_size; ++i) {
+ digitalio_digitalinout_obj_t *pin = mp_arg_validate_type(rows[i], &digitalio_digitalinout_type, MP_QSTR_rows);
+ if (common_hal_digitalio_digitalinout_deinited(pin)) {
+ raise_deinited_error();
+ }
+ }
+
+ for (size_t i = 0; i < cols_size; ++i) {
+ digitalio_digitalinout_obj_t *pin = mp_arg_validate_type(cols[i], &digitalio_digitalinout_type, MP_QSTR_cols);
+ if (common_hal_digitalio_digitalinout_deinited(pin)) {
+ raise_deinited_error();
+ }
+ }
+
+ digitalio_digitalinout_obj_t *buttons = mp_arg_validate_type(args[ARG_buttons].u_obj, &digitalio_digitalinout_type, MP_QSTR_buttons);
+ if (common_hal_digitalio_digitalinout_deinited(buttons)) {
+ raise_deinited_error();
+ }
+
+ pew_obj_t *pew = MP_STATE_VM(pew_singleton);
+ if (!pew) {
+ pew = m_new_obj(pew_obj_t);
+ pew->base.type = &pewpew_type;
+ pew = gc_make_long_lived(pew);
+ MP_STATE_VM(pew_singleton) = pew;
+ }
+
+ pew->buffer = bufinfo.buf;
+ pew->rows = rows;
+ pew->rows_size = rows_size;
+ pew->cols = cols;
+ pew->cols_size = cols_size;
+ pew->buttons = buttons;
+ pew->pressed = 0;
+ pew_init();
+
+ return MP_OBJ_FROM_PTR(pew);
+}
+
+
+STATIC const mp_rom_map_elem_t pewpew_locals_dict_table[] = {
+};
+STATIC MP_DEFINE_CONST_DICT(pewpew_locals_dict, pewpew_locals_dict_table);
+const mp_obj_type_t pewpew_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PewPew,
+ .make_new = pewpew_make_new,
+ .locals_dict = (mp_obj_dict_t *)&pewpew_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_pew/PewPew.h b/circuitpython/shared-bindings/_pew/PewPew.h
new file mode 100644
index 0000000..f763847
--- /dev/null
+++ b/circuitpython/shared-bindings/_pew/PewPew.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Radomir Dopieralski
+ *
+ * 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.
+ */
+
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PEW_PEWPEW_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PEW_PEWPEW_H
+
+extern const mp_obj_type_t pewpew_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PEW_PEWPEW_H
diff --git a/circuitpython/shared-bindings/_pew/__init__.c b/circuitpython/shared-bindings/_pew/__init__.c
new file mode 100644
index 0000000..e338869
--- /dev/null
+++ b/circuitpython/shared-bindings/_pew/__init__.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Radomir Dopieralski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "PewPew.h"
+#include "common-hal/_pew/PewPew.h"
+
+
+STATIC mp_obj_t get_pressed(void) {
+ pew_obj_t *pew = MP_STATE_VM(pew_singleton);
+ if (!pew) {
+ return mp_const_none;
+ }
+ uint8_t pressed = pew->pressed;
+ pew->pressed = 0;
+ return mp_obj_new_int(pressed);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_pressed_obj, get_pressed);
+
+
+STATIC mp_obj_t get_ticks(void) {
+ return mp_obj_new_int(pew_get_ticks());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_ticks_obj, get_ticks);
+
+
+//| """LED matrix driver"""
+//|
+STATIC const mp_rom_map_elem_t pew_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__pew) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_PewPew), MP_ROM_PTR(&pewpew_type)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_get_pressed), MP_ROM_PTR(&get_pressed_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_get_ticks), MP_ROM_PTR(&get_ticks_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(pew_module_globals,
+ pew_module_globals_table);
+
+const mp_obj_module_t pew_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&pew_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__pew, pew_module, CIRCUITPY_PEW);
diff --git a/circuitpython/shared-bindings/_stage/Layer.c b/circuitpython/shared-bindings/_stage/Layer.c
new file mode 100644
index 0000000..c3c0aa1
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/Layer.c
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <py/runtime.h>
+
+#include "__init__.h"
+#include "Layer.h"
+#include "supervisor/shared/translate.h"
+
+//| class Layer:
+//| """Keep information about a single layer of graphics"""
+//|
+//| def __init__(self, width: int, height: int, graphic: ReadableBuffer, palette: ReadableBuffer, grid: ReadableBuffer) -> None:
+//| """Keep internal information about a layer of graphics (either a
+//| ``Grid`` or a ``Sprite``) in a format suitable for fast rendering
+//| with the ``render()`` function.
+//|
+//| :param int width: The width of the grid in tiles, or 1 for sprites.
+//| :param int height: The height of the grid in tiles, or 1 for sprites.
+//| :param ~circuitpython_typing.ReadableBuffer graphic: The graphic data of the tiles.
+//| :param ~circuitpython_typing.ReadableBuffer palette: The color palette to be used.
+//| :param ~circuitpython_typing.ReadableBuffer grid: The contents of the grid map.
+//|
+//| This class is intended for internal use in the ``stage`` library and
+//| it shouldn't be used on its own."""
+//| ...
+//|
+STATIC mp_obj_t layer_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 4, 5, false);
+
+ layer_obj_t *self = m_new_obj(layer_obj_t);
+ self->base.type = type;
+
+ self->width = mp_obj_get_int(args[0]);
+ self->height = mp_obj_get_int(args[1]);
+ self->x = 0;
+ self->y = 0;
+ self->frame = 0;
+ self->rotation = false;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ self->graphic = bufinfo.buf;
+ if (bufinfo.len != 2048) {
+ mp_raise_ValueError(translate("graphic must be 2048 bytes long"));
+ }
+
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ self->palette = bufinfo.buf;
+ if (bufinfo.len != 32) {
+ mp_raise_ValueError(translate("palette must be 32 bytes long"));
+ }
+
+ if (n_args > 4) {
+ mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ);
+ self->map = bufinfo.buf;
+ if (bufinfo.len < (self->width * self->height) / 2) {
+ mp_raise_ValueError(translate("map buffer too small"));
+ }
+ } else {
+ self->map = NULL;
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def move(self, x: int, y: int) -> None:
+//| """Set the offset of the layer to the specified values."""
+//| ...
+//|
+STATIC mp_obj_t layer_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ layer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->x = mp_obj_get_int(x_in);
+ self->y = mp_obj_get_int(y_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_move_obj, layer_move);
+
+//| def frame(self, frame: int, rotation: int) -> None:
+//| """Set the animation frame of the sprite, and optionally rotation its
+//| graphic."""
+//| ...
+//|
+STATIC mp_obj_t layer_frame(mp_obj_t self_in, mp_obj_t frame_in,
+ mp_obj_t rotation_in) {
+ layer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->frame = mp_obj_get_int(frame_in);
+ self->rotation = mp_obj_get_int(rotation_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_frame_obj, layer_frame);
+
+
+STATIC const mp_rom_map_elem_t layer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&layer_move_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&layer_frame_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(layer_locals_dict, layer_locals_dict_table);
+
+const mp_obj_type_t mp_type_layer = {
+ { &mp_type_type },
+ .name = MP_QSTR_Layer,
+ .make_new = layer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&layer_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_stage/Layer.h b/circuitpython/shared-bindings/_stage/Layer.h
new file mode 100644
index 0000000..6d15dfb
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/Layer.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED__STAGE_LAYER_H
+#define MICROPY_INCLUDED__STAGE_LAYER_H
+
+#include "shared-module/_stage/Layer.h"
+
+extern const mp_obj_type_t mp_type_layer;
+
+#endif // MICROPY_INCLUDED__STAGE_LAYER
diff --git a/circuitpython/shared-bindings/_stage/Text.c b/circuitpython/shared-bindings/_stage/Text.c
new file mode 100644
index 0000000..d6b2217
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/Text.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <py/runtime.h>
+
+#include "__init__.h"
+#include "Text.h"
+#include "supervisor/shared/translate.h"
+
+//| class Text:
+//| """Keep information about a single grid of text"""
+//|
+//| def __init__(self, width: int, height: int, font: ReadableBuffer, palette: ReadableBuffer, chars: ReadableBuffer) -> None:
+//| """Keep internal information about a grid of text
+//| in a format suitable for fast rendering
+//| with the ``render()`` function.
+//|
+//| :param int width: The width of the grid in tiles, or 1 for sprites.
+//| :param int height: The height of the grid in tiles, or 1 for sprites.
+//| :param ~circuitpython_typing.ReadableBuffer font: The font data of the characters.
+//| :param ~circuitpython_typing.ReadableBuffer palette: The color palette to be used.
+//| :param ~circuitpython_typing.ReadableBuffer chars: The contents of the character grid.
+//|
+//| This class is intended for internal use in the ``stage`` library and
+//| it shouldn't be used on its own."""
+//| ...
+//|
+STATIC mp_obj_t text_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 5, 5, false);
+
+ text_obj_t *self = m_new_obj(text_obj_t);
+ self->base.type = type;
+
+ self->width = mp_obj_get_int(args[0]);
+ self->height = mp_obj_get_int(args[1]);
+ self->x = 0;
+ self->y = 0;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ self->font = bufinfo.buf;
+ if (bufinfo.len != 2048) {
+ mp_raise_ValueError(translate("font must be 2048 bytes long"));
+ }
+
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ self->palette = bufinfo.buf;
+ if (bufinfo.len != 32) {
+ mp_raise_ValueError(translate("palette must be 32 bytes long"));
+ }
+
+ mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ);
+ self->chars = bufinfo.buf;
+ if (bufinfo.len < self->width * self->height) {
+ mp_raise_ValueError(translate("chars buffer too small"));
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def move(self, x: int, y: int) -> None:
+//| """Set the offset of the text to the specified values."""
+//| ...
+//|
+STATIC mp_obj_t text_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
+ text_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->x = mp_obj_get_int(x_in);
+ self->y = mp_obj_get_int(y_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(text_move_obj, text_move);
+
+
+STATIC const mp_rom_map_elem_t text_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&text_move_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(text_locals_dict, text_locals_dict_table);
+
+const mp_obj_type_t mp_type_text = {
+ { &mp_type_type },
+ .name = MP_QSTR_Text,
+ .make_new = text_make_new,
+ .locals_dict = (mp_obj_dict_t *)&text_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/_stage/Text.h b/circuitpython/shared-bindings/_stage/Text.h
new file mode 100644
index 0000000..77de62a
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/Text.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED__STAGE_TEXT_H
+#define MICROPY_INCLUDED__STAGE_TEXT_H
+
+#include "shared-module/_stage/Text.h"
+
+extern const mp_obj_type_t mp_type_text;
+
+#endif // MICROPY_INCLUDED__STAGE_TEXT
diff --git a/circuitpython/shared-bindings/_stage/__init__.c b/circuitpython/shared-bindings/_stage/__init__.c
new file mode 100644
index 0000000..ebaa068
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/__init__.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "__init__.h"
+#include "py/mperrno.h"
+#include "py/runtime.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/displayio/Display.h"
+#include "shared-module/_stage/__init__.h"
+#include "shared-module/displayio/display_core.h"
+#include "Layer.h"
+#include "Text.h"
+
+//| """C-level helpers for animation of sprites on a stage
+//|
+//| The `_stage` module contains native code to speed-up the ```stage`` Library
+//| <https://github.com/python-ugame/circuitpython-stage>`_."""
+//|
+//| def render(x0: int, y0: int, x1: int, y1: int, layers: List[Layer], buffer: WriteableBuffer, display: displayio.Display, scale: int, background: int) -> None:
+//| """Render and send to the display a fragment of the screen.
+//|
+//| :param int x0: Left edge of the fragment.
+//| :param int y0: Top edge of the fragment.
+//| :param int x1: Right edge of the fragment.
+//| :param int y1: Bottom edge of the fragment.
+//| :param layers: A list of the :py:class:`~_stage.Layer` objects.
+//| :type layers: list[Layer]
+//| :param ~circuitpython_typing.WriteableBuffer buffer: A buffer to use for rendering.
+//| :param ~displayio.Display display: The display to use.
+//| :param int scale: How many times should the image be scaled up.
+//| :param int background: What color to display when nothing is there.
+//|
+//| There are also no sanity checks, outside of the basic overflow
+//| checking. The caller is responsible for making the passed parameters
+//| valid.
+//|
+//| This function is intended for internal use in the ``stage`` library
+//| and all the necessary checks are performed there."""
+//|
+STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) {
+ uint16_t x0 = mp_obj_get_int(args[0]);
+ uint16_t y0 = mp_obj_get_int(args[1]);
+ uint16_t x1 = mp_obj_get_int(args[2]);
+ uint16_t y1 = mp_obj_get_int(args[3]);
+
+ size_t layers_size = 0;
+ mp_obj_t *layers;
+ mp_obj_get_array(args[4], &layers_size, &layers);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[5], &bufinfo, MP_BUFFER_WRITE);
+ uint16_t *buffer = bufinfo.buf;
+ size_t buffer_size = bufinfo.len / 2; // 16-bit indexing
+
+ mp_obj_t native_display = mp_obj_cast_to_native_base(args[6],
+ &displayio_display_type);
+ if (!mp_obj_is_type(native_display, &displayio_display_type)) {
+ mp_raise_TypeError(translate("argument num/types mismatch"));
+ }
+ displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display);
+ uint8_t scale = mp_obj_get_int(args[7]);
+ int16_t vx = mp_obj_get_int(args[8]);
+ int16_t vy = mp_obj_get_int(args[9]);
+ uint16_t background = 0;
+
+ render_stage(x0, y0, x1, y1, vx, vy, layers, layers_size,
+ buffer, buffer_size, display, scale, background);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 10, 10, stage_render);
+
+
+STATIC const mp_rom_map_elem_t stage_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__stage) },
+ { MP_ROM_QSTR(MP_QSTR_Layer), MP_ROM_PTR(&mp_type_layer) },
+ { MP_ROM_QSTR(MP_QSTR_Text), MP_ROM_PTR(&mp_type_text) },
+ { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&stage_render_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(stage_module_globals, stage_module_globals_table);
+
+const mp_obj_module_t stage_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&stage_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__stage, stage_module, CIRCUITPY_STAGE);
diff --git a/circuitpython/shared-bindings/_stage/__init__.h b/circuitpython/shared-bindings/_stage/__init__.h
new file mode 100644
index 0000000..2df81cb
--- /dev/null
+++ b/circuitpython/shared-bindings/_stage/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Radomir Dopieralski
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED__STAGE_H
+#define MICROPY_INCLUDED__STAGE_H
+
+#include "shared-module/_stage/__init__.h"
+
+#endif // MICROPY_INCLUDED__STAGE
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/__init__.c b/circuitpython/shared-bindings/adafruit_bus_device/__init__.c
new file mode 100644
index 0000000..be2378b
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/__init__.c
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/objproperty.h"
+
+#include "shared-bindings/adafruit_bus_device/__init__.h"
+#include "shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h"
+#include "shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h"
+
+STATIC const mp_rom_map_elem_t adafruit_bus_device_i2c_device_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2c_device) },
+ { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2c_device_globals, adafruit_bus_device_i2c_device_globals_table);
+
+const mp_obj_module_t adafruit_bus_device_i2c_device_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&adafruit_bus_device_i2c_device_globals,
+};
+
+STATIC const mp_rom_map_elem_t adafruit_bus_device_spi_device_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spi_device) },
+ { MP_ROM_QSTR(MP_QSTR_SPIDevice), MP_ROM_PTR(&adafruit_bus_device_spidevice_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spi_device_globals, adafruit_bus_device_spi_device_globals_table);
+
+const mp_obj_module_t adafruit_bus_device_spi_device_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&adafruit_bus_device_spi_device_globals,
+};
+
+//| """Hardware accelerated external bus access
+//|
+//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy.
+//| For example, they manage locking the bus to prevent other concurrent access. For SPI
+//| devices, it manages the chip select and protocol changes such as mode. For I2C, it
+//| manages the device address."""
+//|
+STATIC const mp_rom_map_elem_t adafruit_bus_device_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_adafruit_bus_device) },
+ { MP_ROM_QSTR(MP_QSTR_i2c_device), MP_ROM_PTR(&adafruit_bus_device_i2c_device_module) },
+ { MP_ROM_QSTR(MP_QSTR_spi_device), MP_ROM_PTR(&adafruit_bus_device_spi_device_module) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_module_globals, adafruit_bus_device_module_globals_table);
+
+const mp_obj_module_t adafruit_bus_device_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&adafruit_bus_device_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device, adafruit_bus_device_module, CIRCUITPY_BUSDEVICE);
+MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device_dot_i2c_device, adafruit_bus_device_i2c_device_module, CIRCUITPY_BUSDEVICE);
+MP_REGISTER_MODULE(MP_QSTR_adafruit_bus_device_dot_spi_device, adafruit_bus_device_spi_device_module, CIRCUITPY_BUSDEVICE);
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/__init__.h b/circuitpython/shared-bindings/adafruit_bus_device/__init__.h
new file mode 100644
index 0000000..4a66980
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c b/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c
new file mode 100644
index 0000000..327e8e7
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// busio.I2C class.
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h"
+#include "shared-bindings/util.h"
+#include "shared-module/adafruit_bus_device/i2c_device/I2CDevice.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/runtime.h"
+#include "py/smallint.h"
+#include "supervisor/shared/translate.h"
+
+
+//| class I2CDevice:
+//| """I2C Device Manager"""
+//|
+//| def __init__(self, i2c: busio.I2C, device_address: int, probe: bool = True) -> None:
+//|
+//| """Represents a single I2C device and manages locking the bus and the device
+//| address.
+//|
+//| :param ~busio.I2C i2c: The I2C bus the device is on
+//| :param int device_address: The 7 bit device address
+//| :param bool probe: Probe for the device upon object creation, default is true
+//|
+//| Example::
+//|
+//| import busio
+//| from board import *
+//| from adafruit_bus_device.i2c_device import I2CDevice
+//| with busio.I2C(SCL, SDA) as i2c:
+//| device = I2CDevice(i2c, 0x70)
+//| bytes_read = bytearray(4)
+//| with device:
+//| device.readinto(bytes_read)
+//| # A second transaction
+//| with device:
+//| device.write(bytes_read)
+//| """
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ adafruit_bus_device_i2cdevice_obj_t *self = m_new_obj(adafruit_bus_device_i2cdevice_obj_t);
+ self->base.type = &adafruit_bus_device_i2cdevice_type;
+ enum { ARG_i2c, ARG_device_address, ARG_probe };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_probe, MP_ARG_BOOL, {.u_bool = true} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t *i2c = args[ARG_i2c].u_obj;
+
+ common_hal_adafruit_bus_device_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int);
+ if (args[ARG_probe].u_bool == true) {
+ common_hal_adafruit_bus_device_i2cdevice_probe_for_device(self);
+ }
+
+ return (mp_obj_t)self;
+}
+
+//| def __enter__(self) -> I2CDevice:
+//| """Context manager entry to lock bus."""
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___enter__(mp_obj_t self_in) {
+ adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_adafruit_bus_device_i2cdevice_lock(self);
+ return self;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_i2cdevice___enter___obj, adafruit_bus_device_i2cdevice_obj___enter__);
+
+//| def __exit__(self) -> None:
+//| """Automatically unlocks the bus on exit."""
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ common_hal_adafruit_bus_device_i2cdevice_unlock(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_i2cdevice___exit___obj, 4, 4, adafruit_bus_device_i2cdevice_obj___exit__);
+
+//| import sys
+//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Read into ``buffer`` from the device.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed.
+//| The number of bytes read will be the length of ``buffer[start:end]``.
+//|
+//| :param WriteableBuffer buffer: read bytes into this buffer
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+
+ adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t dest[8];
+ uint8_t num_kws = 1;
+
+ mp_load_method(self->i2c, MP_QSTR_readfrom_into, dest);
+ dest[2] = MP_OBJ_NEW_SMALL_INT(self->device_address);
+ dest[3] = args[ARG_buffer].u_obj;
+ // dest[4] = mp_obj_new_str("start", 5);
+ dest[4] = MP_OBJ_NEW_QSTR(MP_QSTR_start);
+ dest[5] = MP_OBJ_NEW_SMALL_INT(args[ARG_start].u_int);
+ if (args[ARG_end].u_int != INT_MAX) {
+ dest[6] = MP_OBJ_NEW_QSTR(MP_QSTR_end);
+ dest[7] = MP_OBJ_NEW_SMALL_INT(args[ARG_end].u_int);
+ num_kws++;
+ }
+ mp_call_method_n_kw(2, num_kws, dest);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_readinto_obj, 1, adafruit_bus_device_i2cdevice_readinto);
+
+//| import sys
+//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``buffer`` to the device, then transmit a stop bit.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``buffer[start:end]``.
+//|
+//| :param ReadableBuffer buffer: write out bytes from this buffer
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t dest[8];
+ uint8_t num_kws = 1;
+
+ mp_load_method(self->i2c, MP_QSTR_writeto, dest);
+ dest[2] = MP_OBJ_NEW_SMALL_INT(self->device_address);
+ dest[3] = args[ARG_buffer].u_obj;
+ dest[4] = MP_OBJ_NEW_QSTR(MP_QSTR_start);
+ dest[5] = MP_OBJ_NEW_SMALL_INT(args[ARG_start].u_int);
+ if (args[ARG_end].u_int != INT_MAX) {
+ dest[6] = MP_OBJ_NEW_QSTR(MP_QSTR_end);
+ dest[7] = MP_OBJ_NEW_SMALL_INT(args[ARG_end].u_int);
+ num_kws++;
+ }
+
+ mp_call_method_n_kw(2, num_kws, dest);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_obj, 1, adafruit_bus_device_i2cdevice_write);
+
+
+//| import sys
+//| def write_then_readinto(self, out_buffer: ReadableBuffer, in_buffer: WriteableBuffer, *, out_start: int = 0, out_end: int = sys.maxsize, in_start: int = 0, in_end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``out_buffer`` to the device, then immediately
+//| reads into ``in_buffer`` from the device.
+//|
+//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
+//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``.
+//|
+//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
+//| as if ``in_buffer[in_start:in_end]`` were passed,
+//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
+//|
+//| :param ReadableBuffer out_buffer: write out bytes from this buffer
+//| :param WriteableBuffer in_buffer: read bytes into this buffer
+//| :param int out_start: beginning of ``out_buffer`` slice
+//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
+//| :param int in_start: beginning of ``in_buffer`` slice
+//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t dest[13];
+ uint8_t num_kws = 2;
+ uint8_t index = 2;
+
+ mp_load_method(self->i2c, MP_QSTR_writeto_then_readfrom, dest);
+ dest[index++] = MP_OBJ_NEW_SMALL_INT(self->device_address);
+ dest[index++] = args[ARG_out_buffer].u_obj;
+ dest[index++] = args[ARG_in_buffer].u_obj;
+ dest[index++] = MP_OBJ_NEW_QSTR(MP_QSTR_out_start);
+ dest[index++] = MP_OBJ_NEW_SMALL_INT(args[ARG_out_start].u_int);
+ if (args[ARG_out_end].u_int != INT_MAX) {
+ dest[index++] = MP_OBJ_NEW_QSTR(MP_QSTR_out_end);
+ dest[index++] = MP_OBJ_NEW_SMALL_INT(args[ARG_out_end].u_int);
+ num_kws++;
+ }
+ dest[index++] = MP_OBJ_NEW_QSTR(MP_QSTR_in_start);
+ dest[index++] = MP_OBJ_NEW_SMALL_INT(args[ARG_in_start].u_int);
+ if (args[ARG_in_end].u_int != INT_MAX) {
+ dest[index++] = MP_OBJ_NEW_QSTR(MP_QSTR_in_end);
+ dest[index++] = MP_OBJ_NEW_SMALL_INT(args[ARG_in_end].u_int);
+ num_kws++;
+ }
+
+ mp_call_method_n_kw(3, num_kws, dest);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_then_readinto_obj, 1, adafruit_bus_device_i2cdevice_write_then_readinto);
+
+STATIC const mp_rom_map_elem_t adafruit_bus_device_i2cdevice_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_then_readinto_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2cdevice_locals_dict, adafruit_bus_device_i2cdevice_locals_dict_table);
+
+const mp_obj_type_t adafruit_bus_device_i2cdevice_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2CDevice,
+ .make_new = adafruit_bus_device_i2cdevice_make_new,
+ .locals_dict = (mp_obj_dict_t *)&adafruit_bus_device_i2cdevice_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h b/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h
new file mode 100644
index 0000000..71c169a
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * 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.
+ */
+
+// Machine is the HAL for low-level, hardware accelerated functions. It is not
+// meant to simplify APIs, its only meant to unify them so that other modules
+// do not require port specific logic.
+//
+// This file includes externs for all functions a port should implement to
+// support the machine module.
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H
+
+#include "py/obj.h"
+
+#include "shared-module/adafruit_bus_device/i2c_device/I2CDevice.h"
+// #include "shared-bindings/busio/I2C.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t adafruit_bus_device_i2cdevice_type;
+
+// Initializes the hardware peripheral.
+extern void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t *i2c, uint8_t device_address);
+extern void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self);
+extern void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevice_obj_t *self);
+extern void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c b/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c
new file mode 100644
index 0000000..2c5708b
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h"
+#include "shared-bindings/util.h"
+#include "shared-module/adafruit_bus_device/spi_device/SPIDevice.h"
+#include "common-hal/digitalio/DigitalInOut.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+
+//| class SPIDevice:
+//| """SPI Device Manager"""
+//|
+//| def __init__(self, spi: busio.SPI, chip_select: microcontroller.Pin, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, extra_clocks : int = 0) -> None:
+//|
+//| """
+//| Represents a single SPI device and manages locking the bus and the device address.
+//|
+//| :param ~busio.SPI spi: The SPI bus the device is on
+//| :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the DigitalInOut API.
+//| :param bool cs_active_value: Set to true if your device requires CS to be active high. Defaults to false.
+//| :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high. (Used for SD cards.)
+//|
+//| Example::
+//|
+//| import busio
+//| import digitalio
+//| from board import *
+//| from adafruit_bus_device.spi_device import SPIDevice
+//| with busio.SPI(SCK, MOSI, MISO) as spi_bus:
+//| cs = digitalio.DigitalInOut(D10)
+//| device = SPIDevice(spi_bus, cs)
+//| bytes_read = bytearray(4)
+//| # The object assigned to spi in the with statements below
+//| # is the original spi_bus object. We are using the busio.SPI
+//| # operations busio.SPI.readinto() and busio.SPI.write().
+//| with device as spi:
+//| spi.readinto(bytes_read)
+//| # A second transaction
+//| with device as spi:
+//| spi.write(bytes_read)"""
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ adafruit_bus_device_spidevice_obj_t *self = m_new_obj(adafruit_bus_device_spidevice_obj_t);
+ self->base.type = &adafruit_bus_device_spidevice_type;
+ enum { ARG_spi, ARG_chip_select, ARG_cs_active_value, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_chip_select, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_cs_active_value, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_extra_clocks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ busio_spi_obj_t *spi = args[ARG_spi].u_obj;
+
+ common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_cs_active_value].u_bool, args[ARG_baudrate].u_int, args[ARG_polarity].u_int,
+ args[ARG_phase].u_int, args[ARG_extra_clocks].u_int);
+
+ if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) {
+ digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj),
+ true, DRIVE_MODE_PUSH_PULL);
+ if (result == DIGITALINOUT_INPUT_ONLY) {
+ mp_raise_NotImplementedError(translate("Pin is input only"));
+ }
+ }
+
+ return (mp_obj_t)self;
+}
+
+//| def __enter__(self) -> busio.SPI:
+//| """Starts a SPI transaction by configuring the SPI and asserting chip select."""
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_spidevice_obj___enter__(mp_obj_t self_in) {
+ adafruit_bus_device_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_adafruit_bus_device_spidevice_enter(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_spidevice___enter___obj, adafruit_bus_device_spidevice_obj___enter__);
+
+
+//| def __exit__(self) -> None:
+//| """Ends a SPI transaction by deasserting chip select. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t adafruit_bus_device_spidevice_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ common_hal_adafruit_bus_device_spidevice_exit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_spidevice___exit___obj, 4, 4, adafruit_bus_device_spidevice_obj___exit__);
+
+STATIC const mp_rom_map_elem_t adafruit_bus_device_spidevice_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_spidevice___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_spidevice___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spidevice_locals_dict, adafruit_bus_device_spidevice_locals_dict_table);
+
+const mp_obj_type_t adafruit_bus_device_spidevice_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPIDevice,
+ .make_new = adafruit_bus_device_spidevice_make_new,
+ .locals_dict = (mp_obj_dict_t *)&adafruit_bus_device_spidevice_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h b/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h
new file mode 100644
index 0000000..b92a5eb
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Mark Komus
+ *
+ * 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.
+ */
+
+// Machine is the HAL for low-level, hardware accelerated functions. It is not
+// meant to simplify APIs, its only meant to unify them so that other modules
+// do not require port specific logic.
+//
+// This file includes externs for all functions a port should implement to
+// support the machine module.
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H
+
+#include "py/obj.h"
+
+#include "shared-module/adafruit_bus_device/spi_device/SPIDevice.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t adafruit_bus_device_spidevice_type;
+
+// Initializes the hardware peripheral.
+extern void common_hal_adafruit_bus_device_spidevice_construct(adafruit_bus_device_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs,
+ bool cs_active_value, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks);
+extern mp_obj_t common_hal_adafruit_bus_device_spidevice_enter(adafruit_bus_device_spidevice_obj_t *self);
+extern void common_hal_adafruit_bus_device_spidevice_exit(adafruit_bus_device_spidevice_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H
diff --git a/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.c b/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.c
new file mode 100644
index 0000000..d9436ea
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.c
@@ -0,0 +1,377 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Rose Hooper
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objarray.h"
+#include "py/objtype.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/gc.h"
+
+#include <string.h>
+
+#include "shared-bindings/adafruit_pixelbuf/PixelBuf.h"
+#include "shared-module/adafruit_pixelbuf/PixelBuf.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+
+#ifdef CIRCUITPY_ULAB
+#include "extmod/ulab/code/ndarray.h"
+#endif
+
+static void parse_byteorder(mp_obj_t byteorder_obj, pixelbuf_byteorder_details_t *parsed);
+
+//| class PixelBuf:
+//| """A fast RGB[W] pixel buffer for LED and similar devices."""
+//|
+//| def __init__(self, size: int, *, byteorder: str = "BGR", brightness: float = 0, auto_write: bool = False, header: ReadableBuffer = b"", trailer: ReadableBuffer = b"") -> None:
+//| """Create a PixelBuf object of the specified size, byteorder, and bits per pixel.
+//|
+//| When brightness is less than 1.0, a second buffer will be used to store the color values
+//| before they are adjusted for brightness.
+//|
+//| When ``P`` (PWM duration) is present as the 4th character of the byteorder
+//| string, the 4th value in the tuple/list for a pixel is the individual pixel
+//| brightness (0.0-1.0) and will enable a Dotstar compatible 1st byte for each
+//| pixel.
+//|
+//| :param int size: Number of pixels
+//| :param str byteorder: Byte order string (such as "RGB", "RGBW" or "PBGR")
+//| :param float brightness: Brightness (0 to 1.0, default 1.0)
+//| :param bool auto_write: Whether to automatically write pixels (Default False)
+//| :param ~circuitpython_typing.ReadableBuffer header: Sequence of bytes to always send before pixel values.
+//| :param ~circuitpython_typing.ReadableBuffer trailer: Sequence of bytes to always send after pixel values."""
+//| ...
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_size, ARG_byteorder, ARG_brightness, ARG_auto_write, ARG_header, ARG_trailer };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_size, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_byteorder, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_BGR) } },
+ { MP_QSTR_brightness, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ { MP_QSTR_auto_write, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_header, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ { MP_QSTR_trailer, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ pixelbuf_byteorder_details_t byteorder_details;
+
+ parse_byteorder(args[ARG_byteorder].u_obj, &byteorder_details);
+
+ mp_buffer_info_t header_bufinfo;
+ mp_buffer_info_t trailer_bufinfo;
+
+ if (!mp_get_buffer(args[ARG_header].u_obj, &header_bufinfo, MP_BUFFER_READ)) {
+ header_bufinfo.buf = NULL;
+ header_bufinfo.len = 0;
+ }
+ if (!mp_get_buffer(args[ARG_trailer].u_obj, &trailer_bufinfo, MP_BUFFER_READ)) {
+ trailer_bufinfo.buf = NULL;
+ trailer_bufinfo.len = 0;
+ }
+
+ float brightness = 1.0;
+ if (args[ARG_brightness].u_obj != mp_const_none) {
+ brightness = mp_obj_get_float(args[ARG_brightness].u_obj);
+ if (brightness < 0) {
+ brightness = 0;
+ } else if (brightness > 1) {
+ brightness = 1;
+ }
+ }
+
+ // Validation complete, allocate and populate object.
+ pixelbuf_pixelbuf_obj_t *self = m_new_obj(pixelbuf_pixelbuf_obj_t);
+ self->base.type = &pixelbuf_pixelbuf_type;
+ common_hal_adafruit_pixelbuf_pixelbuf_construct(self, args[ARG_size].u_int,
+ &byteorder_details, brightness, args[ARG_auto_write].u_bool, header_bufinfo.buf,
+ header_bufinfo.len, trailer_bufinfo.buf, trailer_bufinfo.len);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+static void parse_byteorder(mp_obj_t byteorder_obj, pixelbuf_byteorder_details_t *parsed) {
+ if (!mp_obj_is_str(byteorder_obj)) {
+ mp_raise_TypeError(translate("byteorder is not a string"));
+ }
+
+ size_t bo_len;
+ const char *byteorder = mp_obj_str_get_data(byteorder_obj, &bo_len);
+ if (bo_len < 3 || bo_len > 4) {
+ mp_raise_ValueError(translate("Invalid byteorder string"));
+ }
+ parsed->order_string = byteorder_obj;
+
+ parsed->bpp = bo_len;
+ char *dotstar = strchr(byteorder, 'P');
+ char *r = strchr(byteorder, 'R');
+ char *g = strchr(byteorder, 'G');
+ char *b = strchr(byteorder, 'B');
+ char *w = strchr(byteorder, 'W');
+ int num_chars = (dotstar ? 1 : 0) + (w ? 1 : 0) + (r ? 1 : 0) + (g ? 1 : 0) + (b ? 1 : 0);
+ if ((num_chars < parsed->bpp) || !(r && b && g)) {
+ mp_raise_ValueError(translate("Invalid byteorder string"));
+ }
+ parsed->is_dotstar = dotstar ? true : false;
+ parsed->has_white = w ? true : false;
+ parsed->byteorder.r = r - byteorder;
+ parsed->byteorder.g = g - byteorder;
+ parsed->byteorder.b = b - byteorder;
+ parsed->byteorder.w = w ? w - byteorder : 0;
+ // The dotstar brightness byte is always first (as it goes with the pixel start bits)
+ if (dotstar && byteorder[0] != 'P') {
+ mp_raise_ValueError(translate("Invalid byteorder string"));
+ }
+ if (parsed->has_white && parsed->is_dotstar) {
+ mp_raise_ValueError(translate("Invalid byteorder string"));
+ }
+}
+
+//| bpp: int
+//| """The number of bytes per pixel in the buffer (read-only)"""
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_bpp(mp_obj_t self_in) {
+ return MP_OBJ_NEW_SMALL_INT(common_hal_adafruit_pixelbuf_pixelbuf_get_bpp(self_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_get_bpp_obj, pixelbuf_pixelbuf_obj_get_bpp);
+
+MP_PROPERTY_GETTER(pixelbuf_pixelbuf_bpp_obj,
+ (mp_obj_t)&pixelbuf_pixelbuf_get_bpp_obj);
+
+
+//| brightness: float
+//| """Float value between 0 and 1. Output brightness.
+//|
+//| When brightness is less than 1.0, a second buffer will be used to store the color values
+//| before they are adjusted for brightness."""
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_brightness(mp_obj_t self_in) {
+ return mp_obj_new_float(common_hal_adafruit_pixelbuf_pixelbuf_get_brightness(self_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_get_brightness_obj, pixelbuf_pixelbuf_obj_get_brightness);
+
+
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_set_brightness(mp_obj_t self_in, mp_obj_t value) {
+ mp_float_t brightness = mp_obj_get_float(value);
+ if (brightness > 1) {
+ brightness = 1;
+ } else if (brightness < 0) {
+ brightness = 0;
+ }
+ common_hal_adafruit_pixelbuf_pixelbuf_set_brightness(self_in, brightness);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(pixelbuf_pixelbuf_set_brightness_obj, pixelbuf_pixelbuf_obj_set_brightness);
+
+MP_PROPERTY_GETSET(pixelbuf_pixelbuf_brightness_obj,
+ (mp_obj_t)&pixelbuf_pixelbuf_get_brightness_obj,
+ (mp_obj_t)&pixelbuf_pixelbuf_set_brightness_obj);
+
+//| auto_write: bool
+//| """Whether to automatically write the pixels after each update."""
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_auto_write(mp_obj_t self_in) {
+ return mp_obj_new_bool(common_hal_adafruit_pixelbuf_pixelbuf_get_auto_write(self_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_get_auto_write_obj, pixelbuf_pixelbuf_obj_get_auto_write);
+
+
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_set_auto_write(mp_obj_t self_in, mp_obj_t value) {
+ common_hal_adafruit_pixelbuf_pixelbuf_set_auto_write(self_in, mp_obj_is_true(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(pixelbuf_pixelbuf_set_auto_write_obj, pixelbuf_pixelbuf_obj_set_auto_write);
+
+MP_PROPERTY_GETSET(pixelbuf_pixelbuf_auto_write_obj,
+ (mp_obj_t)&pixelbuf_pixelbuf_get_auto_write_obj,
+ (mp_obj_t)&pixelbuf_pixelbuf_set_auto_write_obj);
+
+//| byteorder: str
+//| """byteorder string for the buffer (read-only)"""
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_byteorder(mp_obj_t self_in) {
+ return common_hal_adafruit_pixelbuf_pixelbuf_get_byteorder_string(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_get_byteorder_str, pixelbuf_pixelbuf_obj_get_byteorder);
+
+MP_PROPERTY_GETTER(pixelbuf_pixelbuf_byteorder_str,
+ (mp_obj_t)&pixelbuf_pixelbuf_get_byteorder_str);
+
+STATIC mp_obj_t pixelbuf_pixelbuf_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_const_true;
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(common_hal_adafruit_pixelbuf_pixelbuf_get_len(self_in));
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def show(self) -> None:
+//| """Transmits the color data to the pixels so that they are shown. This is done automatically
+//| when `auto_write` is True."""
+//| ...
+//|
+
+STATIC mp_obj_t pixelbuf_pixelbuf_show(mp_obj_t self_in) {
+ common_hal_adafruit_pixelbuf_pixelbuf_show(self_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_show_obj, pixelbuf_pixelbuf_show);
+
+//| def fill(self, color: Union[int, Tuple[int, int, int], Tuple[int, int, int, float]]) -> None:
+//| """Fills the given pixelbuf with the given color."""
+//| ...
+//|
+
+STATIC mp_obj_t pixelbuf_pixelbuf_fill(mp_obj_t self_in, mp_obj_t value) {
+ common_hal_adafruit_pixelbuf_pixelbuf_fill(self_in, value);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(pixelbuf_pixelbuf_fill_obj, pixelbuf_pixelbuf_fill);
+
+//| @overload
+//| def __getitem__(self, index: slice) -> Union[Tuple[Tuple[int, int, int], ...], Tuple[Tuple[int, int, int, float], ...]]: ...
+//| @overload
+//| def __getitem__(self, index: int) -> Union[Tuple[int, int, int], Tuple[int, int, int, float]]:
+//| """Returns the pixel value at the given index as a tuple of (Red, Green, Blue[, White]) values
+//| between 0 and 255. When in PWM (DotStar) mode, the 4th tuple value is a float of the pixel
+//| intensity from 0-1.0."""
+//| ...
+//|
+//| @overload
+//| def __setitem__(self, index: slice, value: Tuple[Union[int, Tuple[float, ...], List[float]], ...]) -> None: ...
+//| @overload
+//| def __setitem__(self, index: slice, value: List[Union[int, Tuple[float, ...], List[float]]]) -> None: ...
+//| @overload
+//| def __setitem__(self, index: int, value: Union[int, Tuple[float, ...], List[float]]) -> None:
+//| """Sets the pixel value at the given index. Value can either be a tuple or integer. Tuples are
+//| The individual (Red, Green, Blue[, White]) values between 0 and 255. If given an integer, the
+//| red, green and blue values are packed into the lower three bytes (0xRRGGBB).
+//| For RGBW byteorders, if given only RGB values either as an int or as a tuple, the white value
+//| is used instead when the red, green, and blue values are the same."""
+//| ...
+//|
+STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
+ if (value == MP_OBJ_NULL) {
+ // delete item
+ // slice deletion
+ return MP_OBJ_NULL; // op not supported
+ }
+
+ if (0) {
+ #if MICROPY_PY_BUILTINS_SLICE
+ } else if (mp_obj_is_type(index_in, &mp_type_slice)) {
+ mp_bound_slice_t slice;
+
+ size_t length = common_hal_adafruit_pixelbuf_pixelbuf_get_len(self_in);
+ mp_seq_get_fast_slice_indexes(length, index_in, &slice);
+ static mp_obj_tuple_t flat_item_tuple = {
+ .base = {&mp_type_tuple},
+ .len = 0,
+ .items = {
+ mp_const_none,
+ mp_const_none,
+ mp_const_none,
+ mp_const_none,
+ }
+ };
+
+ size_t slice_len;
+ if (slice.step > 0) {
+ slice_len = slice.stop - slice.start;
+ } else {
+ slice_len = 1 + slice.start - slice.stop;
+ }
+ if (slice.step > 1 || slice.step < -1) {
+ size_t step = slice.step > 0 ? slice.step : slice.step * -1;
+ slice_len = (slice_len / step) + (slice_len % step ? 1 : 0);
+ }
+
+ if (value == MP_OBJ_SENTINEL) { // Get
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(slice_len, NULL));
+ for (uint i = 0; i < slice_len; i++) {
+ t->items[i] = common_hal_adafruit_pixelbuf_pixelbuf_get_pixel(self_in, i * slice.step + slice.start);
+ }
+ return MP_OBJ_FROM_PTR(t);
+ } else { // Set
+ #if MICROPY_PY_ARRAY_SLICE_ASSIGN
+
+ size_t num_items = mp_obj_get_int(mp_obj_len(value));
+
+ if (num_items != slice_len && num_items != (slice_len * common_hal_adafruit_pixelbuf_pixelbuf_get_bpp(self_in))) {
+ mp_raise_ValueError_varg(translate("Unmatched number of items on RHS (expected %d, got %d)."), slice_len, num_items);
+ }
+ common_hal_adafruit_pixelbuf_pixelbuf_set_pixels(self_in, slice.start, slice.step, slice_len, value,
+ num_items != slice_len ? &flat_item_tuple : mp_const_none);
+ return mp_const_none;
+ #else
+ return MP_OBJ_NULL; // op not supported
+ #endif
+ }
+ #endif
+ } else { // Single index rather than slice.
+ size_t length = common_hal_adafruit_pixelbuf_pixelbuf_get_len(self_in);
+ size_t index = mp_get_index(mp_obj_get_type(self_in), length, index_in, false);
+
+ if (value == MP_OBJ_SENTINEL) { // Get
+ return common_hal_adafruit_pixelbuf_pixelbuf_get_pixel(self_in, index);
+ } else { // Store
+ common_hal_adafruit_pixelbuf_pixelbuf_set_pixel(self_in, index, value);
+ return mp_const_none;
+ }
+ }
+}
+
+STATIC const mp_rom_map_elem_t pixelbuf_pixelbuf_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_auto_write), MP_ROM_PTR(&pixelbuf_pixelbuf_auto_write_obj)},
+ { MP_ROM_QSTR(MP_QSTR_bpp), MP_ROM_PTR(&pixelbuf_pixelbuf_bpp_obj)},
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&pixelbuf_pixelbuf_brightness_obj)},
+ { MP_ROM_QSTR(MP_QSTR_byteorder), MP_ROM_PTR(&pixelbuf_pixelbuf_byteorder_str)},
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&pixelbuf_pixelbuf_show_obj)},
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&pixelbuf_pixelbuf_fill_obj)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(pixelbuf_pixelbuf_locals_dict, pixelbuf_pixelbuf_locals_dict_table);
+
+
+const mp_obj_type_t pixelbuf_pixelbuf_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PixelBuf,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .locals_dict = (mp_obj_t)&pixelbuf_pixelbuf_locals_dict,
+ .make_new = pixelbuf_pixelbuf_make_new,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = pixelbuf_pixelbuf_subscr,
+ .unary_op = pixelbuf_pixelbuf_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ ),
+};
diff --git a/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.h b/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.h
new file mode 100644
index 0000000..7ae3d6a
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_pixelbuf/PixelBuf.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Rose Hooper
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef CP_SHARED_BINDINGS_PIXELBUF_PIXELBUF_H
+#define CP_SHARED_BINDINGS_PIXELBUF_PIXELBUF_H
+
+#include "shared-module/adafruit_pixelbuf/PixelBuf.h"
+
+extern const mp_obj_type_t pixelbuf_pixelbuf_type;
+
+void common_hal_adafruit_pixelbuf_pixelbuf_construct(pixelbuf_pixelbuf_obj_t *self, size_t n,
+ pixelbuf_byteorder_details_t *byteorder, mp_float_t brightness, bool auto_write, uint8_t *header,
+ size_t header_len, uint8_t *trailer, size_t trailer_len);
+
+// These take mp_obj_t because they are called on subclasses of PixelBuf.
+uint8_t common_hal_adafruit_pixelbuf_pixelbuf_get_bpp(mp_obj_t self);
+mp_float_t common_hal_adafruit_pixelbuf_pixelbuf_get_brightness(mp_obj_t self);
+void common_hal_adafruit_pixelbuf_pixelbuf_set_brightness(mp_obj_t self, mp_float_t brightness);
+bool common_hal_adafruit_pixelbuf_pixelbuf_get_auto_write(mp_obj_t self);
+void common_hal_adafruit_pixelbuf_pixelbuf_set_auto_write(mp_obj_t self, bool auto_write);
+size_t common_hal_adafruit_pixelbuf_pixelbuf_get_len(mp_obj_t self_in);
+mp_obj_t common_hal_adafruit_pixelbuf_pixelbuf_get_byteorder_string(mp_obj_t self);
+void common_hal_adafruit_pixelbuf_pixelbuf_fill(mp_obj_t self, mp_obj_t item);
+void common_hal_adafruit_pixelbuf_pixelbuf_show(mp_obj_t self);
+mp_obj_t common_hal_adafruit_pixelbuf_pixelbuf_get_pixel(mp_obj_t self, size_t index);
+void common_hal_adafruit_pixelbuf_pixelbuf_set_pixel(mp_obj_t self, size_t index, mp_obj_t item);
+void common_hal_adafruit_pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t *values, mp_obj_tuple_t *flatten_to);
+
+#endif // CP_SHARED_BINDINGS_PIXELBUF_PIXELBUF_H
diff --git a/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.c b/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.c
new file mode 100644
index 0000000..7b8d0da
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Rose Hooper
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "py/objproperty.h"
+
+#include "shared-bindings/adafruit_pixelbuf/__init__.h"
+#include "shared-bindings/adafruit_pixelbuf/PixelBuf.h"
+
+
+//| """A fast RGB(W) pixel buffer library for like NeoPixel and DotStar
+//|
+//| The `adafruit_pixelbuf` module provides the :py:class:`PixelBuf` class to accelerate
+//| RGB(W) strip/matrix manipulation, such as DotStar and Neopixel.
+//|
+//| Also available as ``_pixelbuf``. This usage has been deprecated.
+//|
+//| Byteorders are configured with strings, such as "RGB" or "RGBD"."""
+// TODO: Pull in docs from adafruit_pixelbuf.
+
+STATIC const mp_rom_map_elem_t pixelbuf_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_adafruit_pixelbuf) },
+ { MP_ROM_QSTR(MP_QSTR_PixelBuf), MP_ROM_PTR(&pixelbuf_pixelbuf_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pixelbuf_module_globals, pixelbuf_module_globals_table);
+
+const mp_obj_module_t pixelbuf_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&pixelbuf_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_adafruit_pixelbuf, pixelbuf_module, CIRCUITPY_PIXELBUF);
diff --git a/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.h b/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.h
new file mode 100644
index 0000000..9a84bc6
--- /dev/null
+++ b/circuitpython/shared-bindings/adafruit_pixelbuf/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Rose Hooper
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef CP_SHARED_BINDINGS_PIXELBUF_INIT_H
+#define CP_SHARED_BINDINGS_PIXELBUF_INIT_H
+
+#endif // CP_SHARED_BINDINGS_PIXELBUF_INIT_H
diff --git a/circuitpython/shared-bindings/aesio/__init__.c b/circuitpython/shared-bindings/aesio/__init__.c
new file mode 100644
index 0000000..716d203
--- /dev/null
+++ b/circuitpython/shared-bindings/aesio/__init__.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "__init__.h"
+
+//| """AES encryption routines
+//|
+//| The `AES` module contains classes used to implement encryption
+//| and decryption. It aims to be low overhead in terms of memory."""
+
+
+STATIC const mp_obj_tuple_t mp_aes_key_size_obj = {
+ {&mp_type_tuple},
+ 3,
+ {
+ MP_OBJ_NEW_SMALL_INT(16),
+ MP_OBJ_NEW_SMALL_INT(24),
+ MP_OBJ_NEW_SMALL_INT(32),
+ }
+};
+
+STATIC const mp_rom_map_elem_t aesio_module_globals_table[] = {
+ {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_aesio)},
+ {MP_ROM_QSTR(MP_QSTR_AES), MP_ROM_PTR(&aesio_aes_type) },
+ {MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(AES_MODE_ECB)},
+ {MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(AES_MODE_CBC)},
+ {MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(AES_MODE_CTR)},
+ {MP_ROM_QSTR(MP_QSTR_block_size), MP_ROM_INT(AES_BLOCKLEN)},
+ {MP_ROM_QSTR(MP_QSTR_key_size), (mp_obj_t)&mp_aes_key_size_obj},
+};
+
+STATIC MP_DEFINE_CONST_DICT(aesio_module_globals, aesio_module_globals_table);
+
+const mp_obj_module_t aesio_module = {
+ .base = {&mp_type_module},
+ .globals = (mp_obj_dict_t *)&aesio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_aesio, aesio_module, CIRCUITPY_AESIO);
diff --git a/circuitpython/shared-bindings/aesio/__init__.h b/circuitpython/shared-bindings/aesio/__init__.h
new file mode 100644
index 0000000..60f6b83
--- /dev/null
+++ b/circuitpython/shared-bindings/aesio/__init__.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AESIO_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AESIO_H
+
+#include "shared-module/aesio/__init__.h"
+
+extern const mp_obj_type_t aesio_aes_type;
+
+void common_hal_aesio_aes_construct(aesio_aes_obj_t *self,
+ const uint8_t *key,
+ uint32_t key_length,
+ const uint8_t *iv,
+ int mode,
+ int counter);
+void common_hal_aesio_aes_rekey(aesio_aes_obj_t *self,
+ const uint8_t *key,
+ uint32_t key_length,
+ const uint8_t *iv);
+void common_hal_aesio_aes_set_mode(aesio_aes_obj_t *self,
+ int mode);
+void common_hal_aesio_aes_encrypt(aesio_aes_obj_t *self,
+ uint8_t *buffer,
+ size_t len);
+void common_hal_aesio_aes_decrypt(aesio_aes_obj_t *self,
+ uint8_t *buffer,
+ size_t len);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AESIO_H
diff --git a/circuitpython/shared-bindings/aesio/aes.c b/circuitpython/shared-bindings/aesio/aes.c
new file mode 100644
index 0000000..bb72b10
--- /dev/null
+++ b/circuitpython/shared-bindings/aesio/aes.c
@@ -0,0 +1,268 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/aesio/__init__.h"
+
+// Defined at the end of this file
+
+//| MODE_ECB: int
+//| MODE_CBC: int
+//| MODE_CTR: int
+//|
+//| class AES:
+//| """Encrypt and decrypt AES streams"""
+//|
+//| def __init__(self, key: ReadableBuffer, mode: int = 0, iv: Optional[ReadableBuffer] = None, segment_size: int = 8) -> None:
+//| """Create a new AES state with the given key.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer key: A 16-, 24-, or 32-byte key
+//| :param int mode: AES mode to use. One of: `MODE_ECB`, `MODE_CBC`, or
+//| `MODE_CTR`
+//| :param ~circuitpython_typing.ReadableBuffer iv: Initialization vector to use for CBC or CTR mode
+//|
+//| Additional arguments are supported for legacy reasons.
+//|
+//| Encrypting a string::
+//|
+//| import aesio
+//| from binascii import hexlify
+//|
+//| key = b'Sixteen byte key'
+//| inp = b'CircuitPython!!!' # Note: 16-bytes long
+//| outp = bytearray(len(inp))
+//| cipher = aesio.AES(key, aesio.MODE_ECB)
+//| cipher.encrypt_into(inp, outp)
+//| hexlify(outp)"""
+//| ...
+//|
+
+STATIC mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_args) {
+ (void)type;
+ enum { ARG_key, ARG_mode, ARG_IV, ARG_counter, ARG_segment_size };
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_key, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_mode, MP_ARG_INT, {.u_int = AES_MODE_ECB} },
+ {MP_QSTR_IV, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_counter, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_segment_size, MP_ARG_INT, {.u_int = 8}},
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args),
+ allowed_args, args);
+
+ aesio_aes_obj_t *self = m_new_obj(aesio_aes_obj_t);
+ self->base.type = &aesio_aes_type;
+
+ mp_buffer_info_t bufinfo;
+
+ const uint8_t *key = NULL;
+ uint32_t key_length = 0;
+ if (mp_get_buffer(args[ARG_key].u_obj, &bufinfo, MP_BUFFER_READ)) {
+ if ((bufinfo.len != 16) && (bufinfo.len != 24) && (bufinfo.len != 32)) {
+ mp_raise_TypeError(translate("Key must be 16, 24, or 32 bytes long"));
+ }
+ key = bufinfo.buf;
+ key_length = bufinfo.len;
+ } else {
+ mp_raise_TypeError(translate("No key was specified"));
+ }
+
+ int mode = args[ARG_mode].u_int;
+ switch (args[ARG_mode].u_int) {
+ case AES_MODE_CBC:
+ case AES_MODE_ECB:
+ case AES_MODE_CTR:
+ break;
+ default:
+ mp_raise_TypeError(translate("Requested AES mode is unsupported"));
+ }
+
+ // IV is required for CBC mode and is ignored for other modes.
+ const uint8_t *iv = NULL;
+ if (args[ARG_IV].u_obj != NULL &&
+ mp_get_buffer(args[ARG_IV].u_obj, &bufinfo, MP_BUFFER_READ)) {
+ if (bufinfo.len != AES_BLOCKLEN) {
+ mp_raise_TypeError_varg(translate("IV must be %d bytes long"),
+ AES_BLOCKLEN);
+ }
+ iv = bufinfo.buf;
+ }
+
+ common_hal_aesio_aes_construct(self, key, key_length, iv, mode,
+ args[ARG_counter].u_int);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t aesio_aes_rekey(size_t n_args, const mp_obj_t *pos_args) {
+ aesio_aes_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(pos_args[1], &bufinfo, MP_BUFFER_READ);
+ const uint8_t *key = bufinfo.buf;
+ size_t key_length = bufinfo.len;
+ if (key == NULL) {
+ mp_raise_ValueError(translate("No key was specified"));
+ }
+ if ((key_length != 16) && (key_length != 24) && (key_length != 32)) {
+ mp_raise_TypeError(translate("Key must be 16, 24, or 32 bytes long"));
+ }
+
+ const uint8_t *iv = NULL;
+ if (n_args > 2) {
+ mp_get_buffer_raise(pos_args[2], &bufinfo, MP_BUFFER_READ);
+ size_t iv_length = bufinfo.len;
+ iv = (const uint8_t *)bufinfo.buf;
+ if (iv_length != AES_BLOCKLEN) {
+ mp_raise_TypeError_varg(translate("IV must be %d bytes long"),
+ AES_BLOCKLEN);
+ }
+ }
+
+ common_hal_aesio_aes_rekey(self, key, key_length, iv);
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_VAR(aesio_aes_rekey_obj, 2, aesio_aes_rekey);
+
+STATIC void validate_length(aesio_aes_obj_t *self, size_t src_length,
+ size_t dest_length) {
+ if (src_length != dest_length) {
+ mp_raise_ValueError(
+ translate("Source and destination buffers must be the same length"));
+ }
+
+ switch (self->mode) {
+ case AES_MODE_ECB:
+ if (src_length != 16) {
+ mp_raise_msg(&mp_type_ValueError,
+ translate("ECB only operates on 16 bytes at a time"));
+ }
+ break;
+ case AES_MODE_CBC:
+ if ((src_length & 15) != 0) {
+ mp_raise_msg(&mp_type_ValueError,
+ translate("CBC blocks must be multiples of 16 bytes"));
+ }
+ break;
+ case AES_MODE_CTR:
+ break;
+ }
+}
+
+//| def encrypt_into(self, src: ReadableBuffer, dest: WriteableBuffer) -> None:
+//| """Encrypt the buffer from ``src`` into ``dest``.
+//|
+//| For ECB mode, the buffers must be 16 bytes long. For CBC mode, the
+//| buffers must be a multiple of 16 bytes, and must be equal length. For
+//| CTX mode, there are no restrictions."""
+//| ...
+//|
+STATIC mp_obj_t aesio_aes_encrypt_into(mp_obj_t aesio_obj, mp_obj_t src,
+ mp_obj_t dest) {
+ if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name);
+ }
+ // Convert parameters into expected types.
+ aesio_aes_obj_t *aes = MP_OBJ_TO_PTR(aesio_obj);
+
+ mp_buffer_info_t srcbufinfo, destbufinfo;
+ mp_get_buffer_raise(src, &srcbufinfo, MP_BUFFER_READ);
+ mp_get_buffer_raise(dest, &destbufinfo, MP_BUFFER_WRITE);
+ validate_length(aes, srcbufinfo.len, destbufinfo.len);
+
+ memcpy(destbufinfo.buf, srcbufinfo.buf, srcbufinfo.len);
+
+ common_hal_aesio_aes_encrypt(aes, (uint8_t *)destbufinfo.buf,
+ destbufinfo.len);
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(aesio_aes_encrypt_into_obj,
+ aesio_aes_encrypt_into);
+
+//| def decrypt_into(self, src: ReadableBuffer, dest: WriteableBuffer) -> None:
+//| """Decrypt the buffer from ``src`` into ``dest``.
+//| For ECB mode, the buffers must be 16 bytes long. For CBC mode, the
+//| buffers must be a multiple of 16 bytes, and must be equal length. For
+//| CTX mode, there are no restrictions."""
+//| ...
+//|
+STATIC mp_obj_t aesio_aes_decrypt_into(mp_obj_t aesio_obj, mp_obj_t src,
+ mp_obj_t dest) {
+ if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name);
+ }
+ // Convert parameters into expected types.
+ aesio_aes_obj_t *aes = MP_OBJ_TO_PTR(aesio_obj);
+
+ mp_buffer_info_t srcbufinfo, destbufinfo;
+ mp_get_buffer_raise(src, &srcbufinfo, MP_BUFFER_READ);
+ mp_get_buffer_raise(dest, &destbufinfo, MP_BUFFER_WRITE);
+ validate_length(aes, srcbufinfo.len, destbufinfo.len);
+
+ memcpy(destbufinfo.buf, srcbufinfo.buf, srcbufinfo.len);
+
+ common_hal_aesio_aes_decrypt(aes, (uint8_t *)destbufinfo.buf,
+ destbufinfo.len);
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(aesio_aes_decrypt_into_obj,
+ aesio_aes_decrypt_into);
+
+STATIC mp_obj_t aesio_aes_get_mode(mp_obj_t aesio_obj) {
+ if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name);
+ }
+ aesio_aes_obj_t *self = MP_OBJ_TO_PTR(aesio_obj);
+ return MP_OBJ_NEW_SMALL_INT(self->mode);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(aesio_aes_get_mode_obj, aesio_aes_get_mode);
+
+STATIC mp_obj_t aesio_aes_set_mode(mp_obj_t aesio_obj, mp_obj_t mode_obj) {
+ if (!mp_obj_is_type(aesio_obj, &aesio_aes_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), aesio_aes_type.name);
+ }
+ aesio_aes_obj_t *self = MP_OBJ_TO_PTR(aesio_obj);
+
+ int mode = mp_obj_get_int(mode_obj);
+ switch (mode) {
+ case AES_MODE_CBC:
+ case AES_MODE_ECB:
+ case AES_MODE_CTR:
+ break;
+ default:
+ mp_raise_TypeError(translate("Requested AES mode is unsupported"));
+ }
+
+ common_hal_aesio_aes_set_mode(self, mode);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(aesio_aes_set_mode_obj, aesio_aes_set_mode);
+
+MP_PROPERTY_GETSET(aesio_aes_mode_obj,
+ (mp_obj_t)&aesio_aes_get_mode_obj,
+ (mp_obj_t)&aesio_aes_set_mode_obj);
+
+STATIC const mp_rom_map_elem_t aesio_locals_dict_table[] = {
+ // Methods
+ {MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_AES)},
+ {MP_ROM_QSTR(MP_QSTR_encrypt_into), (mp_obj_t)&aesio_aes_encrypt_into_obj},
+ {MP_ROM_QSTR(MP_QSTR_decrypt_into), (mp_obj_t)&aesio_aes_decrypt_into_obj},
+ {MP_ROM_QSTR(MP_QSTR_rekey), (mp_obj_t)&aesio_aes_rekey_obj},
+ {MP_ROM_QSTR(MP_QSTR_mode), (mp_obj_t)&aesio_aes_mode_obj},
+};
+STATIC MP_DEFINE_CONST_DICT(aesio_locals_dict, aesio_locals_dict_table);
+
+const mp_obj_type_t aesio_aes_type = {
+ {&mp_type_type},
+ .name = MP_QSTR_AES,
+ .make_new = aesio_aes_make_new,
+ .locals_dict = (mp_obj_dict_t *)&aesio_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/alarm/SleepMemory.c b/circuitpython/shared-bindings/alarm/SleepMemory.c
new file mode 100644
index 0000000..7de36f0
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/SleepMemory.c
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+
+#include "shared-bindings/alarm/SleepMemory.h"
+#include "supervisor/shared/translate.h"
+
+//| class SleepMemory:
+//| """Store raw bytes in RAM that persists during deep sleep.
+//| The class acts as a ``bytearray``.
+//| If power is lost, the memory contents are lost.
+//|
+//| Note that this class can't be imported and used directly. The sole
+//| instance of :class:`SleepMemory` is available at
+//| :attr:`alarm.sleep_memory`.
+//|
+//| Usage::
+//|
+//| import alarm
+//| alarm.sleep_memory[0] = True
+//| alarm.sleep_memory[1] = 12
+//| """
+
+//| def __init__(self) -> None:
+//| """Not used. Access the sole instance through `alarm.sleep_memory`."""
+//| ...
+//|
+//| def __bool__(self) -> bool:
+//| """``sleep_memory`` is ``True`` if its length is greater than zero.
+//| This is an easy way to check for its existence.
+//| """
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Return the length. This is used by (`len`)"""
+//| ...
+//|
+STATIC mp_obj_t alarm_sleep_memory_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ alarm_sleep_memory_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint16_t len = common_hal_alarm_sleep_memory_get_length(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC const mp_rom_map_elem_t alarm_sleep_memory_locals_dict_table[] = {
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_sleep_memory_locals_dict, alarm_sleep_memory_locals_dict_table);
+
+//| @overload
+//| def __getitem__(self, index: slice) -> bytearray: ...
+//| @overload
+//| def __getitem__(self, index: int) -> int:
+//| """Returns the value at the given index."""
+//| ...
+//|
+//| @overload
+//| def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ...
+//| @overload
+//| def __setitem__(self, index: int, value: int) -> None:
+//| """Set the value at the given index."""
+//| ...
+//|
+STATIC mp_obj_t alarm_sleep_memory_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
+ if (value == MP_OBJ_NULL) {
+ // delete item
+ // slice deletion
+ return MP_OBJ_NULL; // op not supported
+ } else {
+ alarm_sleep_memory_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (0) {
+ #if MICROPY_PY_BUILTINS_SLICE
+ } else if (mp_obj_is_type(index_in, &mp_type_slice)) {
+ mp_bound_slice_t slice;
+ if (!mp_seq_get_fast_slice_indexes(common_hal_alarm_sleep_memory_get_length(self), index_in, &slice)) {
+ mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported"));
+ }
+ if (value != MP_OBJ_SENTINEL) {
+ #if MICROPY_PY_ARRAY_SLICE_ASSIGN
+ // Assign
+ size_t src_len = slice.stop - slice.start;
+ uint8_t *src_items;
+ if (mp_obj_is_type(value, &mp_type_array) ||
+ mp_obj_is_type(value, &mp_type_bytearray) ||
+ mp_obj_is_type(value, &mp_type_memoryview) ||
+ mp_obj_is_type(value, &mp_type_bytes)) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != src_len) {
+ mp_raise_ValueError(translate("Slice and value different lengths."));
+ }
+ src_len = bufinfo.len;
+ src_items = bufinfo.buf;
+ if (1 != mp_binary_get_size('@', bufinfo.typecode, NULL)) {
+ mp_raise_ValueError(translate("Array values should be single bytes."));
+ }
+ } else {
+ mp_raise_NotImplementedError(translate("array/bytes required on right side"));
+ }
+
+ if (!common_hal_alarm_sleep_memory_set_bytes(self, slice.start, src_items, src_len)) {
+ mp_raise_RuntimeError(translate("Unable to write to sleep_memory."));
+ }
+ return mp_const_none;
+ #else
+ return MP_OBJ_NULL; // op not supported
+ #endif
+ } else {
+ // Read slice.
+ size_t len = slice.stop - slice.start;
+ uint8_t *items = m_new(uint8_t, len);
+ common_hal_alarm_sleep_memory_get_bytes(self, slice.start, items, len);
+ return mp_obj_new_bytearray_by_ref(len, items);
+ }
+ #endif
+ } else {
+ // Single index rather than slice.
+ size_t index = mp_get_index(self->base.type, common_hal_alarm_sleep_memory_get_length(self),
+ index_in, false);
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ uint8_t value_out;
+ common_hal_alarm_sleep_memory_get_bytes(self, index, &value_out, 1);
+ return MP_OBJ_NEW_SMALL_INT(value_out);
+ } else {
+ // store
+ mp_int_t byte_value = mp_obj_get_int(value);
+ if (byte_value > 0xff || byte_value < 0) {
+ mp_raise_ValueError(translate("Bytes must be between 0 and 255."));
+ }
+ uint8_t short_value = byte_value;
+ if (!common_hal_alarm_sleep_memory_set_bytes(self, index, &short_value, 1)) {
+ mp_raise_RuntimeError(translate("Unable to write to sleep_memory."));
+ }
+ return mp_const_none;
+ }
+ }
+ }
+}
+
+const mp_obj_type_t alarm_sleep_memory_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SleepMemory,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .locals_dict = (mp_obj_t)&alarm_sleep_memory_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = alarm_sleep_memory_subscr,
+ .unary_op = alarm_sleep_memory_unary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/alarm/SleepMemory.h b/circuitpython/shared-bindings/alarm/SleepMemory.h
new file mode 100644
index 0000000..c1667ec
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/SleepMemory.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_SLEEPMEMORY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_SLEEPMEMORY_H
+
+#include "common-hal/alarm/SleepMemory.h"
+
+extern const mp_obj_type_t alarm_sleep_memory_type;
+
+uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self);
+
+bool common_hal_alarm_sleep_memory_set_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, const uint8_t *values, uint32_t len);
+void common_hal_alarm_sleep_memory_get_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, uint8_t *values, uint32_t len);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_SLEEPMEMORY_H
diff --git a/circuitpython/shared-bindings/alarm/__init__.c b/circuitpython/shared-bindings/alarm/__init__.c
new file mode 100644
index 0000000..7fd14b7
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/__init__.c
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/alarm/__init__.h"
+#include "shared-bindings/alarm/SleepMemory.h"
+#include "shared-bindings/alarm/pin/PinAlarm.h"
+#include "shared-bindings/alarm/time/TimeAlarm.h"
+#include "shared-bindings/alarm/touch/TouchAlarm.h"
+#include "shared-bindings/supervisor/Runtime.h"
+#include "shared-bindings/time/__init__.h"
+#include "supervisor/shared/workflow.h"
+
+//| """Alarms and sleep
+//|
+//| Provides alarms that trigger based on time intervals or on external events, such as pin
+//| changes.
+//| The program can simply wait for these alarms, or go to sleep and be awoken when they trigger.
+//|
+//| There are two supported levels of sleep: light sleep and deep sleep.
+//|
+//| Light sleep keeps sufficient state so the program can resume after sleeping.
+//| It does not shut down WiFi, BLE, or other communications, or ongoing activities such
+//| as audio playback. It reduces power consumption to the extent possible that leaves
+//| these continuing activities running. In some cases there may be no decrease in power consumption.
+//|
+//| Deep sleep shuts down power to nearly all of the microcontroller including the CPU and RAM. This can save
+//| a more significant amount of power, but CircuitPython must restart ``code.py`` from the beginning when
+//| awakened.
+//|
+//| For both light sleep and deep sleep, if CircuitPython is connected to a host computer,
+//| maintaining the connection takes priority and power consumption may not be reduced.
+//|
+//| For more information about working with alarms and light/deep sleep in CircuitPython,
+//| see `this Learn guide <https://learn.adafruit.com/deep-sleep-with-circuitpython>`_.
+//| """
+
+//| sleep_memory: SleepMemory
+//| """Memory that persists during deep sleep.
+//| This object is the sole instance of `alarm.SleepMemory`."""
+//|
+
+//| wake_alarm: Optional[circuitpython_typing.Alarm]
+//| """The most recently triggered alarm. If CircuitPython was sleeping, the alarm that woke it from sleep.
+//| If no alarm occured since the last hard reset or soft restart, value is ``None``.
+//| """
+//|
+
+// wake_alarm is implemented as a dictionary entry, so there's no code here.
+
+STATIC void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
+ for (size_t i = 0; i < n_args; i++) {
+ if (mp_obj_is_type(objs[i], &alarm_pin_pinalarm_type) ||
+ mp_obj_is_type(objs[i], &alarm_time_timealarm_type) ||
+ mp_obj_is_type(objs[i], &alarm_touch_touchalarm_type)) {
+ continue;
+ }
+ mp_raise_TypeError_varg(translate("Expected an alarm"));
+ }
+}
+
+//| def light_sleep_until_alarms(*alarms: circuitpython_typing.Alarm) -> circuitpython_typing.Alarm:
+//| """Go into a light sleep until awakened one of the alarms. The alarm causing the wake-up
+//| is returned, and is also available as `alarm.wake_alarm`.
+//|
+//| If no alarms are specified, return immediately.
+//|
+//| **If CircuitPython is connected to a host computer, the connection will be maintained,
+//| and the microcontroller may not actually go into a light sleep.**
+//| This allows the user to interrupt an existing program with ctrl-C,
+//| and to edit the files in CIRCUITPY, which would not be possible in true light sleep.
+//| Thus, to use light sleep and save significant power,
+//| it may be necessary to disconnect from the host.
+//| """
+//| ...
+//|
+STATIC mp_obj_t alarm_light_sleep_until_alarms(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ return mp_const_none;
+ }
+
+ validate_objs_are_alarms(n_args, args);
+
+ mp_obj_t alarm = common_hal_alarm_light_sleep_until_alarms(n_args, args);
+ shared_alarm_save_wake_alarm(alarm);
+ return alarm;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_light_sleep_until_alarms);
+
+//| def exit_and_deep_sleep_until_alarms(*alarms: circuitpython_typing.Alarm) -> None:
+//| """Exit the program and go into a deep sleep, until awakened by one of the alarms.
+//| This function does not return.
+//|
+//| When awakened, the microcontroller will restart and will run ``boot.py`` and ``code.py``
+//| from the beginning.
+//|
+//| After restart, an alarm *equivalent* to the one that caused the wake-up
+//| will be available as `alarm.wake_alarm`.
+//| Its type and/or attributes may not correspond exactly to the original alarm.
+//| For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created.
+//|
+//| If no alarms are specified, the microcontroller will deep sleep until reset.
+//|
+//| **If CircuitPython is connected to a host computer via USB or BLE
+//| the first time a deep sleep is requested,
+//| the connection will be maintained and the system will not go into deep sleep.**
+//| This allows the user to interrupt an existing program with ctrl-C,
+//| and to edit the files in CIRCUITPY, which would not be possible in true deep sleep.
+//|
+//| If CircuitPython goes into a true deep sleep, and USB or BLE is reconnected,
+//| the next deep sleep will still be a true deep sleep. You must do a hard reset
+//| or power-cycle to exit a true deep sleep loop.
+//|
+//| Here is skeletal example that deep-sleeps and restarts every 60 seconds:
+//|
+//| .. code-block:: python
+//|
+//| import alarm
+//| import time
+//|
+//| print("Waking up")
+//|
+//| # Set an alarm for 60 seconds from now.
+//| time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60)
+//|
+//| # Deep sleep until the alarm goes off. Then restart the program.
+//| alarm.exit_and_deep_sleep_until_alarms(time_alarm)
+//| """
+//| ...
+//|
+STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *args) {
+ validate_objs_are_alarms(n_args, args);
+
+ // Validate the alarms and set them.
+ common_hal_alarm_set_deep_sleep_alarms(n_args, args);
+
+ // Raise an exception, which will be processed in main.c.
+ mp_raise_type_arg(&mp_type_DeepSleepRequest, NULL);
+
+ // Doesn't get here.
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_exit_and_deep_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_exit_and_deep_sleep_until_alarms);
+
+STATIC const mp_map_elem_t alarm_pin_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pin) },
+
+ { MP_ROM_QSTR(MP_QSTR_PinAlarm), MP_OBJ_FROM_PTR(&alarm_pin_pinalarm_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_pin_globals, alarm_pin_globals_table);
+
+STATIC const mp_obj_module_t alarm_pin_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&alarm_pin_globals,
+};
+
+STATIC const mp_map_elem_t alarm_time_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) },
+
+ { MP_ROM_QSTR(MP_QSTR_TimeAlarm), MP_OBJ_FROM_PTR(&alarm_time_timealarm_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_time_globals, alarm_time_globals_table);
+
+STATIC const mp_obj_module_t alarm_time_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&alarm_time_globals,
+};
+
+STATIC const mp_map_elem_t alarm_touch_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_touch) },
+ { MP_ROM_QSTR(MP_QSTR_TouchAlarm), MP_OBJ_FROM_PTR(&alarm_touch_touchalarm_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_touch_globals, alarm_touch_globals_table);
+
+STATIC const mp_obj_module_t alarm_touch_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&alarm_touch_globals,
+};
+
+// The module table is mutable because .wake_alarm is a mutable attribute.
+STATIC mp_map_elem_t alarm_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_alarm) },
+
+ // wake_alarm is a mutable attribute.
+ { MP_ROM_QSTR(MP_QSTR_wake_alarm), mp_const_none },
+
+ { MP_ROM_QSTR(MP_QSTR_light_sleep_until_alarms), MP_OBJ_FROM_PTR(&alarm_light_sleep_until_alarms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_exit_and_deep_sleep_until_alarms),
+ MP_OBJ_FROM_PTR(&alarm_exit_and_deep_sleep_until_alarms_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_pin), MP_OBJ_FROM_PTR(&alarm_pin_module) },
+ { MP_ROM_QSTR(MP_QSTR_time), MP_OBJ_FROM_PTR(&alarm_time_module) },
+ { MP_ROM_QSTR(MP_QSTR_touch), MP_OBJ_FROM_PTR(&alarm_touch_module) },
+
+ { MP_ROM_QSTR(MP_QSTR_SleepMemory), MP_OBJ_FROM_PTR(&alarm_sleep_memory_type) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_memory), MP_OBJ_FROM_PTR(&alarm_sleep_memory_obj) },
+};
+STATIC MP_DEFINE_MUTABLE_DICT(alarm_module_globals, alarm_module_globals_table);
+
+// Fetch value from module dict.
+mp_obj_t shared_alarm_get_wake_alarm(void) {
+ mp_map_elem_t *elem =
+ mp_map_lookup(&alarm_module_globals.map, MP_ROM_QSTR(MP_QSTR_wake_alarm), MP_MAP_LOOKUP);
+ if (elem) {
+ return elem->value;
+ } else {
+ return NULL;
+ }
+}
+
+// Initialize .wake_alarm value.
+void shared_alarm_save_wake_alarm(mp_obj_t alarm) {
+ // Equivalent of:
+ // alarm.wake_alarm = alarm
+ mp_map_elem_t *elem =
+ mp_map_lookup(&alarm_module_globals.map, MP_ROM_QSTR(MP_QSTR_wake_alarm), MP_MAP_LOOKUP);
+ if (elem) {
+ elem->value = alarm;
+ }
+}
+
+const mp_obj_module_t alarm_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&alarm_module_globals,
+};
+
+extern void port_idle_until_interrupt(void);
+
+MP_WEAK void common_hal_alarm_pretending_deep_sleep(void) {
+ port_idle_until_interrupt();
+}
+
+MP_REGISTER_MODULE(MP_QSTR_alarm, alarm_module, CIRCUITPY_ALARM);
diff --git a/circuitpython/shared-bindings/alarm/__init__.h b/circuitpython/shared-bindings/alarm/__init__.h
new file mode 100644
index 0000000..eb67917
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/__init__.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H
+
+#include "py/obj.h"
+
+#include "common-hal/alarm/__init__.h"
+
+// Light sleep fully self-contained and does not exit user code. It will return
+// the same alarm object that was orignally passed in, unlike deep sleep, which
+// must create an identical copy due to the VM reset
+extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
+
+// Deep sleep is a two step process. Alarms are set when the VM is valid but
+// everything is reset before entering deep sleep. Furthermore, deep sleep may
+// not actually happen if the user is connected to the device. In this case, the
+// supervisor will idle using `port_wait_for_interrupt`. After each call, it will
+// call alarm_woken_from_sleep to see if we've been woken by an alarm and if so,
+// it will exit idle as if deep sleep was exited
+extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms);
+
+extern NORETURN void common_hal_alarm_enter_deep_sleep(void);
+
+// May be used to re-initialize peripherals like GPIO, if the VM reset returned
+// them to a default state
+extern void common_hal_alarm_pretending_deep_sleep(void);
+
+// Fetches value from module dict.
+extern mp_obj_t shared_alarm_get_wake_alarm(void);
+
+// Creates a new alarm object after exiting deep sleep (real or fake)
+extern mp_obj_t common_hal_alarm_create_wake_alarm(void);
+
+// Saves alarm to global array
+void shared_alarm_save_wake_alarm(mp_obj_t alarm);
+
+// True if an alarm is alerting. Used in light sleep/fake deep sleep
+extern bool common_hal_alarm_woken_from_sleep(void);
+
+extern void common_hal_alarm_gc_collect(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H
diff --git a/circuitpython/shared-bindings/alarm/pin/PinAlarm.c b/circuitpython/shared-bindings/alarm/pin/PinAlarm.c
new file mode 100644
index 0000000..ff34716
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/pin/PinAlarm.c
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/board/__init__.h"
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/alarm/pin/PinAlarm.h"
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class PinAlarm:
+//| """Trigger an alarm when a pin changes state."""
+//|
+//| def __init__(self, pin: microcontroller.Pin, value: bool, edge: bool = False, pull: bool = False) -> None:
+//| """Create an alarm triggered by a `microcontroller.Pin` level. The alarm is not active
+//| until it is passed to an `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or
+//| `alarm.exit_and_deep_sleep_until_alarms()`.
+//|
+//| :param microcontroller.Pin pin: The pin to monitor. On some ports, the choice of pin
+//| may be limited due to hardware restrictions, particularly for deep-sleep alarms.
+//| :param bool value: When active, trigger when the pin value is high (``True``) or low (``False``).
+//| On some ports, multiple `PinAlarm` objects may need to have coordinated values
+//| for deep-sleep alarms.
+//| :param bool edge: If ``True``, trigger only when there is a transition to the specified
+//| value of ``value``. If ``True``, if the alarm becomes active when the pin value already
+//| matches ``value``, the alarm is not triggered: the pin must transition from ``not value``
+//| to ``value`` to trigger the alarm. On some ports, edge-triggering may not be available,
+//| particularly for deep-sleep alarms.
+//| :param bool pull: Enable a pull-up or pull-down which pulls the pin to the level opposite
+//| that of ``value``. For instance, if ``value`` is set to ``True``, setting ``pull``
+//| to ``True`` will enable a pull-down, to hold the pin low normally until an outside signal
+//| pulls it high.
+//| """
+//| ...
+//|
+STATIC mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ alarm_pin_pinalarm_obj_t *self = m_new_obj(alarm_pin_pinalarm_obj_t);
+ self->base.type = &alarm_pin_pinalarm_type;
+ enum { ARG_pin, ARG_value, ARG_edge, ARG_pull };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_BOOL },
+ { MP_QSTR_edge, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+
+ common_hal_alarm_pin_pinalarm_construct(self,
+ pin,
+ args[ARG_value].u_bool,
+ args[ARG_edge].u_bool,
+ args[ARG_pull].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| pin: microcontroller.Pin
+//| """The trigger pin."""
+//|
+STATIC mp_obj_t alarm_pin_pinalarm_obj_get_pin(mp_obj_t self_in) {
+ alarm_pin_pinalarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const mcu_pin_obj_t *pin = common_hal_alarm_pin_pinalarm_get_pin(self);
+ if (pin == NULL) {
+ return mp_const_none;
+ }
+ return MP_OBJ_FROM_PTR(pin);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(alarm_pin_pinalarm_get_pin_obj, alarm_pin_pinalarm_obj_get_pin);
+
+MP_PROPERTY_GETTER(alarm_pin_pinalarm_pin_obj,
+ (mp_obj_t)&alarm_pin_pinalarm_get_pin_obj);
+
+//| value: bool
+//| """The value on which to trigger."""
+//|
+STATIC mp_obj_t alarm_pin_pinalarm_obj_get_value(mp_obj_t self_in) {
+ alarm_pin_pinalarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_alarm_pin_pinalarm_get_value(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(alarm_pin_pinalarm_get_value_obj, alarm_pin_pinalarm_obj_get_value);
+
+MP_PROPERTY_GETTER(alarm_pin_pinalarm_value_obj,
+ (mp_obj_t)&alarm_pin_pinalarm_get_value_obj);
+
+STATIC const mp_rom_map_elem_t alarm_pin_pinalarm_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&alarm_pin_pinalarm_pin_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&alarm_pin_pinalarm_value_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_pin_pinalarm_locals_dict, alarm_pin_pinalarm_locals_dict_table);
+
+const mp_obj_type_t alarm_pin_pinalarm_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PinAlarm,
+ .make_new = alarm_pin_pinalarm_make_new,
+ .locals_dict = (mp_obj_t)&alarm_pin_pinalarm_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/alarm/pin/PinAlarm.h b/circuitpython/shared-bindings/alarm/pin/PinAlarm.h
new file mode 100644
index 0000000..ba74bab
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/pin/PinAlarm.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H
+
+#include "py/obj.h"
+#include "py/objtuple.h"
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/alarm/pin/PinAlarm.h"
+
+extern const mp_obj_type_t alarm_pin_pinalarm_type;
+
+void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, const mcu_pin_obj_t *pin, bool value, bool edge, bool pull);
+extern const mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self);
+extern bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self);
+extern bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self);
+extern bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H
diff --git a/circuitpython/shared-bindings/alarm/time/TimeAlarm.c b/circuitpython/shared-bindings/alarm/time/TimeAlarm.c
new file mode 100644
index 0000000..ab0274a
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/time/TimeAlarm.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/alarm/time/TimeAlarm.h"
+#include "shared-bindings/rtc/__init__.h"
+#include "shared-bindings/time/__init__.h"
+
+#include "supervisor/shared/translate.h"
+
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+mp_obj_t MP_WEAK rtc_get_time_source_time(void) {
+ mp_raise_RuntimeError(translate("RTC is not supported on this board"));
+}
+#endif
+
+//| class TimeAlarm:
+//| """Trigger an alarm when the specified time is reached."""
+//|
+//| def __init__(self, monotonic_time: Optional[float] = None, epoch_time: Optional[int] = None) -> None:
+//| """Create an alarm that will be triggered when `time.monotonic()` would equal
+//| ``monotonic_time``, or when `time.time()` would equal ``epoch_time``.
+//| Only one of the two arguments can be given.
+//| The alarm is not active until it is passed to an
+//| `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or
+//| `alarm.exit_and_deep_sleep_until_alarms()`.
+//|
+//| If the given time is in the past when sleep occurs, the alarm will be triggered
+//| immediately.
+//| """
+//| ...
+//|
+STATIC mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ alarm_time_timealarm_obj_t *self = m_new_obj(alarm_time_timealarm_obj_t);
+ self->base.type = &alarm_time_timealarm_type;
+
+ enum { ARG_monotonic_time, ARG_epoch_time };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_monotonic_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_epoch_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ bool have_monotonic = args[ARG_monotonic_time].u_obj != mp_const_none;
+ bool have_epoch = args[ARG_epoch_time].u_obj != mp_const_none;
+
+ if (!(have_monotonic ^ have_epoch)) {
+ mp_raise_ValueError(translate("Supply one of monotonic_time or epoch_time"));
+ }
+
+ mp_float_t monotonic_time = 0; // To avoid compiler warning.
+ if (have_monotonic) {
+ monotonic_time = mp_obj_get_float(args[ARG_monotonic_time].u_obj);
+ }
+
+ mp_float_t monotonic_time_now = common_hal_time_monotonic_ms() / 1000.0;
+
+ if (have_epoch) {
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+ mp_raise_ValueError(translate("epoch_time not supported on this board"));
+ #else
+ mp_uint_t epoch_time_secs = mp_obj_int_get_checked(args[ARG_epoch_time].u_obj);
+
+ timeutils_struct_time_t tm;
+ struct_time_to_tm(rtc_get_time_source_time(), &tm);
+ mp_uint_t epoch_secs_now = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ // How far in the future (in secs) is the requested time?
+ mp_int_t epoch_diff = epoch_time_secs - epoch_secs_now;
+ // Convert it to a future monotonic time.
+ monotonic_time = monotonic_time_now + epoch_diff;
+ #endif
+ }
+
+ if (monotonic_time < monotonic_time_now) {
+ mp_raise_ValueError(translate("Time is in the past."));
+ }
+
+ common_hal_alarm_time_timealarm_construct(self, monotonic_time);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| monotonic_time: float
+//| """When this time is reached, the alarm will trigger, based on the `time.monotonic()` clock.
+//| The time may be given as ``epoch_time`` in the constructor, but it is returned
+//| by this property only as a `time.monotonic()` time.
+//| """
+//|
+STATIC mp_obj_t alarm_time_timealarm_obj_get_monotonic_time(mp_obj_t self_in) {
+ alarm_time_timealarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_float(common_hal_alarm_time_timealarm_get_monotonic_time(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(alarm_time_timealarm_get_monotonic_time_obj, alarm_time_timealarm_obj_get_monotonic_time);
+
+MP_PROPERTY_GETTER(alarm_time_timealarm_monotonic_time_obj,
+ (mp_obj_t)&alarm_time_timealarm_get_monotonic_time_obj);
+
+STATIC const mp_rom_map_elem_t alarm_time_timealarm_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_monotonic_time), MP_ROM_PTR(&alarm_time_timealarm_monotonic_time_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(alarm_time_timealarm_locals_dict, alarm_time_timealarm_locals_dict_table);
+
+const mp_obj_type_t alarm_time_timealarm_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TimeAlarm,
+ .make_new = alarm_time_timealarm_make_new,
+ .locals_dict = (mp_obj_t)&alarm_time_timealarm_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/alarm/time/TimeAlarm.h b/circuitpython/shared-bindings/alarm/time/TimeAlarm.h
new file mode 100644
index 0000000..0a4b9ca
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/time/TimeAlarm.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H
+
+#include "py/obj.h"
+
+#include "common-hal/alarm/time/TimeAlarm.h"
+
+extern const mp_obj_type_t alarm_time_timealarm_type;
+
+extern void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time);
+extern mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timealarm_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H
diff --git a/circuitpython/shared-bindings/alarm/touch/TouchAlarm.c b/circuitpython/shared-bindings/alarm/touch/TouchAlarm.c
new file mode 100644
index 0000000..ce5074f
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/touch/TouchAlarm.c
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/alarm/touch/TouchAlarm.h"
+#include "shared-bindings/board/__init__.h"
+
+#include "py/objproperty.h"
+
+//| class TouchAlarm:
+//| """Trigger an alarm when touch is detected."""
+//|
+//| def __init__(self, *pin: microcontroller.Pin) -> None:
+//| """Create an alarm that will be triggered when the given pin is touched.
+//| The alarm is not active until it is passed to an `alarm`-enabling function, such as
+//| `alarm.light_sleep_until_alarms()` or `alarm.exit_and_deep_sleep_until_alarms()`.
+//|
+//| :param microcontroller.Pin pin: The pin to monitor. On some ports, the choice of pin
+//| may be limited due to hardware restrictions, particularly for deep-sleep alarms.
+//| """
+//| ...
+//|
+STATIC mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ alarm_touch_touchalarm_obj_t *self = m_new_obj(alarm_touch_touchalarm_obj_t);
+ self->base.type = &alarm_touch_touchalarm_type;
+
+ enum { ARG_pin };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+
+ common_hal_alarm_touch_touchalarm_construct(self, pin);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| pin: microcontroller.Pin
+//| """The trigger pin."""
+//|
+STATIC mp_obj_t alarm_touch_touchalarm_obj_get_pin(mp_obj_t self_in) {
+ alarm_touch_touchalarm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_FROM_PTR(self->pin);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(alarm_touch_touchalarm_get_pin_obj, alarm_touch_touchalarm_obj_get_pin);
+
+MP_PROPERTY_GETTER(alarm_touch_touchalarm_pin_obj,
+ (mp_obj_t)&alarm_touch_touchalarm_get_pin_obj);
+
+STATIC const mp_rom_map_elem_t alarm_touch_touchalarm_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&alarm_touch_touchalarm_pin_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(alarm_touch_touchalarm_locals_dict, alarm_touch_touchalarm_locals_dict_table);
+
+const mp_obj_type_t alarm_touch_touchalarm_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TouchAlarm,
+ .make_new = alarm_touch_touchalarm_make_new,
+ .locals_dict = (mp_obj_t)&alarm_touch_touchalarm_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/alarm/touch/TouchAlarm.h b/circuitpython/shared-bindings/alarm/touch/TouchAlarm.h
new file mode 100644
index 0000000..1b70d4d
--- /dev/null
+++ b/circuitpython/shared-bindings/alarm/touch/TouchAlarm.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 microDev
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TOUCH_TOUCHALARM_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TOUCH_TOUCHALARM_H
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/alarm/touch/TouchAlarm.h"
+
+extern const mp_obj_type_t alarm_touch_touchalarm_type;
+
+extern void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TOUCH_TOUCHALARM_H
diff --git a/circuitpython/shared-bindings/analogio/AnalogIn.c b/circuitpython/shared-bindings/analogio/AnalogIn.c
new file mode 100644
index 0000000..f2c888f
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/AnalogIn.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/mphal.h"
+#include "py/nlr.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/analogio/AnalogIn.h"
+#include "shared-bindings/util.h"
+
+//| class AnalogIn:
+//| """Read analog voltage levels
+//|
+//| Usage::
+//|
+//| import analogio
+//| from board import *
+//|
+//| adc = analogio.AnalogIn(A1)
+//| val = adc.value"""
+//|
+
+//| def __init__(self, pin: microcontroller.Pin) -> None:
+//| """Use the AnalogIn on the given pin. The reference voltage varies by
+//| platform so use ``reference_voltage`` to read the configured setting.
+//|
+//| :param ~microcontroller.Pin pin: the pin to read from"""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogin_make_new(const mp_obj_type_t *type,
+ mp_uint_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // 1st argument is the pin
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]);
+
+ analogio_analogin_obj_t *self = m_new_obj(analogio_analogin_obj_t);
+ self->base.type = &analogio_analogin_type;
+ common_hal_analogio_analogin_construct(self, pin);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the AnalogIn and release the pin for other use."""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogin_deinit(mp_obj_t self_in) {
+ analogio_analogin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_analogio_analogin_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_deinit_obj, analogio_analogin_deinit);
+
+STATIC void check_for_deinit(analogio_analogin_obj_t *self) {
+ if (common_hal_analogio_analogin_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| def __enter__(self) -> AnalogIn:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogin___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_analogio_analogin_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(analogio_analogin___exit___obj, 4, 4, analogio_analogin___exit__);
+
+//| value: int
+//| """The value on the analog pin between 0 and 65535 inclusive (16-bit). (read-only)
+//|
+//| Even if the underlying analog to digital converter (ADC) is lower
+//| resolution, the value is 16-bit."""
+//|
+STATIC mp_obj_t analogio_analogin_obj_get_value(mp_obj_t self_in) {
+ analogio_analogin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_analogio_analogin_get_value(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_get_value_obj, analogio_analogin_obj_get_value);
+
+MP_PROPERTY_GETTER(analogio_analogin_value_obj,
+ (mp_obj_t)&analogio_analogin_get_value_obj);
+
+//| reference_voltage: float
+//| """The maximum voltage measurable (also known as the reference voltage) as a
+//| `float` in Volts. Note the ADC value may not scale to the actual voltage linearly
+//| at ends of the analog range."""
+//|
+STATIC mp_obj_t analogio_analogin_obj_get_reference_voltage(mp_obj_t self_in) {
+ analogio_analogin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ float reference_voltage = common_hal_analogio_analogin_get_reference_voltage(self);
+ if (reference_voltage <= 0.0f) {
+ return mp_const_none;
+ } else {
+ return mp_obj_new_float(reference_voltage);
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_get_reference_voltage_obj,
+ analogio_analogin_obj_get_reference_voltage);
+
+MP_PROPERTY_GETTER(analogio_analogin_reference_voltage_obj,
+ (mp_obj_t)&analogio_analogin_get_reference_voltage_obj);
+
+STATIC const mp_rom_map_elem_t analogio_analogin_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&analogio_analogin_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&analogio_analogin___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&analogio_analogin_value_obj)},
+ { MP_ROM_QSTR(MP_QSTR_reference_voltage), MP_ROM_PTR(&analogio_analogin_reference_voltage_obj)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(analogio_analogin_locals_dict, analogio_analogin_locals_dict_table);
+
+const mp_obj_type_t analogio_analogin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_AnalogIn,
+ .make_new = analogio_analogin_make_new,
+ .locals_dict = (mp_obj_t)&analogio_analogin_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/analogio/AnalogIn.h b/circuitpython/shared-bindings/analogio/AnalogIn.h
new file mode 100644
index 0000000..9f80416
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/AnalogIn.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGIN_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/analogio/AnalogIn.h"
+
+extern const mp_obj_type_t analogio_analogin_type;
+
+void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin);
+void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self);
+bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self);
+uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self);
+float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self);
+
+#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGIN_H__
diff --git a/circuitpython/shared-bindings/analogio/AnalogOut.c b/circuitpython/shared-bindings/analogio/AnalogOut.c
new file mode 100644
index 0000000..31173f8
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/AnalogOut.c
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/analogio/AnalogOut.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class AnalogOut:
+//| """Output analog values (a specific voltage).
+//|
+//| Example usage::
+//|
+//| import analogio
+//| from board import *
+//|
+//| dac = analogio.AnalogOut(A2) # output on pin A2
+//| dac.value = 32768 # makes A2 1.65V"""
+//|
+//| def __init__(self, pin: microcontroller.Pin) -> None:
+//| """Use the AnalogOut on the given pin.
+//|
+//| :param ~microcontroller.Pin pin: the pin to output to"""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogout_make_new(const mp_obj_type_t *type, mp_uint_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]);
+
+ analogio_analogout_obj_t *self = m_new_obj(analogio_analogout_obj_t);
+ self->base.type = &analogio_analogout_type;
+ common_hal_analogio_analogout_construct(self, pin);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the AnalogOut and release the pin for other use."""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogout_deinit(mp_obj_t self_in) {
+ analogio_analogout_obj_t *self = self_in;
+
+ common_hal_analogio_analogout_deinit(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogout_deinit_obj, analogio_analogout_deinit);
+
+//| def __enter__(self) -> AnalogOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t analogio_analogout___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_analogio_analogout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(analogio_analogout___exit___obj, 4, 4, analogio_analogout___exit__);
+
+//| value: int
+//| """The value on the analog pin between 0 and 65535 inclusive (16-bit). (write-only)
+//|
+//| Even if the underlying digital to analog converter (DAC) is lower
+//| resolution, the value is 16-bit."""
+//|
+STATIC mp_obj_t analogio_analogout_obj_set_value(mp_obj_t self_in, mp_obj_t value) {
+ analogio_analogout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (common_hal_analogio_analogout_deinited(self)) {
+ raise_deinited_error();
+ }
+ uint32_t v = mp_obj_get_int(value);
+ if (v >= (1 << 16)) {
+ mp_raise_ValueError(translate("AnalogOut is only 16 bits. Value must be less than 65536."));
+ }
+ common_hal_analogio_analogout_set_value(self, v);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(analogio_analogout_set_value_obj, analogio_analogout_obj_set_value);
+
+MP_PROPERTY_GETSET(analogio_analogout_value_obj,
+ MP_ROM_NONE,
+ (mp_obj_t)&analogio_analogout_set_value_obj);
+
+STATIC const mp_rom_map_elem_t analogio_analogout_locals_dict_table[] = {
+ // instance methods
+ { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&analogio_analogout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&analogio_analogout___exit___obj) },
+
+ // Properties
+ { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&analogio_analogout_value_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(analogio_analogout_locals_dict, analogio_analogout_locals_dict_table);
+
+const mp_obj_type_t analogio_analogout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_AnalogOut,
+ .make_new = analogio_analogout_make_new,
+ .locals_dict = (mp_obj_t)&analogio_analogout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/analogio/AnalogOut.h b/circuitpython/shared-bindings/analogio/AnalogOut.h
new file mode 100644
index 0000000..736afd0
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/AnalogOut.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGOUT_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/analogio/AnalogOut.h"
+
+extern const mp_obj_type_t analogio_analogout_type;
+
+void common_hal_analogio_analogout_construct(analogio_analogout_obj_t *self, const mcu_pin_obj_t *pin);
+void common_hal_analogio_analogout_deinit(analogio_analogout_obj_t *self);
+bool common_hal_analogio_analogout_deinited(analogio_analogout_obj_t *self);
+void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self, uint16_t value);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGOUT_H
diff --git a/circuitpython/shared-bindings/analogio/__init__.c b/circuitpython/shared-bindings/analogio/__init__.c
new file mode 100644
index 0000000..eb956d0
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/__init__.c
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/analogio/__init__.h"
+#include "shared-bindings/analogio/AnalogIn.h"
+#include "shared-bindings/analogio/AnalogOut.h"
+
+//| """Analog hardware support
+//|
+//| The `analogio` module contains classes to provide access to analog IO
+//| typically implemented with digital-to-analog (DAC) and analog-to-digital
+//| (ADC) converters.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import analogio
+//| from board import *
+//|
+//| pin = analogio.AnalogIn(A0)
+//| print(pin.value)
+//| pin.deinit()
+//|
+//| This example will initialize the the device, read
+//| :py:data:`~analogio.AnalogIn.value` and then
+//| :py:meth:`~analogio.AnalogIn.deinit` the hardware. The last step is optional
+//| because CircuitPython will do it automatically after the program finishes.
+//|
+//| For the essentials of `analogio`, see the `CircuitPython Essentials
+//| Learn guide <https://learn.adafruit.com/circuitpython-essentials/circuitpython-analog-in>`_
+//|
+//| For more information on using `analogio`, see `this additional Learn guide
+//| <https://learn.adafruit.com/circuitpython-basics-analog-inputs-and-outputs>`_
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t analogio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_analogio) },
+ { MP_ROM_QSTR(MP_QSTR_AnalogIn), MP_ROM_PTR(&analogio_analogin_type) },
+ { MP_ROM_QSTR(MP_QSTR_AnalogOut), MP_ROM_PTR(&analogio_analogout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(analogio_module_globals, analogio_module_globals_table);
+
+const mp_obj_module_t analogio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&analogio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_analogio, analogio_module, CIRCUITPY_ANALOGIO);
diff --git a/circuitpython/shared-bindings/analogio/__init__.h b/circuitpython/shared-bindings/analogio/__init__.h
new file mode 100644
index 0000000..284a95b
--- /dev/null
+++ b/circuitpython/shared-bindings/analogio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO___INIT___H
diff --git a/circuitpython/shared-bindings/atexit/__init__.c b/circuitpython/shared-bindings/atexit/__init__.c
new file mode 100644
index 0000000..dd27ada
--- /dev/null
+++ b/circuitpython/shared-bindings/atexit/__init__.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-module/atexit/__init__.h"
+
+//| """Atexit Module
+//|
+//| This module defines functions to register and unregister cleanup functions.
+//| Functions thus registered are automatically executed upon normal vm termination.
+//|
+//| These functions are run in the reverse order in which they were registered;
+//| if you register ``A``, ``B``, and ``C``, they will be run in the order ``C``, ``B``, ``A``.
+//|
+//| |see_cpython_module| :mod:`cpython:atexit`.
+//| """
+//| ...
+//|
+
+//| def register(func: Callable[..., Any], *args: Optional[Any], **kwargs: Optional[Any]) -> Callable[..., Any]:
+//|
+//| """Register func as a function to be executed at termination.
+//|
+//| Any optional arguments that are to be passed to func must be passed as arguments to `register()`.
+//| It is possible to register the same function and arguments more than once.
+//|
+//| At normal program termination (for instance, if `sys.exit()` is called or the vm execution completes),
+//| all functions registered are called in last in, first out order.
+//|
+//| If an exception is raised during execution of the exit handler,
+//| a traceback is printed (unless `SystemExit` is raised) and the execution stops.
+//|
+//| This function returns func, which makes it possible to use it as a decorator.
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t atexit_register(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ shared_module_atexit_register(pos_args[0], (n_args - 1), ((n_args > 1) ? &pos_args[1] : NULL), kw_args);
+ return pos_args[0];
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(atexit_register_obj, 1, atexit_register);
+
+//| def unregister(func: Callable[..., Any]) -> None:
+//|
+//| """Remove func from the list of functions to be run at termination.
+//|
+//| `unregister()` silently does nothing if func was not previously registered. If func has been registered more than once,
+//| every occurrence of that function in the atexit call stack will be removed.
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t atexit_unregister(const mp_obj_t self_in) {
+ shared_module_atexit_unregister(&self_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(atexit_unregister_obj, atexit_unregister);
+
+STATIC const mp_rom_map_elem_t atexit_module_globals_table[] = {
+ // module name
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_atexit) },
+ // module functions
+ { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&atexit_register_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&atexit_unregister_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(atexit_module_globals, atexit_module_globals_table);
+
+const mp_obj_module_t atexit_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&atexit_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_atexit, atexit_module, CIRCUITPY_ATEXIT);
diff --git a/circuitpython/shared-bindings/audiobusio/I2SOut.c b/circuitpython/shared-bindings/audiobusio/I2SOut.c
new file mode 100644
index 0000000..93c316d
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/I2SOut.c
@@ -0,0 +1,279 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiobusio/I2SOut.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class I2SOut:
+//| """Output an I2S audio signal"""
+//|
+//| def __init__(self, bit_clock: microcontroller.Pin, word_select: microcontroller.Pin, data: microcontroller.Pin, *, left_justified: bool) -> None:
+//| """Create a I2SOut object associated with the given pins.
+//|
+//| :param ~microcontroller.Pin bit_clock: The bit clock (or serial clock) pin
+//| :param ~microcontroller.Pin word_select: The word select (or left/right clock) pin
+//| :param ~microcontroller.Pin data: The data pin
+//| :param bool left_justified: True when data bits are aligned with the word select clock. False
+//| when they are shifted by one to match classic I2S protocol.
+//|
+//| Simple 8ksps 440 Hz sine wave on `Metro M0 Express <https://www.adafruit.com/product/3505>`_
+//| using `UDA1334 Breakout <https://www.adafruit.com/product/3678>`_::
+//|
+//| import audiobusio
+//| import audiocore
+//| import board
+//| import array
+//| import time
+//| import math
+//|
+//| # Generate one period of sine wave.
+//| length = 8000 // 440
+//| sine_wave = array.array("H", [0] * length)
+//| for i in range(length):
+//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+//|
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+//| i2s = audiobusio.I2SOut(board.D1, board.D0, board.D9)
+//| i2s.play(sine_wave, loop=True)
+//| time.sleep(1)
+//| i2s.stop()
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audiocore
+//| import audiobusio
+//| import digitalio
+//|
+//|
+//| f = open("cplay-5.1-16bit-16khz.wav", "rb")
+//| wav = audiocore.WaveFile(f)
+//|
+//| a = audiobusio.I2SOut(board.D1, board.D0, board.D9)
+//|
+//| print("playing")
+//| a.play(wav)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ #if !CIRCUITPY_AUDIOBUSIO_I2SOUT
+ mp_raise_NotImplementedError(translate("I2SOut not available"));
+ return NULL; // Not reachable.
+ #else
+ enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_left_justified };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bit_clock, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_word_select, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_left_justified, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *bit_clock = validate_obj_is_free_pin(args[ARG_bit_clock].u_obj);
+ const mcu_pin_obj_t *word_select = validate_obj_is_free_pin(args[ARG_word_select].u_obj);
+ const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj);
+
+ audiobusio_i2sout_obj_t *self = m_new_obj_with_finaliser(audiobusio_i2sout_obj_t);
+ self->base.type = &audiobusio_i2sout_type;
+ common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, args[ARG_left_justified].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+ #endif
+}
+
+#if CIRCUITPY_AUDIOBUSIO_I2SOUT
+
+//| def deinit(self) -> None:
+//| """Deinitialises the I2SOut and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_deinit(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiobusio_i2sout_deinit(self);
+ return mp_const_none;
+
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_deinit_obj, audiobusio_i2sout_deinit);
+
+STATIC void check_for_deinit(audiobusio_i2sout_obj_t *self) {
+ if (common_hal_audiobusio_i2sout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| def __enter__(self) -> I2SOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiobusio_i2sout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_i2sout___exit___obj, 4, 4, audiobusio_i2sout_obj___exit__);
+
+
+//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None:
+//| """Plays the sample once when loop=False and continuously when loop=True.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+//|
+//| The sample itself should consist of 8 bit or 16 bit samples."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audiobusio_i2sout_play(self, sample, args[ARG_loop].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiobusio_i2sout_play_obj, 1, audiobusio_i2sout_obj_play);
+
+//| def stop(self) -> None:
+//| """Stops playback."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_stop(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audiobusio_i2sout_stop(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_stop_obj, audiobusio_i2sout_obj_stop);
+
+//| playing: bool
+//| """True when the audio sample is being output. (read-only)"""
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_get_playing(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiobusio_i2sout_get_playing(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_get_playing_obj, audiobusio_i2sout_obj_get_playing);
+
+MP_PROPERTY_GETTER(audiobusio_i2sout_playing_obj,
+ (mp_obj_t)&audiobusio_i2sout_get_playing_obj);
+
+//| def pause(self) -> None:
+//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_pause(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (!common_hal_audiobusio_i2sout_get_playing(self)) {
+ mp_raise_RuntimeError(translate("Not playing"));
+ }
+ common_hal_audiobusio_i2sout_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_pause_obj, audiobusio_i2sout_obj_pause);
+
+//| def resume(self) -> None:
+//| """Resumes sample playback after :py:func:`pause`."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_resume(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (common_hal_audiobusio_i2sout_get_paused(self)) {
+ common_hal_audiobusio_i2sout_resume(self);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_resume_obj, audiobusio_i2sout_obj_resume);
+
+//| paused: bool
+//| """True when playback is paused. (read-only)"""
+//|
+STATIC mp_obj_t audiobusio_i2sout_obj_get_paused(mp_obj_t self_in) {
+ audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiobusio_i2sout_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_get_paused_obj, audiobusio_i2sout_obj_get_paused);
+
+MP_PROPERTY_GETTER(audiobusio_i2sout_paused_obj,
+ (mp_obj_t)&audiobusio_i2sout_get_paused_obj);
+#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT
+
+STATIC const mp_rom_map_elem_t audiobusio_i2sout_locals_dict_table[] = {
+ // Methods
+ #if CIRCUITPY_AUDIOBUSIO_I2SOUT
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiobusio_i2sout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_i2sout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_i2sout___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiobusio_i2sout_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiobusio_i2sout_stop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiobusio_i2sout_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiobusio_i2sout_resume_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiobusio_i2sout_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiobusio_i2sout_paused_obj) },
+ #endif // CIRCUITPY_AUDIOBUSIO_I2SOUT
+};
+STATIC MP_DEFINE_CONST_DICT(audiobusio_i2sout_locals_dict, audiobusio_i2sout_locals_dict_table);
+
+const mp_obj_type_t audiobusio_i2sout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2SOut,
+ .make_new = audiobusio_i2sout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audiobusio_i2sout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/audiobusio/I2SOut.h b/circuitpython/shared-bindings/audiobusio/I2SOut.h
new file mode 100644
index 0000000..64dcc3b
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/I2SOut.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_I2SOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_I2SOUT_H
+
+#include "common-hal/audiobusio/I2SOut.h"
+#include "common-hal/microcontroller/Pin.h"
+
+extern const mp_obj_type_t audiobusio_i2sout_type;
+
+// Some boards don't have the I2SOut pins available.
+#if CIRCUITPY_AUDIOBUSIO_I2SOUT
+
+void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
+ const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data,
+ bool left_justified);
+
+void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self);
+bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self);
+void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, mp_obj_t sample, bool loop);
+void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t *self);
+bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t *self);
+void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t *self);
+void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t *self);
+bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t *self);
+
+#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_I2SOUT_H
diff --git a/circuitpython/shared-bindings/audiobusio/PDMIn.c b/circuitpython/shared-bindings/audiobusio/PDMIn.c
new file mode 100644
index 0000000..aa810f2
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/PDMIn.c
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/mphal.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiobusio/PDMIn.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class PDMIn:
+//| """Record an input PDM audio stream"""
+//|
+//| def __init__(self, clock_pin: microcontroller.Pin, data_pin: microcontroller.Pin, *, sample_rate: int = 16000, bit_depth: int = 8, mono: bool = True, oversample: int = 64, startup_delay: float = 0.11) -> None:
+//| """Create a PDMIn object associated with the given pins. This allows you to
+//| record audio signals from the given pins. Individual ports may put further
+//| restrictions on the recording parameters. The overall sample rate is
+//| determined by `sample_rate` x ``oversample``, and the total must be 1MHz or
+//| higher, so `sample_rate` must be a minimum of 16000.
+//|
+//| :param ~microcontroller.Pin clock_pin: The pin to output the clock to
+//| :param ~microcontroller.Pin data_pin: The pin to read the data from
+//| :param int sample_rate: Target sample_rate of the resulting samples. Check `sample_rate` for actual value.
+//| Minimum sample_rate is about 16000 Hz.
+//| :param int bit_depth: Final number of bits per sample. Must be divisible by 8
+//| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise
+//| :param int oversample: Number of single bit samples to decimate into a final sample. Must be divisible by 8
+//| :param float startup_delay: seconds to wait after starting microphone clock
+//| to allow microphone to turn on. Most require only 0.01s; some require 0.1s. Longer is safer.
+//| Must be in range 0.0-1.0 seconds."""
+//|
+
+//| """Record 8-bit unsigned samples to buffer::
+//|
+//| import audiobusio
+//| import board
+//|
+//| # Prep a buffer to record into
+//| b = bytearray(200)
+//| with audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=16000) as mic:
+//| mic.record(b, len(b))
+//|
+//| Record 16-bit unsigned samples to buffer::
+//|
+//| import audiobusio
+//| import board
+//|
+//| # Prep a buffer to record into. The array interface doesn't allow for
+//| # constructing with a set size so we append to it until we have the size
+//| # we want.
+//| b = array.array("H")
+//| for i in range(200):
+//| b.append(0)
+//| with audiobusio.PDMIn(board.MICROPHONE_CLOCK, board.MICROPHONE_DATA, sample_rate=16000, bit_depth=16) as mic:
+//| mic.record(b, len(b))"""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ #if !CIRCUITPY_AUDIOBUSIO_PDMIN
+ mp_raise_NotImplementedError(translate("PDMIn not available"));
+ #else
+ enum { ARG_clock_pin, ARG_data_pin, ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_data_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_sample_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} },
+ { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = true} },
+ { MP_QSTR_oversample, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ { MP_QSTR_startup_delay, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ // Default microphone startup delay is 110msecs. Have seen mics that need 100 msecs plus a bit.
+ static const float STARTUP_DELAY_DEFAULT = 0.110F;
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock_pin = validate_obj_is_free_pin(args[ARG_clock_pin].u_obj);
+ const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj);
+
+ // create PDMIn object from the given pin
+ audiobusio_pdmin_obj_t *self = m_new_obj(audiobusio_pdmin_obj_t);
+ self->base.type = &audiobusio_pdmin_type;
+
+ uint32_t sample_rate = args[ARG_sample_rate].u_int;
+ uint8_t bit_depth = args[ARG_bit_depth].u_int;
+ if (bit_depth % 8 != 0) {
+ mp_raise_ValueError(translate("Bit depth must be multiple of 8."));
+ }
+ uint8_t oversample = args[ARG_oversample].u_int;
+ if (oversample % 8 != 0) {
+ mp_raise_ValueError(translate("Oversample must be multiple of 8."));
+ }
+ bool mono = args[ARG_mono].u_bool;
+
+ mp_float_t startup_delay = (args[ARG_startup_delay].u_obj == MP_OBJ_NULL)
+ ? (mp_float_t)STARTUP_DELAY_DEFAULT
+ : mp_obj_get_float(args[ARG_startup_delay].u_obj);
+ if (startup_delay < 0.0 || startup_delay > 1.0) {
+ mp_raise_ValueError(translate("Microphone startup delay must be in range 0.0 to 1.0"));
+ }
+
+ common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, sample_rate,
+ bit_depth, mono, oversample);
+
+ // Wait for the microphone to start up. Some start in 10 msecs; some take as much as 100 msecs.
+ mp_hal_delay_ms(startup_delay * 1000);
+
+ return MP_OBJ_FROM_PTR(self);
+ #endif
+}
+
+#if CIRCUITPY_AUDIOBUSIO_PDMIN
+//| def deinit(self) -> None:
+//| """Deinitialises the PDMIn and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_pdmin_deinit(mp_obj_t self_in) {
+ audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiobusio_pdmin_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_pdmin_deinit_obj, audiobusio_pdmin_deinit);
+
+STATIC void check_for_deinit(audiobusio_pdmin_obj_t *self) {
+ if (common_hal_audiobusio_pdmin_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| def __enter__(self) -> PDMIn:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_pdmin_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiobusio_pdmin_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4, audiobusio_pdmin_obj___exit__);
+
+
+//| def record(self, destination: WriteableBuffer, destination_length: int) -> None:
+//| """Records destination_length bytes of samples to destination. This is
+//| blocking.
+//|
+//| An IOError may be raised when the destination is too slow to record the
+//| audio at the given rate. For internal flash, writing all 1s to the file
+//| before recording is recommended to speed up writes.
+//|
+//| :return: The number of samples recorded. If this is less than ``destination_length``,
+//| some samples were missed due to processing time."""
+//| ...
+//|
+STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) {
+ audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj);
+ check_for_deinit(self);
+ if (!mp_obj_is_small_int(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) {
+ mp_raise_TypeError(translate("destination_length must be an int >= 0"));
+ }
+ uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length);
+
+ mp_buffer_info_t bufinfo;
+ if (mp_obj_is_type(destination, &mp_type_fileio)) {
+ mp_raise_NotImplementedError(translate("Cannot record to a file"));
+ } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) {
+ if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) {
+ mp_raise_ValueError(translate("Destination capacity is smaller than destination_length."));
+ }
+ uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self);
+ if (bufinfo.typecode != 'H' && bit_depth == 16) {
+ mp_raise_ValueError(translate("destination buffer must be an array of type 'H' for bit_depth = 16"));
+ } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) {
+ mp_raise_ValueError(translate("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8"));
+ }
+ // length is the buffer length in slots, not bytes.
+ uint32_t length_written =
+ common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length);
+ return MP_OBJ_NEW_SMALL_INT(length_written);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(audiobusio_pdmin_record_obj, audiobusio_pdmin_obj_record);
+
+//| sample_rate: int
+//| """The actual sample_rate of the recording. This may not match the constructed
+//| sample rate due to internal clock limitations."""
+//|
+STATIC mp_obj_t audiobusio_pdmin_obj_get_sample_rate(mp_obj_t self_in) {
+ audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiobusio_pdmin_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_pdmin_get_sample_rate_obj, audiobusio_pdmin_obj_get_sample_rate);
+
+MP_PROPERTY_GETTER(audiobusio_pdmin_sample_rate_obj,
+ (mp_obj_t)&audiobusio_pdmin_get_sample_rate_obj);
+
+STATIC const mp_rom_map_elem_t audiobusio_pdmin_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_pdmin_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_pdmin___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audiobusio_pdmin_record_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiobusio_pdmin_sample_rate_obj) }
+};
+STATIC MP_DEFINE_CONST_DICT(audiobusio_pdmin_locals_dict, audiobusio_pdmin_locals_dict_table);
+#endif
+
+const mp_obj_type_t audiobusio_pdmin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PDMIn,
+ .make_new = audiobusio_pdmin_make_new,
+ #if CIRCUITPY_AUDIOBUSIO_PDMIN
+ .locals_dict = (mp_obj_dict_t *)&audiobusio_pdmin_locals_dict,
+ #endif
+};
diff --git a/circuitpython/shared-bindings/audiobusio/PDMIn.h b/circuitpython/shared-bindings/audiobusio/PDMIn.h
new file mode 100644
index 0000000..0516bce
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/PDMIn.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_AUDIOOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_AUDIOOUT_H
+
+#include "common-hal/audiobusio/PDMIn.h"
+#include "common-hal/microcontroller/Pin.h"
+#include "extmod/vfs_fat.h"
+
+extern const mp_obj_type_t audiobusio_pdmin_type;
+
+#if CIRCUITPY_AUDIOBUSIO_PDMIN
+void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self,
+ const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin,
+ uint32_t sample_rate, uint8_t bit_depth, bool mono, uint8_t oversample);
+void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t *self);
+bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t *self);
+uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self,
+ uint16_t *buffer, uint32_t length);
+uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t *self);
+uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t *self);
+// TODO(tannewt): Add record to file
+#endif
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_AUDIOOUT_H
diff --git a/circuitpython/shared-bindings/audiobusio/__init__.c b/circuitpython/shared-bindings/audiobusio/__init__.c
new file mode 100644
index 0000000..34ce9ef
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/__init__.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiobusio/__init__.h"
+#include "shared-bindings/audiobusio/I2SOut.h"
+#include "shared-bindings/audiobusio/PDMIn.h"
+
+//| """Support for audio input and output over digital buses
+//|
+//| The `audiobusio` module contains classes to provide access to audio IO
+//| over digital buses. These protocols are used to communicate audio to other
+//| chips in the same circuit. It doesn't include audio interconnect protocols
+//| such as S/PDIF.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a
+//| context manager."""
+//|
+
+STATIC const mp_rom_map_elem_t audiobusio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiobusio) },
+ { MP_ROM_QSTR(MP_QSTR_I2SOut), MP_ROM_PTR(&audiobusio_i2sout_type) },
+ { MP_ROM_QSTR(MP_QSTR_PDMIn), MP_ROM_PTR(&audiobusio_pdmin_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiobusio_module_globals, audiobusio_module_globals_table);
+
+const mp_obj_module_t audiobusio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audiobusio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audiobusio, audiobusio_module, CIRCUITPY_AUDIOBUSIO);
diff --git a/circuitpython/shared-bindings/audiobusio/__init__.h b/circuitpython/shared-bindings/audiobusio/__init__.h
new file mode 100644
index 0000000..f7a0c3c
--- /dev/null
+++ b/circuitpython/shared-bindings/audiobusio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO___INIT___H
diff --git a/circuitpython/shared-bindings/audiocore/RawSample.c b/circuitpython/shared-bindings/audiocore/RawSample.c
new file mode 100644
index 0000000..82c0245
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/RawSample.c
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "supervisor/shared/translate.h"
+
+//| class RawSample:
+//| """A raw audio sample buffer in memory"""
+//|
+//| def __init__(self, buffer: ReadableBuffer, *, channel_count: int = 1, sample_rate: int = 8000) -> None:
+//| """Create a RawSample based on the given buffer of signed values. If channel_count is more than
+//| 1 then each channel's samples should alternate. In other words, for a two channel buffer, the
+//| first sample will be for channel 1, the second sample will be for channel two, the third for
+//| channel 1 and so on.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer buffer: A buffer with samples
+//| :param int channel_count: The number of channels in the buffer
+//| :param int sample_rate: The desired playback sample rate
+//|
+//| Simple 8ksps 440 Hz sin wave::
+//|
+//| import audiocore
+//| import audioio
+//| import board
+//| import array
+//| import time
+//| import math
+//|
+//| # Generate one period of sine wav.
+//| length = 8000 // 440
+//| sine_wave = array.array("h", [0] * length)
+//| for i in range(length):
+//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15))
+//|
+//| dac = audioio.AudioOut(board.SPEAKER)
+//| sine_wave = audiocore.RawSample(sine_wave)
+//| dac.play(sine_wave, loop=True)
+//| time.sleep(1)
+//| dac.stop()"""
+//| ...
+//|
+STATIC mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_buffer, ARG_channel_count, ARG_sample_rate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } },
+ { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ audioio_rawsample_obj_t *self = m_new_obj(audioio_rawsample_obj_t);
+ self->base.type = &audioio_rawsample_type;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+ uint8_t bytes_per_sample = 1;
+ bool signed_samples = bufinfo.typecode == 'b' || bufinfo.typecode == 'h';
+ if (bufinfo.typecode == 'h' || bufinfo.typecode == 'H') {
+ bytes_per_sample = 2;
+ } else if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) {
+ mp_raise_ValueError(translate("sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or 'B'"));
+ }
+ common_hal_audioio_rawsample_construct(self, ((uint8_t *)bufinfo.buf), bufinfo.len,
+ bytes_per_sample, signed_samples, args[ARG_channel_count].u_int,
+ args[ARG_sample_rate].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the RawSample and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) {
+ audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audioio_rawsample_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit);
+
+STATIC void check_for_deinit(audioio_rawsample_obj_t *self) {
+ if (common_hal_audioio_rawsample_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> RawSample:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audioio_rawsample_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audioio_rawsample_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4, audioio_rawsample_obj___exit__);
+
+//| sample_rate: Optional[int]
+//| """32 bit value that dictates how quickly samples are played in Hertz (cycles per second).
+//| When the sample is looped, this can change the pitch output without changing the underlying
+//| sample. This will not change the sample rate of any active playback. Call ``play`` again to
+//| change it."""
+//|
+STATIC mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) {
+ audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate);
+
+STATIC mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
+ audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate);
+
+MP_PROPERTY_GETSET(audioio_rawsample_sample_rate_obj,
+ (mp_obj_t)&audioio_rawsample_get_sample_rate_obj,
+ (mp_obj_t)&audioio_rawsample_set_sample_rate_obj);
+
+STATIC const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_rawsample_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table);
+
+STATIC const audiosample_p_t audioio_rawsample_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
+ .sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_rawsample_get_sample_rate,
+ .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_rawsample_get_bits_per_sample,
+ .channel_count = (audiosample_channel_count_fun)common_hal_audioio_rawsample_get_channel_count,
+ .reset_buffer = (audiosample_reset_buffer_fun)audioio_rawsample_reset_buffer,
+ .get_buffer = (audiosample_get_buffer_fun)audioio_rawsample_get_buffer,
+ .get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_rawsample_get_buffer_structure,
+};
+
+const mp_obj_type_t audioio_rawsample_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RawSample,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = audioio_rawsample_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audioio_rawsample_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &audioio_rawsample_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/audiocore/RawSample.h b/circuitpython/shared-bindings/audiocore/RawSample.h
new file mode 100644
index 0000000..71056f3
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/RawSample.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H
+
+#include "shared-module/audiocore/RawSample.h"
+
+extern const mp_obj_type_t audioio_rawsample_type;
+
+void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t *self,
+ uint8_t *buffer, uint32_t len, uint8_t bytes_per_sample, bool samples_signed,
+ uint8_t channel_count, uint32_t sample_rate);
+
+void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t *self);
+bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t *self);
+uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t *self);
+uint8_t common_hal_audioio_rawsample_get_bits_per_sample(audioio_rawsample_obj_t *self);
+uint8_t common_hal_audioio_rawsample_get_channel_count(audioio_rawsample_obj_t *self);
+void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t *self, uint32_t sample_rate);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H
diff --git a/circuitpython/shared-bindings/audiocore/WaveFile.c b/circuitpython/shared-bindings/audiocore/WaveFile.c
new file mode 100644
index 0000000..285bd7c
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/WaveFile.c
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/audiocore/WaveFile.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class WaveFile:
+//| """Load a wave file for audio playback
+//|
+//| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must
+//| be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating
+//| an internal buffer, which can prevent memory fragmentation."""
+//|
+//| def __init__(self, file: typing.BinaryIO, buffer: WriteableBuffer) -> None:
+//| """Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
+//|
+//| :param typing.BinaryIO file: Already opened wave file
+//| :param ~circuitpython_typing.WriteableBuffer buffer: Optional pre-allocated buffer,
+//| that will be split in half and used for double-buffering of the data.
+//| The buffer must be 8 to 1024 bytes long.
+//| If not provided, two 256 byte buffers are initially allocated internally.
+//|
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audiocore
+//| import audioio
+//| import digitalio
+//|
+//| # Required for CircuitPlayground Express
+//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+//| speaker_enable.switch_to_output(value=True)
+//|
+//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
+//| wav = audiocore.WaveFile(data)
+//| a = audioio.AudioOut(board.A0)
+//|
+//| print("playing")
+//| a.play(wav)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 2, false);
+
+ audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t);
+ self->base.type = &audioio_wavefile_type;
+ if (!mp_obj_is_type(args[0], &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+ uint8_t *buffer = NULL;
+ size_t buffer_size = 0;
+ if (n_args >= 2) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ buffer = bufinfo.buf;
+ buffer_size = mp_arg_validate_length_range(bufinfo.len, 8, 1024, MP_QSTR_buffer);
+ }
+ common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0]),
+ buffer, buffer_size);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the WaveFile and releases all memory resources for reuse."""
+//| ...
+STATIC mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) {
+ audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audioio_wavefile_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit);
+
+STATIC void check_for_deinit(audioio_wavefile_obj_t *self) {
+ if (common_hal_audioio_wavefile_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> WaveFile:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audioio_wavefile_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audioio_wavefile_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4, audioio_wavefile_obj___exit__);
+
+//| sample_rate: int
+//| """32 bit value that dictates how quickly samples are loaded into the DAC
+//| in Hertz (cycles per second). When the sample is looped, this can change
+//| the pitch output without changing the underlying sample."""
+//|
+STATIC mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) {
+ audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate);
+
+STATIC mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
+ audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate);
+
+MP_PROPERTY_GETSET(audioio_wavefile_sample_rate_obj,
+ (mp_obj_t)&audioio_wavefile_get_sample_rate_obj,
+ (mp_obj_t)&audioio_wavefile_set_sample_rate_obj);
+
+//| bits_per_sample: int
+//| """Bits per sample. (read only)"""
+//|
+STATIC mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) {
+ audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample);
+
+MP_PROPERTY_GETTER(audioio_wavefile_bits_per_sample_obj,
+ (mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj);
+//| channel_count: int
+//| """Number of audio channels. (read only)"""
+//|
+STATIC mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) {
+ audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count);
+
+MP_PROPERTY_GETTER(audioio_wavefile_channel_count_obj,
+ (mp_obj_t)&audioio_wavefile_get_channel_count_obj);
+
+
+STATIC const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_wavefile_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) },
+ { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table);
+
+STATIC const audiosample_p_t audioio_wavefile_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
+ .sample_rate = (audiosample_sample_rate_fun)common_hal_audioio_wavefile_get_sample_rate,
+ .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audioio_wavefile_get_bits_per_sample,
+ .channel_count = (audiosample_channel_count_fun)common_hal_audioio_wavefile_get_channel_count,
+ .reset_buffer = (audiosample_reset_buffer_fun)audioio_wavefile_reset_buffer,
+ .get_buffer = (audiosample_get_buffer_fun)audioio_wavefile_get_buffer,
+ .get_buffer_structure = (audiosample_get_buffer_structure_fun)audioio_wavefile_get_buffer_structure,
+};
+
+
+const mp_obj_type_t audioio_wavefile_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WaveFile,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = audioio_wavefile_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audioio_wavefile_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &audioio_wavefile_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/audiocore/WaveFile.h b/circuitpython/shared-bindings/audiocore/WaveFile.h
new file mode 100644
index 0000000..29140b4
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/WaveFile.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H
+
+#include "py/obj.h"
+#include "extmod/vfs_fat.h"
+
+#include "shared-module/audiocore/WaveFile.h"
+
+extern const mp_obj_type_t audioio_wavefile_type;
+
+void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t *self,
+ pyb_file_obj_t *file, uint8_t *buffer, size_t buffer_size);
+
+void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t *self);
+bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t *self);
+uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t *self);
+void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t *self, uint32_t sample_rate);
+uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t *self);
+uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H
diff --git a/circuitpython/shared-bindings/audiocore/__init__.c b/circuitpython/shared-bindings/audiocore/__init__.c
new file mode 100644
index 0000000..f03c64c
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/__init__.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/__init__.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/audiocore/WaveFile.h"
+// #include "shared-bindings/audiomixer/Mixer.h"
+
+//| """Support for audio samples"""
+//|
+
+STATIC const mp_rom_map_elem_t audiocore_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiocore) },
+ { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) },
+ { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiocore_module_globals, audiocore_module_globals_table);
+
+const mp_obj_module_t audiocore_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audiocore_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audiocore, audiocore_module, CIRCUITPY_AUDIOCORE);
diff --git a/circuitpython/shared-bindings/audiocore/__init__.h b/circuitpython/shared-bindings/audiocore/__init__.h
new file mode 100644
index 0000000..02437cd
--- /dev/null
+++ b/circuitpython/shared-bindings/audiocore/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H
diff --git a/circuitpython/shared-bindings/audioio/AudioOut.c b/circuitpython/shared-bindings/audioio/AudioOut.c
new file mode 100644
index 0000000..0b4ed7b
--- /dev/null
+++ b/circuitpython/shared-bindings/audioio/AudioOut.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audioio/AudioOut.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class AudioOut:
+//| """Output an analog audio signal"""
+//|
+//| def __init__(self, left_channel: microcontroller.Pin, *, right_channel: Optional[microcontroller.Pin] = None, quiescent_value: int = 0x8000) -> None:
+//| """Create a AudioOut object associated with the given pin(s). This allows you to
+//| play audio signals out on the given pin(s).
+//|
+//| :param ~microcontroller.Pin left_channel: The pin to output the left channel to
+//| :param ~microcontroller.Pin right_channel: The pin to output the right channel to
+//| :param int quiescent_value: The output value when no signal is present. Samples should start
+//| and end with this value to prevent audible popping.
+//|
+//| Simple 8ksps 440 Hz sin wave::
+//|
+//| import audiocore
+//| import audioio
+//| import board
+//| import array
+//| import time
+//| import math
+//|
+//| # Generate one period of sine wav.
+//| length = 8000 // 440
+//| sine_wave = array.array("H", [0] * length)
+//| for i in range(length):
+//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+//|
+//| dac = audioio.AudioOut(board.SPEAKER)
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+//| dac.play(sine_wave, loop=True)
+//| time.sleep(1)
+//| dac.stop()
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audioio
+//| import digitalio
+//|
+//| # Required for CircuitPlayground Express
+//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+//| speaker_enable.switch_to_output(value=True)
+//|
+//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
+//| wav = audiocore.WaveFile(data)
+//| a = audioio.AudioOut(board.A0)
+//|
+//| print("playing")
+//| a.play(wav)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_left_channel, ARG_right_channel, ARG_quiescent_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_left_channel, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_right_channel, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = mp_const_none} },
+ { MP_QSTR_quiescent_value, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x8000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *left_channel_pin = validate_obj_is_free_pin(args[ARG_left_channel].u_obj);
+ const mcu_pin_obj_t *right_channel_pin = validate_obj_is_free_pin_or_none(args[ARG_right_channel].u_obj);
+
+ // create AudioOut object from the given pin
+ audioio_audioout_obj_t *self = m_new_obj(audioio_audioout_obj_t);
+ self->base.type = &audioio_audioout_type;
+ common_hal_audioio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the AudioOut and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_deinit(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audioio_audioout_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_deinit_obj, audioio_audioout_deinit);
+
+STATIC void check_for_deinit(audioio_audioout_obj_t *self) {
+ if (common_hal_audioio_audioout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| def __enter__(self) -> AudioOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audioio_audioout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_audioout___exit___obj, 4, 4, audioio_audioout_obj___exit__);
+
+
+//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None:
+//| """Plays the sample once when loop=False and continuously when loop=True.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+//|
+//| The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
+//| resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit
+//| DAC that ignores the lowest 6 bits when playing 16 bit samples."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audioio_audioout_play(self, sample, args[ARG_loop].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audioio_audioout_play_obj, 1, audioio_audioout_obj_play);
+
+//| def stop(self) -> None:
+//| """Stops playback and resets to the start of the sample."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_obj_stop(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audioio_audioout_stop(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_stop_obj, audioio_audioout_obj_stop);
+
+//| playing: bool
+//| """True when an audio sample is being output even if `paused`. (read-only)"""
+//|
+STATIC mp_obj_t audioio_audioout_obj_get_playing(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audioio_audioout_get_playing(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_playing_obj, audioio_audioout_obj_get_playing);
+
+MP_PROPERTY_GETTER(audioio_audioout_playing_obj,
+ (mp_obj_t)&audioio_audioout_get_playing_obj);
+
+//| def pause(self) -> None:
+//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_obj_pause(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (!common_hal_audioio_audioout_get_playing(self)) {
+ mp_raise_RuntimeError(translate("Not playing"));
+ }
+ common_hal_audioio_audioout_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_pause_obj, audioio_audioout_obj_pause);
+
+//| def resume(self) -> None:
+//| """Resumes sample playback after :py:func:`pause`."""
+//| ...
+//|
+STATIC mp_obj_t audioio_audioout_obj_resume(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (common_hal_audioio_audioout_get_paused(self)) {
+ common_hal_audioio_audioout_resume(self);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_resume_obj, audioio_audioout_obj_resume);
+
+//| paused: bool
+//| """True when playback is paused. (read-only)"""
+//|
+STATIC mp_obj_t audioio_audioout_obj_get_paused(mp_obj_t self_in) {
+ audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audioio_audioout_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_paused_obj, audioio_audioout_obj_get_paused);
+
+MP_PROPERTY_GETTER(audioio_audioout_paused_obj,
+ (mp_obj_t)&audioio_audioout_get_paused_obj);
+
+STATIC const mp_rom_map_elem_t audioio_audioout_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_audioout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_audioout___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_audioout_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_audioout_stop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audioio_audioout_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audioio_audioout_resume_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_audioout_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audioio_audioout_paused_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audioio_audioout_locals_dict, audioio_audioout_locals_dict_table);
+
+const mp_obj_type_t audioio_audioout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_AudioOut,
+ .make_new = audioio_audioout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audioio_audioout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/audioio/AudioOut.h b/circuitpython/shared-bindings/audioio/AudioOut.h
new file mode 100644
index 0000000..163d784
--- /dev/null
+++ b/circuitpython/shared-bindings/audioio/AudioOut.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H
+
+#include "common-hal/audioio/AudioOut.h"
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+
+extern const mp_obj_type_t audioio_audioout_type;
+
+// left_channel will always be non-NULL but right_channel may be for mono output.
+void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self,
+ const mcu_pin_obj_t *left_channel, const mcu_pin_obj_t *right_channel, uint16_t default_value);
+
+void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self);
+bool common_hal_audioio_audioout_deinited(audioio_audioout_obj_t *self);
+void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, mp_obj_t sample, bool loop);
+void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self);
+bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t *self);
+void common_hal_audioio_audioout_pause(audioio_audioout_obj_t *self);
+void common_hal_audioio_audioout_resume(audioio_audioout_obj_t *self);
+bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H
diff --git a/circuitpython/shared-bindings/audioio/__init__.c b/circuitpython/shared-bindings/audioio/__init__.c
new file mode 100644
index 0000000..9f8411f
--- /dev/null
+++ b/circuitpython/shared-bindings/audioio/__init__.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audioio/__init__.h"
+#include "shared-bindings/audioio/AudioOut.h"
+
+//| """Support for audio output
+//|
+//| The `audioio` module contains classes to provide access to audio IO.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| Since CircuitPython 5, `RawSample` and `WaveFile` are moved
+//| to :mod:`audiocore`, and `Mixer` is moved to :mod:`audiomixer`.
+//|
+//| For compatibility with CircuitPython 4.x, some builds allow the items in
+//| `audiocore` to be imported from `audioio`. This will be removed for all
+//| boards in a future build of CircuitPython."""
+//|
+
+STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) },
+ { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audioio_module_globals, audioio_module_globals_table);
+
+const mp_obj_module_t audioio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audioio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audioio, audioio_module, CIRCUITPY_AUDIOIO);
diff --git a/circuitpython/shared-bindings/audioio/__init__.h b/circuitpython/shared-bindings/audioio/__init__.h
new file mode 100644
index 0000000..e4b7067
--- /dev/null
+++ b/circuitpython/shared-bindings/audioio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H
diff --git a/circuitpython/shared-bindings/audiomixer/Mixer.c b/circuitpython/shared-bindings/audiomixer/Mixer.c
new file mode 100644
index 0000000..a165435
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/Mixer.c
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "shared-bindings/audiomixer/Mixer.h"
+#include "shared-bindings/audiomixer/MixerVoice.h"
+#include "shared-module/audiomixer/MixerVoice.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Mixer:
+//| """Mixes one or more audio samples together into one sample."""
+//|
+//| def __init__(self, voice_count: int = 2, buffer_size: int = 1024, channel_count: int = 2, bits_per_sample: int = 16, samples_signed: bool = True, sample_rate: int = 8000) -> None:
+//| """Create a Mixer object that can mix multiple channels with the same sample rate.
+//| Samples are accessed and controlled with the mixer's `audiomixer.MixerVoice` objects.
+//|
+//| :param int voice_count: The maximum number of voices to mix
+//| :param int buffer_size: The total size in bytes of the buffers to mix into
+//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo.
+//| :param int bits_per_sample: The bits per sample of the samples being played
+//| :param bool samples_signed: Samples are signed (True) or unsigned (False)
+//| :param int sample_rate: The sample rate to be used for all samples
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audioio
+//| import audiocore
+//| import audiomixer
+//| import digitalio
+//|
+//| a = audioio.AudioOut(board.A0)
+//| music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb"))
+//| drum = audiocore.WaveFile(open("drum.wav", "rb"))
+//| mixer = audiomixer.Mixer(voice_count=2, sample_rate=16000, channel_count=1,
+//| bits_per_sample=16, samples_signed=True)
+//|
+//| print("playing")
+//| # Have AudioOut play our Mixer source
+//| a.play(mixer)
+//| # Play the first sample voice
+//| mixer.voice[0].play(music)
+//| while mixer.playing:
+//| # Play the second sample voice
+//| mixer.voice[1].play(drum)
+//| time.sleep(1)
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} },
+ { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} },
+ { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} },
+ { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} },
+ { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t voice_count = args[ARG_voice_count].u_int;
+ if (voice_count < 1 || voice_count > 255) {
+ mp_raise_ValueError(translate("Invalid voice count"));
+ }
+
+ mp_int_t channel_count = args[ARG_channel_count].u_int;
+ if (channel_count < 1 || channel_count > 2) {
+ mp_raise_ValueError(translate("Invalid channel count"));
+ }
+ mp_int_t sample_rate = args[ARG_sample_rate].u_int;
+ if (sample_rate < 1) {
+ mp_raise_ValueError(translate("Sample rate must be positive"));
+ }
+ mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int;
+ if (bits_per_sample != 8 && bits_per_sample != 16) {
+ mp_raise_ValueError(translate("bits_per_sample must be 8 or 16"));
+ }
+ audiomixer_mixer_obj_t *self = m_new_obj_var(audiomixer_mixer_obj_t, mp_obj_t, voice_count);
+ self->base.type = &audiomixer_mixer_type;
+ common_hal_audiomixer_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate);
+
+ for (int v = 0; v < voice_count; v++) {
+ self->voice[v] = audiomixer_mixervoice_type.make_new(&audiomixer_mixervoice_type, 0, 0, NULL);
+ common_hal_audiomixer_mixervoice_set_parent(self->voice[v], self);
+ }
+ self->voice_tuple = mp_obj_new_tuple(self->voice_count, self->voice);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the Mixer and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixer_deinit(mp_obj_t self_in) {
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiomixer_mixer_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_deinit_obj, audiomixer_mixer_deinit);
+
+STATIC void check_for_deinit(audiomixer_mixer_obj_t *self) {
+ if (common_hal_audiomixer_mixer_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> Mixer:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiomixer_mixer_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomixer_mixer___exit___obj, 4, 4, audiomixer_mixer_obj___exit__);
+
+//| playing: bool
+//| """True when any voice is being output. (read-only)"""
+//|
+STATIC mp_obj_t audiomixer_mixer_obj_get_playing(mp_obj_t self_in) {
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiomixer_mixer_get_playing(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_playing_obj, audiomixer_mixer_obj_get_playing);
+
+MP_PROPERTY_GETTER(audiomixer_mixer_playing_obj,
+ (mp_obj_t)&audiomixer_mixer_get_playing_obj);
+
+//| sample_rate: int
+//| """32 bit value that dictates how quickly samples are played in Hertz (cycles per second)."""
+//|
+STATIC mp_obj_t audiomixer_mixer_obj_get_sample_rate(mp_obj_t self_in) {
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiomixer_mixer_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_sample_rate_obj, audiomixer_mixer_obj_get_sample_rate);
+
+MP_PROPERTY_GETTER(audiomixer_mixer_sample_rate_obj,
+ (mp_obj_t)&audiomixer_mixer_get_sample_rate_obj);
+
+//| voice: Tuple[MixerVoice, ...]
+//| """A tuple of the mixer's `audiomixer.MixerVoice` object(s).
+//|
+//| .. code-block:: python
+//|
+//| >>> mixer.voice
+//| (<MixerVoice>,)"""
+STATIC mp_obj_t audiomixer_mixer_obj_get_voice(mp_obj_t self_in) {
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return self->voice_tuple;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_voice_obj, audiomixer_mixer_obj_get_voice);
+
+MP_PROPERTY_GETTER(audiomixer_mixer_voice_obj,
+ (mp_obj_t)&audiomixer_mixer_get_voice_obj);
+
+//| def play(self, sample: circuitpython_typing.AudioSample, *, voice: int = 0, loop: bool = False) -> None:
+//| """Plays the sample once when loop=False and continuously when loop=True.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+//|
+//| The sample must match the Mixer's encoding settings given in the constructor."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_voice, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t v = args[ARG_voice].u_int;
+ if (v > (self->voice_count - 1)) {
+ mp_raise_ValueError(translate("Invalid voice"));
+ }
+ audiomixer_mixervoice_obj_t *voice = MP_OBJ_TO_PTR(self->voice[v]);
+ mp_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audiomixer_mixervoice_play(voice, sample, args[ARG_loop].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixer_play_obj, 1, audiomixer_mixer_obj_play);
+
+//| def stop_voice(self, voice: int = 0) -> None:
+//| """Stops playback of the sample on the given voice."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_voice };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} },
+ };
+ audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t v = args[ARG_voice].u_int;
+ if (v > (self->voice_count - 1)) {
+ mp_raise_ValueError(translate("Invalid voice"));
+ }
+ audiomixer_mixervoice_obj_t *voice = MP_OBJ_TO_PTR(self->voice[v]);
+ common_hal_audiomixer_mixervoice_stop(voice);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixer_stop_voice_obj, 1, audiomixer_mixer_obj_stop_voice);
+
+
+STATIC const mp_rom_map_elem_t audiomixer_mixer_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiomixer_mixer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomixer_mixer___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiomixer_mixer_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audiomixer_mixer_stop_voice_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixer_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomixer_mixer_sample_rate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audiomixer_mixer_voice_obj) }
+};
+STATIC MP_DEFINE_CONST_DICT(audiomixer_mixer_locals_dict, audiomixer_mixer_locals_dict_table);
+
+STATIC const audiosample_p_t audiomixer_mixer_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
+ .sample_rate = (audiosample_sample_rate_fun)common_hal_audiomixer_mixer_get_sample_rate,
+ .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiomixer_mixer_get_bits_per_sample,
+ .channel_count = (audiosample_channel_count_fun)common_hal_audiomixer_mixer_get_channel_count,
+ .reset_buffer = (audiosample_reset_buffer_fun)audiomixer_mixer_reset_buffer,
+ .get_buffer = (audiosample_get_buffer_fun)audiomixer_mixer_get_buffer,
+ .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiomixer_mixer_get_buffer_structure,
+};
+
+const mp_obj_type_t audiomixer_mixer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Mixer,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = audiomixer_mixer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audiomixer_mixer_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &audiomixer_mixer_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/audiomixer/Mixer.h b/circuitpython/shared-bindings/audiomixer/Mixer.h
new file mode 100644
index 0000000..88592a1
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/Mixer.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-module/audiomixer/Mixer.h"
+#include "shared-bindings/audiocore/RawSample.h"
+
+extern const mp_obj_type_t audiomixer_mixer_type;
+extern const mp_obj_type_t audiomixer_mixervoice_type;
+
+void common_hal_audiomixer_mixer_construct(audiomixer_mixer_obj_t *self,
+ uint8_t voice_count,
+ uint32_t buffer_size,
+ uint8_t bits_per_sample,
+ bool samples_signed,
+ uint8_t channel_count,
+ uint32_t sample_rate);
+
+void common_hal_audiomixer_mixer_deinit(audiomixer_mixer_obj_t *self);
+bool common_hal_audiomixer_mixer_deinited(audiomixer_mixer_obj_t *self);
+
+bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t *self);
+uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t *self);
+uint8_t common_hal_audiomixer_mixer_get_channel_count(audiomixer_mixer_obj_t *self);
+uint8_t common_hal_audiomixer_mixer_get_bits_per_sample(audiomixer_mixer_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H
diff --git a/circuitpython/shared-bindings/audiomixer/MixerVoice.c b/circuitpython/shared-bindings/audiomixer/MixerVoice.c
new file mode 100644
index 0000000..f02b952
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/MixerVoice.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 DeanM for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "shared-bindings/audiomixer/Mixer.h"
+#include "shared-bindings/audiomixer/MixerVoice.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class MixerVoice:
+//| """Voice objects used with Mixer
+//|
+//| Used to access and control samples with `audiomixer.Mixer`."""
+//|
+//| def __init__(self) -> None:
+//| """MixerVoice instance object(s) created by `audiomixer.Mixer`."""
+//| ...
+//|
+// TODO: support mono or stereo voices
+STATIC mp_obj_t audiomixer_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ audiomixer_mixervoice_obj_t *self = m_new_obj(audiomixer_mixervoice_obj_t);
+ self->base.type = &audiomixer_mixervoice_type;
+
+ common_hal_audiomixer_mixervoice_construct(self);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None:
+//| """Plays the sample once when ``loop=False``, and continuously when ``loop=True``.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+//|
+//| The sample must match the `audiomixer.Mixer`'s encoding settings given in the constructor."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audiomixer_mixervoice_play(self, sample, args[ARG_loop].u_bool);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_play_obj, 1, audiomixer_mixervoice_obj_play);
+
+//| def stop(self) -> None:
+//| """Stops playback of the sample on this voice."""
+//| ...
+//|
+STATIC mp_obj_t audiomixer_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_voice };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} },
+ };
+ audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ common_hal_audiomixer_mixervoice_stop(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_stop_obj, 1, audiomixer_mixervoice_obj_stop);
+
+//| level: float
+//| """The volume level of a voice, as a floating point number between 0 and 1."""
+//|
+STATIC mp_obj_t audiomixer_mixervoice_obj_get_level(mp_obj_t self_in) {
+ return mp_obj_new_float(common_hal_audiomixer_mixervoice_get_level(self_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixervoice_get_level_obj, audiomixer_mixervoice_obj_get_level);
+
+STATIC mp_obj_t audiomixer_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_level };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ };
+ audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ float level = mp_obj_get_float(args[ARG_level].u_obj);
+
+ if (level > 1 || level < 0) {
+ mp_raise_ValueError(translate("level must be between 0 and 1"));
+ }
+
+ common_hal_audiomixer_mixervoice_set_level(self, level);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_set_level_obj, 1, audiomixer_mixervoice_obj_set_level);
+
+MP_PROPERTY_GETSET(audiomixer_mixervoice_level_obj,
+ (mp_obj_t)&audiomixer_mixervoice_get_level_obj,
+ (mp_obj_t)&audiomixer_mixervoice_set_level_obj);
+
+//| playing: bool
+//| """True when this voice is being output. (read-only)"""
+//|
+
+STATIC mp_obj_t audiomixer_mixervoice_obj_get_playing(mp_obj_t self_in) {
+ audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_audiomixer_mixervoice_get_playing(self));
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixervoice_get_playing_obj, audiomixer_mixervoice_obj_get_playing);
+
+MP_PROPERTY_GETTER(audiomixer_mixervoice_playing_obj,
+ (mp_obj_t)&audiomixer_mixervoice_get_playing_obj);
+
+STATIC const mp_rom_map_elem_t audiomixer_mixervoice_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiomixer_mixervoice_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiomixer_mixervoice_stop_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixervoice_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audiomixer_mixervoice_level_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audiomixer_mixervoice_locals_dict, audiomixer_mixervoice_locals_dict_table);
+
+const mp_obj_type_t audiomixer_mixervoice_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_MixerVoice,
+ .make_new = audiomixer_mixervoice_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audiomixer_mixervoice_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/audiomixer/MixerVoice.h b/circuitpython/shared-bindings/audiomixer/MixerVoice.h
new file mode 100644
index 0000000..bce4632
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/MixerVoice.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 DeanM for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_
+#define SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+
+#include "shared-module/audiomixer/MixerVoice.h"
+#include "shared-module/audiomixer/Mixer.h"
+
+extern const mp_obj_type_t audiomixer_mixer_type;
+extern const mp_obj_type_t audiomixer_mixervoice_type;
+
+void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self);
+void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *self, audiomixer_mixer_obj_t *parent);
+void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop);
+void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t *self);
+float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self);
+void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t *self, float gain);
+
+bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t *self);
+
+#endif /* SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_ */
diff --git a/circuitpython/shared-bindings/audiomixer/__init__.c b/circuitpython/shared-bindings/audiomixer/__init__.c
new file mode 100644
index 0000000..a29d4f1
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/__init__.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Michael Schroeder
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiomixer/Mixer.h"
+
+//| """Support for audio mixing"""
+//|
+
+STATIC const mp_rom_map_elem_t audiomixer_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiomixer) },
+ { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audiomixer_mixer_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiomixer_module_globals, audiomixer_module_globals_table);
+
+const mp_obj_module_t audiomixer_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audiomixer_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audiomixer, audiomixer_module, CIRCUITPY_AUDIOMIXER);
diff --git a/circuitpython/shared-bindings/audiomixer/__init__.h b/circuitpython/shared-bindings/audiomixer/__init__.h
new file mode 100644
index 0000000..35a9044
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomixer/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Michael Schroeder
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H
diff --git a/circuitpython/shared-bindings/audiomp3/MP3Decoder.c b/circuitpython/shared-bindings/audiomp3/MP3Decoder.c
new file mode 100644
index 0000000..16efa36
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomp3/MP3Decoder.c
@@ -0,0 +1,286 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/audiomp3/MP3Decoder.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class MP3Decoder:
+//| """Load a mp3 file for audio playback
+//|
+//| .. note::
+//|
+//| ``MP3Decoder`` uses a lot of contiguous memory, so care should be given to
+//| optimizing memory usage. More information and recommendations can be found here:
+//| https://learn.adafruit.com/Memory-saving-tips-for-CircuitPython/reducing-memory-fragmentation
+//| """
+//|
+//| def __init__(self, file: typing.BinaryIO, buffer: WriteableBuffer) -> None:
+//|
+//| """Load a .mp3 file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
+//|
+//| :param typing.BinaryIO file: Already opened mp3 file
+//| :param ~circuitpython_typing.WriteableBuffer buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two buffers are allocated internally. The specific buffer size required depends on the mp3 file.
+//|
+//| Playback of mp3 audio is CPU intensive, and the
+//| exact limit depends on many factors such as the particular
+//| microcontroller, SD card or flash performance, and other
+//| code in use such as displayio. If playback is garbled,
+//| skips, or plays as static, first try using a "simpler" mp3:
+//|
+//| * Use constant bit rate (CBR) not VBR or ABR (variable or average bit rate) when encoding your mp3 file
+//| * Use a lower sample rate (e.g., 11.025kHz instead of 48kHz)
+//| * Use a lower bit rate (e.g., 32kbit/s instead of 256kbit/s)
+//|
+//| Reduce activity taking place at the same time as
+//| mp3 playback. For instance, only update small portions of a
+//| displayio screen if audio is playing. Disable auto-refresh
+//| and explicitly call refresh.
+//|
+//| Playing a mp3 file from flash::
+//|
+//| import board
+//| import audiomp3
+//| import audioio
+//| import digitalio
+//|
+//| # Required for CircuitPlayground Express
+//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+//| speaker_enable.switch_to_output(value=True)
+//|
+//| data = open("cplay-16bit-16khz-64kbps.mp3", "rb")
+//| mp3 = audiomp3.MP3Decoder(data)
+//| a = audioio.AudioOut(board.A0)
+//|
+//| print("playing")
+//| a.play(mp3)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 2, false);
+
+ audiomp3_mp3file_obj_t *self = m_new_obj(audiomp3_mp3file_obj_t);
+ self->base.type = &audiomp3_mp3file_type;
+ if (!mp_obj_is_type(args[0], &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+ uint8_t *buffer = NULL;
+ size_t buffer_size = 0;
+ if (n_args >= 2) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ buffer = bufinfo.buf;
+ buffer_size = bufinfo.len;
+ }
+ common_hal_audiomp3_mp3file_construct(self, MP_OBJ_TO_PTR(args[0]),
+ buffer, buffer_size);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the MP3 and releases all memory resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audiomp3_mp3file_deinit(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiomp3_mp3file_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_deinit_obj, audiomp3_mp3file_deinit);
+
+STATIC void check_for_deinit(audiomp3_mp3file_obj_t *self) {
+ if (common_hal_audiomp3_mp3file_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> MP3Decoder:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiomp3_mp3file_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomp3_mp3file___exit___obj, 4, 4, audiomp3_mp3file_obj___exit__);
+
+//| file: typing.BinaryIO
+//| """File to play back."""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_file(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return self->file;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_file_obj, audiomp3_mp3file_obj_get_file);
+
+STATIC mp_obj_t audiomp3_mp3file_obj_set_file(mp_obj_t self_in, mp_obj_t file) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (!mp_obj_is_type(file, &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+ common_hal_audiomp3_mp3file_set_file(self, file);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_file_obj, audiomp3_mp3file_obj_set_file);
+
+MP_PROPERTY_GETSET(audiomp3_mp3file_file_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_file_obj,
+ (mp_obj_t)&audiomp3_mp3file_set_file_obj);
+
+
+
+//| sample_rate: int
+//| """32 bit value that dictates how quickly samples are loaded into the DAC
+//| in Hertz (cycles per second). When the sample is looped, this can change
+//| the pitch output without changing the underlying sample."""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_sample_rate(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_sample_rate_obj, audiomp3_mp3file_obj_get_sample_rate);
+
+STATIC mp_obj_t audiomp3_mp3file_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audiomp3_mp3file_set_sample_rate(self, mp_obj_get_int(sample_rate));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(audiomp3_mp3file_set_sample_rate_obj, audiomp3_mp3file_obj_set_sample_rate);
+
+MP_PROPERTY_GETSET(audiomp3_mp3file_sample_rate_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_sample_rate_obj,
+ (mp_obj_t)&audiomp3_mp3file_set_sample_rate_obj);
+
+//| bits_per_sample: int
+//| """Bits per sample. (read only)"""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_bits_per_sample(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_bits_per_sample(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_bits_per_sample_obj, audiomp3_mp3file_obj_get_bits_per_sample);
+
+MP_PROPERTY_GETTER(audiomp3_mp3file_bits_per_sample_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_bits_per_sample_obj);
+
+//| channel_count: int
+//| """Number of audio channels. (read only)"""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_channel_count(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_channel_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_channel_count_obj, audiomp3_mp3file_obj_get_channel_count);
+
+MP_PROPERTY_GETTER(audiomp3_mp3file_channel_count_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_channel_count_obj);
+
+//| rms_level: float
+//| """The RMS audio level of a recently played moment of audio. (read only)"""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_rms_level(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_audiomp3_mp3file_get_rms_level(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_rms_level_obj, audiomp3_mp3file_obj_get_rms_level);
+
+MP_PROPERTY_GETTER(audiomp3_mp3file_rms_level_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_rms_level_obj);
+
+//| samples_decoded: int
+//| """The number of audio samples decoded from the current file. (read only)"""
+//|
+STATIC mp_obj_t audiomp3_mp3file_obj_get_samples_decoded(mp_obj_t self_in) {
+ audiomp3_mp3file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_audiomp3_mp3file_get_samples_decoded(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiomp3_mp3file_get_samples_decoded_obj, audiomp3_mp3file_obj_get_samples_decoded);
+
+MP_PROPERTY_GETTER(audiomp3_mp3file_samples_decoded_obj,
+ (mp_obj_t)&audiomp3_mp3file_get_samples_decoded_obj);
+
+STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiomp3_mp3file_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_file), MP_ROM_PTR(&audiomp3_mp3file_file_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomp3_mp3file_sample_rate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audiomp3_mp3file_bits_per_sample_obj) },
+ { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audiomp3_mp3file_channel_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rms_level), MP_ROM_PTR(&audiomp3_mp3file_rms_level_obj) },
+ { MP_ROM_QSTR(MP_QSTR_samples_decoded), MP_ROM_PTR(&audiomp3_mp3file_samples_decoded_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audiomp3_mp3file_locals_dict, audiomp3_mp3file_locals_dict_table);
+
+STATIC const audiosample_p_t audiomp3_mp3file_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
+ .sample_rate = (audiosample_sample_rate_fun)common_hal_audiomp3_mp3file_get_sample_rate,
+ .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_audiomp3_mp3file_get_bits_per_sample,
+ .channel_count = (audiosample_channel_count_fun)common_hal_audiomp3_mp3file_get_channel_count,
+ .reset_buffer = (audiosample_reset_buffer_fun)audiomp3_mp3file_reset_buffer,
+ .get_buffer = (audiosample_get_buffer_fun)audiomp3_mp3file_get_buffer,
+ .get_buffer_structure = (audiosample_get_buffer_structure_fun)audiomp3_mp3file_get_buffer_structure,
+};
+
+const mp_obj_type_t audiomp3_mp3file_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_MP3Decoder,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = audiomp3_mp3file_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audiomp3_mp3file_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &audiomp3_mp3file_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/audiomp3/MP3Decoder.h b/circuitpython/shared-bindings/audiomp3/MP3Decoder.h
new file mode 100644
index 0000000..e1f4fcf
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomp3/MP3Decoder.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MP3FILE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MP3FILE_H
+
+#include "py/obj.h"
+#include "extmod/vfs_fat.h"
+
+#include "shared-module/audiomp3/MP3Decoder.h"
+
+extern const mp_obj_type_t audiomp3_mp3file_type;
+
+void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self,
+ pyb_file_obj_t *file, uint8_t *buffer, size_t buffer_size);
+
+void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file_obj_t *file);
+void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self);
+bool common_hal_audiomp3_mp3file_deinited(audiomp3_mp3file_obj_t *self);
+uint32_t common_hal_audiomp3_mp3file_get_sample_rate(audiomp3_mp3file_obj_t *self);
+void common_hal_audiomp3_mp3file_set_sample_rate(audiomp3_mp3file_obj_t *self, uint32_t sample_rate);
+uint8_t common_hal_audiomp3_mp3file_get_bits_per_sample(audiomp3_mp3file_obj_t *self);
+uint8_t common_hal_audiomp3_mp3file_get_channel_count(audiomp3_mp3file_obj_t *self);
+float common_hal_audiomp3_mp3file_get_rms_level(audiomp3_mp3file_obj_t *self);
+uint32_t common_hal_audiomp3_mp3file_get_samples_decoded(audiomp3_mp3file_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MP3FILE_H
diff --git a/circuitpython/shared-bindings/audiomp3/__init__.c b/circuitpython/shared-bindings/audiomp3/__init__.c
new file mode 100644
index 0000000..13f02b1
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomp3/__init__.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/audiomp3/MP3Decoder.h"
+
+//| """Support for MP3-compressed audio files
+//|
+//| For more infomration about working with MP3 files in CircuitPython,
+//| see `this CircuitPython Essentials Learn guide page
+//| <https://learn.adafruit.com/circuitpython-essentials/circuitpython-mp3-audio>`_.
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t audiomp3_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiomp3) },
+ { MP_ROM_QSTR(MP_QSTR_MP3Decoder), MP_ROM_PTR(&audiomp3_mp3file_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiomp3_module_globals, audiomp3_module_globals_table);
+
+const mp_obj_module_t audiomp3_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audiomp3_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audiomp3, audiomp3_module, CIRCUITPY_AUDIOMP3);
diff --git a/circuitpython/shared-bindings/audiomp3/__init__.h b/circuitpython/shared-bindings/audiomp3/__init__.h
new file mode 100644
index 0000000..9026af6
--- /dev/null
+++ b/circuitpython/shared-bindings/audiomp3/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMP3___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMP3___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMP3___INIT___H
diff --git a/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.c b/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.c
new file mode 100644
index 0000000..8118eb4
--- /dev/null
+++ b/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.c
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiopwmio/PWMAudioOut.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class PWMAudioOut:
+//| """Output an analog audio signal by varying the PWM duty cycle."""
+//|
+//| def __init__(self, left_channel: microcontroller.Pin, *, right_channel: Optional[microcontroller.Pin] = None, quiescent_value: int = 0x8000) -> None:
+//| """Create a PWMAudioOut object associated with the given pin(s). This allows you to
+//| play audio signals out on the given pin(s). In contrast to mod:`audioio`,
+//| the pin(s) specified are digital pins, and are driven with a device-dependent PWM
+//| signal.
+//|
+//| :param ~microcontroller.Pin left_channel: The pin to output the left channel to
+//| :param ~microcontroller.Pin right_channel: The pin to output the right channel to
+//| :param int quiescent_value: The output value when no signal is present. Samples should start
+//| and end with this value to prevent audible popping.
+//|
+//| Simple 8ksps 440 Hz sin wave::
+//|
+//| import audiocore
+//| import audiopwmio
+//| import board
+//| import array
+//| import time
+//| import math
+//|
+//| # Generate one period of sine wav.
+//| length = 8000 // 440
+//| sine_wave = array.array("H", [0] * length)
+//| for i in range(length):
+//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15)
+//|
+//| dac = audiopwmio.PWMAudioOut(board.SPEAKER)
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+//| dac.play(sine_wave, loop=True)
+//| time.sleep(1)
+//| dac.stop()
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audiocore
+//| import audiopwmio
+//| import digitalio
+//|
+//| # Required for CircuitPlayground Express
+//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+//| speaker_enable.switch_to_output(value=True)
+//|
+//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
+//| wav = audiocore.WaveFile(data)
+//| a = audiopwmio.PWMAudioOut(board.SPEAKER)
+//|
+//| print("playing")
+//| a.play(wav)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_left_channel, ARG_right_channel, ARG_quiescent_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_left_channel, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_right_channel, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = mp_const_none} },
+ { MP_QSTR_quiescent_value, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x8000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *left_channel_pin = validate_obj_is_free_pin(args[ARG_left_channel].u_obj);
+ const mcu_pin_obj_t *right_channel_pin = validate_obj_is_free_pin_or_none(args[ARG_right_channel].u_obj);
+
+ // create AudioOut object from the given pin
+ audiopwmio_pwmaudioout_obj_t *self = m_new_obj(audiopwmio_pwmaudioout_obj_t);
+ self->base.type = &audiopwmio_pwmaudioout_type;
+ common_hal_audiopwmio_pwmaudioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the PWMAudioOut and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_deinit(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiopwmio_pwmaudioout_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_deinit_obj, audiopwmio_pwmaudioout_deinit);
+
+STATIC void check_for_deinit(audiopwmio_pwmaudioout_obj_t *self) {
+ if (common_hal_audiopwmio_pwmaudioout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| def __enter__(self) -> PWMAudioOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiopwmio_pwmaudioout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiopwmio_pwmaudioout___exit___obj, 4, 4, audiopwmio_pwmaudioout_obj___exit__);
+
+
+//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None:
+//| """Plays the sample once when loop=False and continuously when loop=True.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`.
+//|
+//| The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
+//| resolution will use the highest order bits to output."""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audiopwmio_pwmaudioout_play(self, sample, args[ARG_loop].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiopwmio_pwmaudioout_play_obj, 1, audiopwmio_pwmaudioout_obj_play);
+
+//| def stop(self) -> None:
+//| """Stops playback and resets to the start of the sample."""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_stop(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audiopwmio_pwmaudioout_stop(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_stop_obj, audiopwmio_pwmaudioout_obj_stop);
+
+//| playing: bool
+//| """True when an audio sample is being output even if `paused`. (read-only)"""
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_get_playing(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiopwmio_pwmaudioout_get_playing(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_get_playing_obj, audiopwmio_pwmaudioout_obj_get_playing);
+
+MP_PROPERTY_GETTER(audiopwmio_pwmaudioout_playing_obj,
+ (mp_obj_t)&audiopwmio_pwmaudioout_get_playing_obj);
+
+//| def pause(self) -> None:
+//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback."""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_pause(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (!common_hal_audiopwmio_pwmaudioout_get_playing(self)) {
+ mp_raise_RuntimeError(translate("Not playing"));
+ }
+ common_hal_audiopwmio_pwmaudioout_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_pause_obj, audiopwmio_pwmaudioout_obj_pause);
+
+//| def resume(self) -> None:
+//| """Resumes sample playback after :py:func:`pause`."""
+//| ...
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_resume(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (common_hal_audiopwmio_pwmaudioout_get_paused(self)) {
+ common_hal_audiopwmio_pwmaudioout_resume(self);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_resume_obj, audiopwmio_pwmaudioout_obj_resume);
+
+//| paused: bool
+//| """True when playback is paused. (read-only)"""
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_get_paused(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiopwmio_pwmaudioout_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_get_paused_obj, audiopwmio_pwmaudioout_obj_get_paused);
+
+MP_PROPERTY_GETTER(audiopwmio_pwmaudioout_paused_obj,
+ (mp_obj_t)&audiopwmio_pwmaudioout_get_paused_obj);
+
+STATIC const mp_rom_map_elem_t audiopwmio_pwmaudioout_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiopwmio_pwmaudioout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiopwmio_pwmaudioout___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiopwmio_pwmaudioout_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiopwmio_pwmaudioout_stop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiopwmio_pwmaudioout_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiopwmio_pwmaudioout_resume_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiopwmio_pwmaudioout_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiopwmio_pwmaudioout_paused_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audiopwmio_pwmaudioout_locals_dict, audiopwmio_pwmaudioout_locals_dict_table);
+
+const mp_obj_type_t audiopwmio_pwmaudioout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PWMAudioOut,
+ .make_new = audiopwmio_pwmaudioout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&audiopwmio_pwmaudioout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.h b/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.h
new file mode 100644
index 0000000..15d1fa9
--- /dev/null
+++ b/circuitpython/shared-bindings/audiopwmio/PWMAudioOut.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H
+
+#include "common-hal/audiopwmio/PWMAudioOut.h"
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+
+extern const mp_obj_type_t audiopwmio_pwmaudioout_type;
+
+// left_channel will always be non-NULL but right_channel may be for mono output.
+void common_hal_audiopwmio_pwmaudioout_construct(audiopwmio_pwmaudioout_obj_t *self,
+ const mcu_pin_obj_t *left_channel, const mcu_pin_obj_t *right_channel, uint16_t default_value);
+
+void common_hal_audiopwmio_pwmaudioout_deinit(audiopwmio_pwmaudioout_obj_t *self);
+bool common_hal_audiopwmio_pwmaudioout_deinited(audiopwmio_pwmaudioout_obj_t *self);
+void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, mp_obj_t sample, bool loop);
+void common_hal_audiopwmio_pwmaudioout_stop(audiopwmio_pwmaudioout_obj_t *self);
+bool common_hal_audiopwmio_pwmaudioout_get_playing(audiopwmio_pwmaudioout_obj_t *self);
+void common_hal_audiopwmio_pwmaudioout_pause(audiopwmio_pwmaudioout_obj_t *self);
+void common_hal_audiopwmio_pwmaudioout_resume(audiopwmio_pwmaudioout_obj_t *self);
+bool common_hal_audiopwmio_pwmaudioout_get_paused(audiopwmio_pwmaudioout_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H
diff --git a/circuitpython/shared-bindings/audiopwmio/__init__.c b/circuitpython/shared-bindings/audiopwmio/__init__.c
new file mode 100644
index 0000000..41a756e
--- /dev/null
+++ b/circuitpython/shared-bindings/audiopwmio/__init__.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiopwmio/__init__.h"
+#include "shared-bindings/audiopwmio/PWMAudioOut.h"
+
+//| """Audio output via digital PWM
+//|
+//| The `audiopwmio` module contains classes to provide access to audio IO.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved
+//| to :mod:`audiocore`."""
+//|
+
+STATIC const mp_rom_map_elem_t audiopwmio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiopwmio) },
+ { MP_ROM_QSTR(MP_QSTR_PWMAudioOut), MP_ROM_PTR(&audiopwmio_pwmaudioout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiopwmio_module_globals, audiopwmio_module_globals_table);
+
+const mp_obj_module_t audiopwmio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&audiopwmio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_audiopwmio, audiopwmio_module, CIRCUITPY_AUDIOPWMIO);
diff --git a/circuitpython/shared-bindings/audiopwmio/__init__.h b/circuitpython/shared-bindings/audiopwmio/__init__.h
new file mode 100644
index 0000000..d7956d3
--- /dev/null
+++ b/circuitpython/shared-bindings/audiopwmio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H
diff --git a/circuitpython/shared-bindings/bitbangio/I2C.c b/circuitpython/shared-bindings/bitbangio/I2C.c
new file mode 100644
index 0000000..c65b184
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/I2C.c
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// bitbangio.I2C class.
+
+#include "shared-bindings/bitbangio/I2C.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/mperrno.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class I2C:
+//| """Two wire serial protocol"""
+//|
+//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 400000, timeout: int = 255) -> None:
+//| """I2C is a two-wire protocol for communicating between devices. At the
+//| physical level it consists of 2 wires: SCL and SDA, the clock and data
+//| lines respectively.
+//|
+//| .. seealso:: Using this class directly requires careful lock management.
+//| Instead, use :class:`~adafruit_bus_device.i2c_device.I2CDevice` to
+//| manage locks.
+//|
+//| .. seealso:: Using this class to directly read registers requires manual
+//| bit unpacking. Instead, use an existing driver or make one with
+//| :ref:`Register <register-module-reference>` data descriptors.
+//|
+//| :param ~microcontroller.Pin scl: The clock pin
+//| :param ~microcontroller.Pin sda: The data pin
+//| :param int frequency: The clock frequency of the bus
+//| :param int timeout: The maximum clock stretching timeout in microseconds"""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj);
+ const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj);
+
+ bitbangio_i2c_obj_t *self = m_new_obj(bitbangio_i2c_obj_t);
+ self->base.type = &bitbangio_i2c_type;
+ shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Releases control of the underlying hardware so other classes can use it."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_obj_deinit(mp_obj_t self_in) {
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ shared_module_bitbangio_i2c_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_deinit_obj, bitbangio_i2c_obj_deinit);
+
+STATIC void check_for_deinit(bitbangio_i2c_obj_t *self) {
+ if (shared_module_bitbangio_i2c_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> I2C:
+//| """No-op used in Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware on context exit. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ shared_module_bitbangio_i2c_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_i2c_obj___exit___obj, 4, 4, bitbangio_i2c_obj___exit__);
+
+static void check_lock(bitbangio_i2c_obj_t *self) {
+ if (!shared_module_bitbangio_i2c_has_lock(self)) {
+ mp_raise_RuntimeError(translate("Function requires lock"));
+ }
+}
+
+//| def scan(self) -> List[int]:
+//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
+//| those that respond. A device responds if it pulls the SDA line low after
+//| its address (including a read bit) is sent on the bus."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_scan(mp_obj_t self_in) {
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
+ for (int addr = 0x08; addr < 0x78; ++addr) {
+ bool success = shared_module_bitbangio_i2c_probe(self, addr);
+ if (success) {
+ mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
+ }
+ }
+ return list;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_scan_obj, bitbangio_i2c_scan);
+
+//| def try_lock(self) -> bool:
+//| """Attempts to grab the I2C lock. Returns True on success."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_obj_try_lock(mp_obj_t self_in) {
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(shared_module_bitbangio_i2c_try_lock(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_try_lock_obj, bitbangio_i2c_obj_try_lock);
+
+//| def unlock(self) -> None:
+//| """Releases the I2C lock."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_obj_unlock(mp_obj_t self_in) {
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ shared_module_bitbangio_i2c_unlock(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock);
+
+//| import sys
+//| def readfrom_into(self, address: int, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Read into ``buffer`` from the device selected by ``address``.
+//| The number of bytes read will be the length of ``buffer``.
+//| At least one byte must be read.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]``. This will not cause an allocation like
+//| ``buf[start:end]`` will so it saves memory.
+//|
+//| :param int address: 7-bit device address
+//| :param WriteableBuffer buffer: buffer to write into
+//| :param int start: Index to start writing at
+//| :param int end: Index to write up to but not include"""
+//| ...
+//|
+// Shared arg parsing for readfrom_into and writeto_then_readfrom.
+STATIC void readfrom(bitbangio_i2c_obj_t *self, mp_int_t address, mp_obj_t buffer, int32_t start, mp_int_t end) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE);
+
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, end, &length);
+ if (length == 0) {
+ mp_raise_ValueError(translate("Buffer must be at least length 1"));
+ }
+
+ uint8_t status = shared_module_bitbangio_i2c_read(self, address, ((uint8_t *)bufinfo.buf) + start, length);
+ if (status != 0) {
+ mp_raise_OSError(status);
+ }
+}
+
+STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ readfrom(self, args[ARG_address].u_int, args[ARG_buffer].u_obj, args[ARG_start].u_int,
+ args[ARG_end].u_int);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 1, bitbangio_i2c_readfrom_into);
+
+//| import sys
+//| def writeto(self, address: int, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``buffer`` to the device selected by ``address`` and then transmits a
+//| stop bit. Use `writeto_then_readfrom` when needing a write, no stop and repeated start
+//| before a read.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``buffer[start:end]``.
+//|
+//| Writing a buffer or slice of length zero is permitted, as it can be used
+//| to poll for the existence of a device.
+//|
+//| :param int address: 7-bit device address
+//| :param ReadableBuffer buffer: buffer containing the bytes to write
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| """
+//| ...
+//|
+// Shared arg parsing for writeto and writeto_then_readfrom.
+STATIC void writeto(bitbangio_i2c_obj_t *self, mp_int_t address, mp_obj_t buffer, int32_t start, mp_int_t end, bool stop) {
+ // get the buffer to write the data from
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ);
+
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, end, &length);
+
+ // do the transfer
+ uint8_t status = shared_module_bitbangio_i2c_write(self, address,
+ ((uint8_t *)bufinfo.buf) + start, length,
+ stop);
+ if (status != 0) {
+ mp_raise_OSError(status);
+ }
+}
+
+STATIC mp_obj_t bitbangio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ writeto(self, args[ARG_address].u_int, args[ARG_buffer].u_obj, args[ARG_start].u_int,
+ args[ARG_end].u_int, true);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_writeto_obj, 1, bitbangio_i2c_writeto);
+
+
+//| import sys
+//| def writeto_then_readfrom(self, address: int, out_buffer: ReadableBuffer, in_buffer: ReadableBuffer, *, out_start: int = 0, out_end: int = sys.maxsize, in_start: int = 0, in_end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate no stop
+//| bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and
+//| ``in_buffer`` can be the same buffer because they are used sequentially.
+//|
+//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
+//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``out_buffer[start:end]``.
+//|
+//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
+//| as if ``in_buffer[in_start:in_end]`` were passed,
+//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
+
+//| :param int address: 7-bit device address
+//| :param ~circuitpython_typing.ReadableBuffer out_buffer: buffer containing the bytes to write
+//| :param ~circuitpython_typing.WriteableBuffer in_buffer: buffer to write into
+//| :param int out_start: beginning of ``out_buffer`` slice
+//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
+//| :param int in_start: beginning of ``in_buffer`` slice
+//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t bitbangio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ writeto(self, args[ARG_address].u_int, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int,
+ args[ARG_out_end].u_int, false);
+ readfrom(self, args[ARG_address].u_int, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int,
+ args[ARG_in_end].u_int);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_writeto_then_readfrom_obj, 1, bitbangio_i2c_writeto_then_readfrom);
+
+STATIC const mp_rom_map_elem_t bitbangio_i2c_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bitbangio_i2c_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bitbangio_i2c_obj___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bitbangio_i2c_scan_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&bitbangio_i2c_try_lock_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&bitbangio_i2c_unlock_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&bitbangio_i2c_writeto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&bitbangio_i2c_readfrom_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeto_then_readfrom), MP_ROM_PTR(&bitbangio_i2c_writeto_then_readfrom_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bitbangio_i2c_locals_dict, bitbangio_i2c_locals_dict_table);
+
+const mp_obj_type_t bitbangio_i2c_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2C,
+ .make_new = bitbangio_i2c_make_new,
+ .locals_dict = (mp_obj_dict_t *)&bitbangio_i2c_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/bitbangio/I2C.h b/circuitpython/shared-bindings/bitbangio/I2C.h
new file mode 100644
index 0000000..d950180
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/I2C.h
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_I2C_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_I2C_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-module/bitbangio/I2C.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t bitbangio_i2c_type;
+
+// Initializes the hardware peripheral.
+extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self,
+ const mcu_pin_obj_t *scl,
+ const mcu_pin_obj_t *sda,
+ uint32_t frequency,
+ uint32_t us_timeout);
+
+extern void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self);
+extern bool shared_module_bitbangio_i2c_deinited(bitbangio_i2c_obj_t *self);
+
+extern bool shared_module_bitbangio_i2c_try_lock(bitbangio_i2c_obj_t *self);
+extern bool shared_module_bitbangio_i2c_has_lock(bitbangio_i2c_obj_t *self);
+extern void shared_module_bitbangio_i2c_unlock(bitbangio_i2c_obj_t *self);
+
+// Probe the bus to see if a device acknowledges the given address.
+extern bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr);
+
+extern uint8_t shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self,
+ uint16_t address,
+ const uint8_t *data, size_t len,
+ bool stop);
+
+// Reads memory of the i2c device picking up where it left off.
+extern uint8_t shared_module_bitbangio_i2c_read(bitbangio_i2c_obj_t *self,
+ uint16_t address,
+ uint8_t *data, size_t len);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_I2C_H
diff --git a/circuitpython/shared-bindings/bitbangio/SPI.c b/circuitpython/shared-bindings/bitbangio/SPI.c
new file mode 100644
index 0000000..2c29c09
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/SPI.c
@@ -0,0 +1,383 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// bitbangio.SPI class.
+
+#include <string.h>
+
+#include "shared-bindings/bitbangio/SPI.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/mperrno.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class SPI:
+//| """A 3-4 wire serial protocol
+//|
+//| SPI is a serial protocol that has exclusive pins for data in and out of the
+//| main device. It is typically faster than :py:class:`~bitbangio.I2C` because a
+//| separate pin is used to select a device rather than a transmitted
+//| address. This class only manages three of the four SPI lines: `!clock`,
+//| `!MOSI`, `!MISO`. Its up to the client to manage the appropriate
+//| select line, often abbreviated `!CS` or `!SS`. (This is common because
+//| multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines
+//| and therefore the hardware.)"""
+//|
+//| def __init__(self, clock: microcontroller.Pin, MOSI: Optional[microcontroller.Pin] = None, MISO: Optional[microcontroller.Pin] = None) -> None:
+//| """Construct an SPI object on the given pins.
+//|
+//| .. seealso:: Using this class directly requires careful lock management.
+//| Instead, use :class:`~adafruit_bus_device.spi_device.SPIDevice` to
+//| manage locks.
+//|
+//| .. seealso:: Using this class to directly read registers requires manual
+//| bit unpacking. Instead, use an existing driver or make one with
+//| :ref:`Register <register-module-reference>` data descriptors.
+//|
+//|
+//| :param ~microcontroller.Pin clock: the pin to use for the clock.
+//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin.
+//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin."""
+//| ...
+//|
+
+// TODO(tannewt): Support LSB SPI.
+STATIC mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj);
+ const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj);
+
+ bitbangio_spi_obj_t *self = m_new_obj(bitbangio_spi_obj_t);
+ self->base.type = &bitbangio_spi_type;
+ shared_module_bitbangio_spi_construct(self, clock, mosi, miso);
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the SPI bus."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_obj_deinit(mp_obj_t self_in) {
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ shared_module_bitbangio_spi_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_deinit_obj, bitbangio_spi_obj_deinit);
+
+STATIC void check_for_deinit(bitbangio_spi_obj_t *self) {
+ if (shared_module_bitbangio_spi_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> SPI:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ shared_module_bitbangio_spi_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_spi_obj___exit___obj, 4, 4, bitbangio_spi_obj___exit__);
+
+
+static void check_lock(bitbangio_spi_obj_t *self) {
+ if (!shared_module_bitbangio_spi_has_lock(self)) {
+ mp_raise_RuntimeError(translate("Function requires lock"));
+ }
+}
+
+//| def configure(self, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, bits: int = 8) -> None:
+//| """Configures the SPI bus. Only valid when locked.
+//|
+//| :param int baudrate: the clock rate in Hertz
+//| :param int polarity: the base state of the clock line (0 or 1)
+//| :param int phase: the edge of the clock that data is captured. First (0)
+//| or second (1). Rising or falling depends on clock polarity.
+//| :param int bits: the number of bits per word"""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ };
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t polarity = args[ARG_polarity].u_int;
+ if (polarity != 0 && polarity != 1) {
+ mp_raise_ValueError(translate("Invalid polarity"));
+ }
+ uint8_t phase = args[ARG_phase].u_int;
+ if (phase != 0 && phase != 1) {
+ mp_raise_ValueError(translate("Invalid phase"));
+ }
+ uint8_t bits = args[ARG_bits].u_int;
+ if (bits != 8 && bits != 9) {
+ mp_raise_ValueError(translate("Invalid number of bits"));
+ }
+
+ shared_module_bitbangio_spi_configure(self, args[ARG_baudrate].u_int, polarity, phase, bits);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_configure_obj, 1, bitbangio_spi_configure);
+
+//| def try_lock(self) -> bool:
+//| """Attempts to grab the SPI lock. Returns True on success.
+//|
+//| :return: True when lock has been grabbed
+//| :rtype: bool"""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_obj_try_lock(mp_obj_t self_in) {
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(shared_module_bitbangio_spi_try_lock(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_try_lock_obj, bitbangio_spi_obj_try_lock);
+
+//| def unlock(self) -> None:
+//| """Releases the SPI lock."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_obj_unlock(mp_obj_t self_in) {
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ shared_module_bitbangio_spi_unlock(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock);
+
+//| def write(self, buf: ReadableBuffer) -> None:
+//| """Write the data contained in ``buf``. Requires the SPI being locked.
+//| If the buffer is empty, nothing happens."""
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+ int32_t start = args[ARG_start].u_int;
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+
+ if (length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = shared_module_bitbangio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_write_obj, 1, bitbangio_spi_write);
+
+
+//| import sys
+//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize, write_value: int = 0) -> None:
+//| """Read into ``buffer`` while writing ``write_value`` for each byte read.
+//| The SPI object must be locked.
+//| If the number of bytes to read is 0, nothing happens.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed.
+//| The number of bytes read will be the length of ``buffer[start:end]``.
+//|
+//| :param WriteableBuffer buffer: read bytes into this buffer
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| :param int write_value: value to write while reading
+//| """
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_write_value,MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+ int32_t start = args[ARG_start].u_int;
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+
+ if (length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = shared_module_bitbangio_spi_read(self, ((uint8_t *)bufinfo.buf) + start, length, args[ARG_write_value].u_int);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_readinto_obj, 1, bitbangio_spi_readinto);
+
+//| import sys
+//| def write_readinto(self, out_buffer: ReadableBuffer, in_buffer: WriteableBuffer, *, out_start: int = 0, out_end: int = sys.maxsize, in_start: int = 0, in_end: int = sys.maxsize) -> None:
+//| """Write out the data in ``out_buffer`` while simultaneously reading data into ``in_buffer``.
+//| The SPI object must be locked.
+//|
+//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
+//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``.
+//|
+//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
+//| as if ``in_buffer[in_start:in_end]`` were passed,
+//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
+//|
+//| The lengths of the slices defined by ``out_buffer[out_start:out_end]``
+//| and ``in_buffer[in_start:in_end]`` must be equal.
+//| If buffer slice lengths are both 0, nothing happens.
+//|
+//| :param ReadableBuffer out_buffer: write out bytes from this buffer
+//| :param WriteableBuffer in_buffer: read bytes into this buffer
+//| :param int out_start: beginning of ``out_buffer`` slice
+//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
+//| :param int in_start: beginning of ``in_buffer`` slice
+//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t bitbangio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t buf_out_info;
+ mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &buf_out_info, MP_BUFFER_READ);
+ int32_t out_start = args[ARG_out_start].u_int;
+ size_t out_length = buf_out_info.len;
+ normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length);
+
+ mp_buffer_info_t buf_in_info;
+ mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &buf_in_info, MP_BUFFER_WRITE);
+ int32_t in_start = args[ARG_in_start].u_int;
+ size_t in_length = buf_in_info.len;
+ normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length);
+
+ if (out_length != in_length) {
+ mp_raise_ValueError(translate("buffer slices must be of equal length"));
+ }
+
+ if (out_length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = shared_module_bitbangio_spi_transfer(self,
+ ((uint8_t *)buf_out_info.buf) + out_start,
+ ((uint8_t *)buf_in_info.buf) + in_start,
+ out_length);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_write_readinto_obj, 1, bitbangio_spi_write_readinto);
+
+STATIC const mp_rom_map_elem_t bitbangio_spi_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bitbangio_spi_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bitbangio_spi_obj___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&bitbangio_spi_configure_obj) },
+ { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&bitbangio_spi_try_lock_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&bitbangio_spi_unlock_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitbangio_spi_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&bitbangio_spi_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&bitbangio_spi_write_readinto_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(bitbangio_spi_locals_dict, bitbangio_spi_locals_dict_table);
+
+const mp_obj_type_t bitbangio_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .make_new = bitbangio_spi_make_new,
+ .locals_dict = (mp_obj_dict_t *)&bitbangio_spi_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/bitbangio/SPI.h b/circuitpython/shared-bindings/bitbangio/SPI.h
new file mode 100644
index 0000000..2d0d75e
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/SPI.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_SPI_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_SPI_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-module/bitbangio/SPI.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t bitbangio_spi_type;
+
+// Construct an underlying SPI object.
+extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
+ const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi,
+ const mcu_pin_obj_t *miso);
+
+extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self);
+extern bool shared_module_bitbangio_spi_deinited(bitbangio_spi_obj_t *self);
+
+extern void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self,
+ uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits);
+
+extern bool shared_module_bitbangio_spi_try_lock(bitbangio_spi_obj_t *self);
+extern bool shared_module_bitbangio_spi_has_lock(bitbangio_spi_obj_t *self);
+extern void shared_module_bitbangio_spi_unlock(bitbangio_spi_obj_t *self);
+
+// Writes out the given data.
+extern bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t *data, size_t len);
+
+// Reads in len bytes while outputting zeroes.
+extern bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value);
+
+// Transfer out len bytes while reading len bytes
+extern bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, const uint8_t *dout, uint8_t *din, size_t len);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_SPI_H
diff --git a/circuitpython/shared-bindings/bitbangio/__init__.c b/circuitpython/shared-bindings/bitbangio/__init__.c
new file mode 100644
index 0000000..57348a3
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/__init__.c
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// bitbangio implements some standard protocols in the processor. Its only
+// dependency is digitalio.
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/bitbangio/__init__.h"
+#include "shared-bindings/bitbangio/I2C.h"
+#include "shared-bindings/onewireio/OneWire.h"
+#include "shared-bindings/bitbangio/SPI.h"
+
+#include "py/runtime.h"
+
+//| """Digital protocols implemented by the CPU
+//|
+//| The `bitbangio` module contains classes to provide digital bus protocol
+//| support regardless of whether the underlying hardware exists to use the
+//| protocol.
+//|
+//| First try to use `busio` module instead which may utilize peripheral
+//| hardware to implement the protocols. Native implementations will be faster
+//| than bitbanged versions and have more capabilities.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import bitbangio
+//| from board import *
+//|
+//| i2c = bitbangio.I2C(SCL, SDA)
+//| print(i2c.scan())
+//| i2c.deinit()
+//|
+//| This example will initialize the the device, run
+//| :py:meth:`~bitbangio.I2C.scan` and then :py:meth:`~bitbangio.I2C.deinit` the
+//| hardware. The last step is optional because CircuitPython automatically
+//| resets hardware after a program finishes."""
+//|
+
+STATIC const mp_rom_map_elem_t bitbangio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitbangio) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&bitbangio_i2c_type) },
+ #if CIRCUITPY_ONEWIREIO
+ { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&onewireio_onewire_type) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&bitbangio_spi_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bitbangio_module_globals, bitbangio_module_globals_table);
+
+const mp_obj_module_t bitbangio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&bitbangio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_bitbangio, bitbangio_module, CIRCUITPY_BITBANGIO);
diff --git a/circuitpython/shared-bindings/bitbangio/__init__.h b/circuitpython/shared-bindings/bitbangio/__init__.h
new file mode 100644
index 0000000..0e9206a
--- /dev/null
+++ b/circuitpython/shared-bindings/bitbangio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO___INIT___H
diff --git a/circuitpython/shared-bindings/bitmaptools/__init__.c b/circuitpython/shared-bindings/bitmaptools/__init__.c
new file mode 100644
index 0000000..5122d03
--- /dev/null
+++ b/circuitpython/shared-bindings/bitmaptools/__init__.c
@@ -0,0 +1,766 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Kevin Matocha
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Bitmap.h"
+#include "shared-bindings/displayio/Palette.h"
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/bitmaptools/__init__.h"
+
+#include <stdint.h>
+
+#include "py/binary.h"
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#if MICROPY_VFS
+#include "extmod/vfs.h"
+#endif
+#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX
+#include "extmod/vfs_posix.h"
+#endif
+
+//| """Collection of bitmap manipulation tools
+//|
+//| .. note:: If you're looking for information about displaying bitmaps on
+//| screens in CircuitPython, see `this Learn guide
+//| <https://learn.adafruit.com/circuitpython-display-support-using-displayio>`_
+//| for information about using the :py:mod:`displayio` module.
+//| """
+//|
+
+STATIC int16_t validate_point(mp_obj_t point, int16_t default_value) {
+ // Checks if point is None and returns default_value, otherwise decodes integer value
+ if (point == mp_const_none) {
+ return default_value;
+ }
+ return mp_obj_get_int(point);
+}
+
+STATIC void extract_tuple(mp_obj_t xy_tuple, int16_t *x, int16_t *y, int16_t x_default, int16_t y_default) {
+ // Helper function for rotozoom
+ // Extract x,y values from a tuple or default if None
+ if (xy_tuple == mp_const_none) {
+ *x = x_default;
+ *y = y_default;
+ } else if (!mp_obj_is_obj(xy_tuple)) {
+ mp_raise_ValueError(translate("clip point must be (x,y) tuple"));
+ } else {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(xy_tuple, 2, &items);
+ *x = mp_obj_get_int(items[0]);
+ *y = mp_obj_get_int(items[1]);
+ }
+}
+
+STATIC void validate_clip_region(displayio_bitmap_t *bitmap, mp_obj_t clip0_tuple, int16_t *clip0_x, int16_t *clip0_y,
+ mp_obj_t clip1_tuple, int16_t *clip1_x, int16_t *clip1_y) {
+ // Helper function for rotozoom
+ // 1. Extract the clip x,y points from the two clip tuples
+ // 2. Rearrange values such that clip0_ < clip1_
+ // 3. Constrain the clip points to within the bitmap
+
+ extract_tuple(clip0_tuple, clip0_x, clip0_y, 0, 0);
+ extract_tuple(clip1_tuple, clip1_x, clip1_y, bitmap->width, bitmap->height);
+
+ // Ensure the value for clip0 is less than clip1 (for both x and y)
+ if (*clip0_x > *clip1_x) {
+ int16_t temp_value = *clip0_x; // swap values
+ *clip0_x = *clip1_x;
+ *clip1_x = temp_value;
+ }
+ if (*clip0_y > *clip1_y) {
+ int16_t temp_value = *clip0_y; // swap values
+ *clip0_y = *clip1_y;
+ *clip1_y = temp_value;
+ }
+
+ // Constrain the clip window to within the bitmap boundaries
+ if (*clip0_x < 0) {
+ *clip0_x = 0;
+ }
+ if (*clip0_y < 0) {
+ *clip0_y = 0;
+ }
+ if (*clip0_x > bitmap->width) {
+ *clip0_x = bitmap->width;
+ }
+ if (*clip0_y > bitmap->height) {
+ *clip0_y = bitmap->height;
+ }
+ if (*clip1_x < 0) {
+ *clip1_x = 0;
+ }
+ if (*clip1_y < 0) {
+ *clip1_y = 0;
+ }
+ if (*clip1_x > bitmap->width) {
+ *clip1_x = bitmap->width;
+ }
+ if (*clip1_y > bitmap->height) {
+ *clip1_y = bitmap->height;
+ }
+
+}
+
+//|
+//| def rotozoom(
+//| dest_bitmap: displayio.Bitmap, source_bitmap: displayio.Bitmap,
+//| *,
+//| ox: int, oy: int, dest_clip0: Tuple[int, int], dest_clip1: Tuple[int, int],
+//| px: int, py: int, source_clip0: Tuple[int, int], source_clip1: Tuple[int, int],
+//| angle: float, scale: float, skip_index: int) -> None:
+//| """Inserts the source bitmap region into the destination bitmap with rotation
+//| (angle), scale and clipping (both on source and destination bitmaps).
+//|
+//| :param bitmap dest_bitmap: Destination bitmap that will be copied into
+//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
+//| :param int ox: Horizontal pixel location in destination bitmap where source bitmap
+//| point (px,py) is placed
+//| :param int oy: Vertical pixel location in destination bitmap where source bitmap
+//| point (px,py) is placed
+//| :param Tuple[int,int] dest_clip0: First corner of rectangular destination clipping
+//| region that constrains region of writing into destination bitmap
+//| :param Tuple[int,int] dest_clip1: Second corner of rectangular destination clipping
+//| region that constrains region of writing into destination bitmap
+//| :param int px: Horizontal pixel location in source bitmap that is placed into the
+//| destination bitmap at (ox,oy)
+//| :param int py: Vertical pixel location in source bitmap that is placed into the
+//| destination bitmap at (ox,oy)
+//| :param Tuple[int,int] source_clip0: First corner of rectangular source clipping
+//| region that constrains region of reading from the source bitmap
+//| :param Tuple[int,int] source_clip1: Second corner of rectangular source clipping
+//| region that constrains region of reading from the source bitmap
+//| :param float angle: Angle of rotation, in radians (positive is clockwise direction)
+//| :param float scale: Scaling factor
+//| :param int skip_index: Bitmap palette index in the source that will not be copied,
+//| set to None to copy all pixels"""
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_dest_bitmap, ARG_source_bitmap,
+ ARG_ox, ARG_oy, ARG_dest_clip0, ARG_dest_clip1,
+ ARG_px, ARG_py, ARG_source_clip0, ARG_source_clip1,
+ ARG_angle, ARG_scale, ARG_skip_index};
+
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+
+ {MP_QSTR_ox, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->width / 2
+ {MP_QSTR_oy, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->height / 2
+ {MP_QSTR_dest_clip0, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ {MP_QSTR_dest_clip1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+
+ {MP_QSTR_px, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width / 2
+ {MP_QSTR_py, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height / 2
+ {MP_QSTR_source_clip0, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ {MP_QSTR_source_clip1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+
+ {MP_QSTR_angle, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to 0.0
+ {MP_QSTR_scale, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to 1.0
+ {MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
+
+ displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source_bitmap].u_obj); // the source bitmap
+
+ // ensure that the destination bitmap has at least as many `bits_per_value` as the source
+ if (destination->bits_per_value < source->bits_per_value) {
+ mp_raise_ValueError(translate("source palette too large"));
+ }
+
+ // Confirm the destination location target (ox,oy); if None, default to bitmap midpoint
+ int16_t ox, oy;
+ ox = validate_point(args[ARG_ox].u_obj, destination->width / 2);
+ oy = validate_point(args[ARG_oy].u_obj, destination->height / 2);
+
+ // Confirm the source location target (px,py); if None, default to bitmap midpoint
+ int16_t px, py;
+ px = validate_point(args[ARG_px].u_obj, source->width / 2);
+ py = validate_point(args[ARG_py].u_obj, source->height / 2);
+
+ // Validate the clipping regions for the destination bitmap
+ int16_t dest_clip0_x, dest_clip0_y, dest_clip1_x, dest_clip1_y;
+
+ validate_clip_region(destination, args[ARG_dest_clip0].u_obj, &dest_clip0_x, &dest_clip0_y,
+ args[ARG_dest_clip1].u_obj, &dest_clip1_x, &dest_clip1_y);
+
+ // Validate the clipping regions for the source bitmap
+ int16_t source_clip0_x, source_clip0_y, source_clip1_x, source_clip1_y;
+
+ validate_clip_region(source, args[ARG_source_clip0].u_obj, &source_clip0_x, &source_clip0_y,
+ args[ARG_source_clip1].u_obj, &source_clip1_x, &source_clip1_y);
+
+ // Confirm the angle value
+ mp_float_t angle = 0.0;
+ if (args[ARG_angle].u_obj != mp_const_none) {
+ angle = mp_obj_get_float(args[ARG_angle].u_obj);
+ }
+
+ // Confirm the scale value
+ mp_float_t scale = 1.0;
+ if (args[ARG_scale].u_obj != mp_const_none) {
+ scale = mp_obj_get_float(args[ARG_scale].u_obj);
+ }
+ if (scale < 0) { // ensure scale >= 0
+ scale = 1.0;
+ }
+
+ uint32_t skip_index;
+ bool skip_index_none; // Flag whether input skip_value was None
+ if (args[ARG_skip_index].u_obj == mp_const_none) {
+ skip_index = 0;
+ skip_index_none = true;
+ } else {
+ skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
+ skip_index_none = false;
+ }
+
+ common_hal_bitmaptools_rotozoom(destination, ox, oy,
+ dest_clip0_x, dest_clip0_y,
+ dest_clip1_x, dest_clip1_y,
+ source, px, py,
+ source_clip0_x, source_clip0_y,
+ source_clip1_x, source_clip1_y,
+ angle,
+ scale,
+ skip_index, skip_index_none);
+
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
+// requires at least 2 arguments (destination bitmap and source bitmap)
+
+//|
+//| def alphablend(dest_bitmap: displayio.Bitmap , source_bitmap_1: displayio.Bitmap, source_bitmap_2: displayio.Bitmap, colorspace: displayio.Colorspace, factor1: float=.5, factor2: float=None) -> None:
+//| """Alpha blend the two source bitmaps into the destination.
+//|
+//| It is permitted for the destination bitmap to be one of the two
+//| source bitmaps.
+//|
+//| :param bitmap dest_bitmap: Destination bitmap that will be written into
+//| :param bitmap source_bitmap_1: The first source bitmap
+//| :param bitmap source_bitmap_2: The second source bitmap
+//| :param float factor1: The proportion of bitmap 1 to mix in
+//| :param float factor2: The proportion of bitmap 2 to mix in. If specified as `None`, ``1-factor1`` is used. Usually the proportions should sum to 1.
+//| :param displayio.Colorspace colorspace: The colorspace of the bitmaps. They must all have the same colorspace. Only the following colorspaces are permitted: ``L8``, ``RGB565``, ``RGB565_SWAPPED``, ``BGR565`` and ``BGR565_SWAPPED``.
+//|
+//| For the L8 colorspace, the bitmaps must have a bits-per-value of 8.
+//| For the RGB colorspaces, they must have a bits-per-value of 16."""
+//|
+
+STATIC mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2};
+
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}},
+ {MP_QSTR_source_bitmap_1, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}},
+ {MP_QSTR_source_bitmap_2, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}},
+ {MP_QSTR_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}},
+ {MP_QSTR_factor_1, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
+ {MP_QSTR_factor_2, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
+ displayio_bitmap_t *source1 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_1].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_1)); // the first source bitmap
+ displayio_bitmap_t *source2 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_2].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_2)); // the second source bitmap
+
+ mp_float_t factor1 = (args[ARG_factor_1].u_obj == mp_const_none) ? MICROPY_FLOAT_CONST(.5) : mp_obj_get_float(args[ARG_factor_1].u_obj);
+ mp_float_t factor2 = (args[ARG_factor_2].u_obj == mp_const_none) ? 1 - factor1 : mp_obj_get_float(args[ARG_factor_2].u_obj);
+
+ displayio_colorspace_t colorspace = (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_colorspace].u_obj);
+
+ if (destination->width != source1->width
+ || destination->height != source1->height
+ || destination->bits_per_value != source1->bits_per_value
+ || destination->width != source2->width
+ || destination->height != source2->height
+ || destination->bits_per_value != source2->bits_per_value
+ ) {
+ mp_raise_ValueError(translate("Bitmap size and bits per value must match"));
+ }
+
+ switch (colorspace) {
+ case DISPLAYIO_COLORSPACE_L8:
+ if (destination->bits_per_value != 8) {
+ mp_raise_ValueError(translate("For L8 colorspace, input bitmap must have 8 bits per pixel"));
+ }
+ break;
+
+ case DISPLAYIO_COLORSPACE_RGB565:
+ case DISPLAYIO_COLORSPACE_RGB565_SWAPPED:
+ case DISPLAYIO_COLORSPACE_BGR565:
+ case DISPLAYIO_COLORSPACE_BGR565_SWAPPED:
+ if (destination->bits_per_value != 16) {
+ mp_raise_ValueError(translate("For RGB colorspaces, input bitmap must have 16 bits per pixel"));
+ }
+ break;
+
+ default:
+ mp_raise_ValueError(translate("Unsupported colorspace"));
+ }
+
+ common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend);
+
+//|
+//| def fill_region(
+//| dest_bitmap: displayio.Bitmap,
+//| x1: int, y1: int,
+//| x2: int, y2: int,
+//| value: int) -> None:
+//| """Draws the color value into the destination bitmap within the
+//| rectangular region bounded by (x1,y1) and (x2,y2), exclusive.
+//|
+//| :param bitmap dest_bitmap: Destination bitmap that will be written into
+//| :param int x1: x-pixel position of the first corner of the rectangular fill region
+//| :param int y1: y-pixel position of the first corner of the rectangular fill region
+//| :param int x2: x-pixel position of the second corner of the rectangular fill region (exclusive)
+//| :param int y2: y-pixel position of the second corner of the rectangular fill region (exclusive)
+//| :param int value: Bitmap palette index that will be written into the rectangular
+//| fill region in the destination bitmap"""
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value};
+
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
+
+ uint32_t value, color_depth;
+ value = args[ARG_value].u_int;
+ color_depth = (1 << destination->bits_per_value);
+ if (color_depth <= value) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+
+ int16_t x1 = args[ARG_x1].u_int;
+ int16_t y1 = args[ARG_y1].u_int;
+ int16_t x2 = args[ARG_x2].u_int;
+ int16_t y2 = args[ARG_y2].u_int;
+
+ common_hal_bitmaptools_fill_region(destination, x1, y1, x2, y2, value);
+
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_fill_region_obj, 0, bitmaptools_obj_fill_region);
+//|
+//| def boundary_fill(
+//| dest_bitmap: displayio.Bitmap,
+//| x: int, y: int,
+//| fill_color_value: int, replaced_color_value: int) -> None:
+//| """Draws the color value into the destination bitmap enclosed
+//| area of pixels of the background_value color. Like "Paint Bucket"
+//| fill tool.
+//|
+//| :param bitmap dest_bitmap: Destination bitmap that will be written into
+//| :param int x: x-pixel position of the first pixel to check and fill if needed
+//| :param int y: y-pixel position of the first pixel to check and fill if needed
+//| :param int fill_color_value: Bitmap palette index that will be written into the
+//| enclosed area in the destination bitmap
+//| :param int replaced_color_value: Bitmap palette index that will filled with the
+//| value color in the enclosed area in the destination bitmap"""
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_dest_bitmap, ARG_x, ARG_y, ARG_fill_color_value, ARG_replaced_color_value};
+
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_replaced_color_value, MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
+
+ uint32_t fill_color_value, color_depth;
+ fill_color_value = args[ARG_fill_color_value].u_int;
+ color_depth = (1 << destination->bits_per_value);
+ if (color_depth <= fill_color_value) {
+ mp_raise_ValueError(translate("value out of range of target"));
+ }
+
+ uint32_t replaced_color_value;
+ replaced_color_value = args[ARG_replaced_color_value].u_int;
+ if (replaced_color_value != INT_MAX && color_depth <= replaced_color_value) {
+ mp_raise_ValueError(translate("background value out of range of target"));
+ }
+
+ int16_t x = args[ARG_x].u_int;
+ int16_t y = args[ARG_y].u_int;
+
+ if (x < 0 || x >= destination->width) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+ if (y < 0 || y >= destination->height) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+
+ common_hal_bitmaptools_boundary_fill(destination, x, y, fill_color_value, replaced_color_value);
+
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_boundary_fill_obj, 0, bitmaptools_obj_boundary_fill);
+// requires all 6 arguments
+
+//|
+//| def draw_line(
+//| dest_bitmap: displayio.Bitmap,
+//| x1: int, y1: int,
+//| x2: int, y2: int,
+//| value: int) -> None:
+//| """Draws a line into a bitmap specified two endpoints (x1,y1) and (x2,y2).
+//|
+//| :param bitmap dest_bitmap: Destination bitmap that will be written into
+//| :param int x1: x-pixel position of the line's first endpoint
+//| :param int y1: y-pixel position of the line's first endpoint
+//| :param int x2: x-pixel position of the line's second endpoint
+//| :param int y2: y-pixel position of the line's second endpoint
+//| :param int value: Bitmap palette index that will be written into the
+//| line in the destination bitmap"""
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value};
+
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}},
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
+
+ uint32_t value, color_depth;
+ value = args[ARG_value].u_int;
+ color_depth = (1 << destination->bits_per_value);
+ if (color_depth <= value) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+
+ int16_t x1 = args[ARG_x1].u_int;
+ int16_t y1 = args[ARG_y1].u_int;
+ int16_t x2 = args[ARG_x2].u_int;
+ int16_t y2 = args[ARG_y2].u_int;
+
+ // verify points are within the bitmap boundary (inclusive)
+ if ((x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0) ||
+ (x1 >= destination->width) || (x2 >= destination->width) ||
+ (y1 >= destination->height) || (y2 >= destination->height)) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+
+ common_hal_bitmaptools_draw_line(destination, x1, y1, x2, y2, value);
+
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_line_obj, 0, bitmaptools_obj_draw_line);
+// requires all 6 arguments
+
+//| def arrayblit(bitmap: displayio.Bitmap, data: ReadableBuffer, x1: int=0, y1: int=0, x2: Optional[int]=None, y2: Optional[int]=None, skip_index:Optional[int]=None) -> None:
+//| """Inserts pixels from ``data`` into the rectangle of width×height pixels with the upper left corner at ``(x,y)``
+//|
+//| The values from ``data`` are taken modulo the number of color values
+//| avalable in the destination bitmap.
+//|
+//| If x1 or y1 are not specified, they are taken as 0. If x2 or y2
+//| are not specified, or are given as -1, they are taken as the width
+//| and height of the image.
+//|
+//| The coordinates affected by the blit are ``x1 <= x < x2`` and ``y1 <= y < y2``.
+//|
+//| ``data`` must contain at least as many elements as required. If it
+//| contains excess elements, they are ignored.
+//|
+//| The blit takes place by rows, so the first elements of ``data`` go
+//| to the first row, the next elements to the next row, and so on.
+//|
+//| :param displayio.Bitmap bitmap: A writable bitmap
+//| :param ReadableBuffer data: Buffer containing the source pixel values
+//| :param int x1: The left corner of the area to blit into (inclusive)
+//| :param int y1: The top corner of the area to blit into (inclusive)
+//| :param int x2: The right of the area to blit into (exclusive)
+//| :param int y2: The bottom corner of the area to blit into (exclusive)
+//| :param int skip_index: Bitmap palette index in the source that will not be copied,
+//| set to None to copy all pixels
+//| """
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_arrayblit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bitmap, ARG_data, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_x1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_y1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_x2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_y2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_skip_index, MP_ARG_OBJ, {.u_obj = mp_const_none } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *bitmap = mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ int x1 = args[ARG_x1].u_int;
+ int y1 = args[ARG_y1].u_int;
+ int x2 = args[ARG_x2].u_int == -1 ? bitmap->width : args[ARG_x2].u_int;
+ int y2 = args[ARG_y2].u_int == -1 ? bitmap->height : args[ARG_y2].u_int;
+
+ if ((x1 < 0) || (y1 < 0) || (x1 > x2) || (y1 > y2) || (x2 > bitmap->width) || (y2 > bitmap->height)) {
+ mp_raise_IndexError(translate("pixel coordinates out of bounds"));
+ }
+
+ size_t output_element_count = (x2 - x1) * (y2 - y1);
+ size_t element_size = mp_binary_get_size('@', bufinfo.typecode, NULL);
+ size_t input_element_count = bufinfo.len / element_size;
+
+ bool skip_specified = args[ARG_skip_index].u_obj != mp_const_none;
+ uint32_t skip_index = skip_specified ? mp_obj_get_int(args[ARG_skip_index].u_obj) : 0;
+ if (input_element_count < output_element_count) {
+ mp_raise_IndexError(translate("index out of range"));
+ }
+
+ common_hal_bitmaptools_arrayblit(bitmap, bufinfo.buf, element_size, x1, y1, x2, y2, skip_specified, skip_index);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_arrayblit_obj, 0, bitmaptools_arrayblit);
+
+
+//| def readinto(bitmap: displayio.Bitmap, file: typing.BinaryIO, bits_per_pixel: int, element_size: int = 1, reverse_pixels_in_element: bool = False, swap_bytes_in_element: bool = False, reverse_rows: bool = False) -> None:
+//| """Reads from a binary file into a bitmap.
+//|
+//| The file must be positioned so that it consists of ``bitmap.height`` rows of pixel data, where each row is the smallest multiple of ``element_size`` bytes that can hold ``bitmap.width`` pixels.
+//|
+//| The bytes in an element can be optionally swapped, and the pixels in an element can be reversed. Also, the
+//| row loading direction can be reversed, which may be requires for loading certain bitmap files.
+//|
+//| This function doesn't parse image headers, but is useful to speed up loading of uncompressed image formats such as PCF glyph data.
+//|
+//| :param displayio.Bitmap bitmap: A writable bitmap
+//| :param typing.BinaryIO file: A file opened in binary mode
+//| :param int bits_per_pixel: Number of bits per pixel. Values 1, 2, 4, 8, 16, 24, and 32 are supported;
+//| :param int element_size: Number of bytes per element. Values of 1, 2, and 4 are supported, except that 24 ``bits_per_pixel`` requires 1 byte per element.
+//| :param bool reverse_pixels_in_element: If set, the first pixel in a word is taken from the Most Signficant Bits; otherwise, it is taken from the Least Significant Bits.
+//| :param bool swap_bytes_in_element: If the ``element_size`` is not 1, then reverse the byte order of each element read.
+//| :param bool reverse_rows: Reverse the direction of the row loading (required for some bitmap images).
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bitmap, ARG_file, ARG_bits_per_pixel, ARG_element_size, ARG_reverse_pixels_in_element, ARG_swap_bytes_in_element, ARG_reverse_rows };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_element_size, MP_ARG_INT, { .u_int = 1 } },
+ { MP_QSTR_reverse_pixels_in_element, MP_ARG_BOOL, { .u_bool = false } },
+ { MP_QSTR_swap_bytes_in_element, MP_ARG_BOOL, { .u_bool = false } },
+ { MP_QSTR_reverse_rows, MP_ARG_BOOL, { .u_bool = false } },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *bitmap = mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap);
+
+ mp_obj_t *file = args[ARG_file].u_obj;
+
+ int element_size = args[ARG_element_size].u_int;
+ if (element_size != 1 && element_size != 2 && element_size != 4) {
+ mp_raise_ValueError_varg(translate("invalid element_size %d, must be, 1, 2, or 4"), element_size);
+ }
+
+ int bits_per_pixel = args[ARG_bits_per_pixel].u_int;
+ switch (bits_per_pixel) {
+ case 24:
+ if (element_size != 1) {
+ mp_raise_ValueError_varg(translate("invalid element size %d for bits_per_pixel %d\n"), element_size, bits_per_pixel);
+ }
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ mp_raise_ValueError_varg(translate("invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32"), bits_per_pixel);
+ }
+
+ bool reverse_pixels_in_element = args[ARG_reverse_pixels_in_element].u_bool;
+ bool swap_bytes_in_element = args[ARG_swap_bytes_in_element].u_bool;
+ bool reverse_rows = args[ARG_reverse_rows].u_bool;
+
+ common_hal_bitmaptools_readinto(bitmap, file, element_size, bits_per_pixel, reverse_pixels_in_element, swap_bytes_in_element, reverse_rows);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto);
+
+//| class DitherAlgorithm:
+//| """Identifies the algorith for dither to use"""
+//|
+//| Atkinson: "DitherAlgorithm"
+//| """The classic Atkinson dither, often associated with the Hypercard esthetic"""
+//|
+//| FloydStenberg: "DitherAlgorithm"
+//| """The Floyd-Stenberg dither"""
+//|
+MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, Atkinson, DITHER_ALGORITHM_ATKINSON);
+MAKE_ENUM_VALUE(bitmaptools_dither_algorithm_type, dither_algorithm, FloydStenberg, DITHER_ALGORITHM_FLOYD_STENBERG);
+
+MAKE_ENUM_MAP(bitmaptools_dither_algorithm) {
+ MAKE_ENUM_MAP_ENTRY(dither_algorithm, Atkinson),
+ MAKE_ENUM_MAP_ENTRY(dither_algorithm, FloydStenberg),
+};
+STATIC MP_DEFINE_CONST_DICT(bitmaptools_dither_algorithm_locals_dict, bitmaptools_dither_algorithm_locals_table);
+
+MAKE_PRINTER(bitmaptools, bitmaptools_dither_algorithm);
+
+MAKE_ENUM_TYPE(bitmaptools, DitherAlgorithm, bitmaptools_dither_algorithm);
+
+//| def dither(dest_bitmap: displayio.Bitmap, source_bitmapp: displayio.Bitmap, source_colorspace: displayio.Colorspace, algorithm: DitherAlgorithm=DitherAlgorithm.Atkinson) -> None:
+//| """Convert the input image into a 2-level output image using the given dither algorithm.
+//|
+//| :param bitmap dest_bitmap: Destination bitmap. It must have a value_count of 2 or 65536. The stored values are 0 and the maximum pixel value.
+//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be dithered. It must have a value_count of 65536.
+//| :param colorspace: The colorspace of the image. The supported colorspaces are ``RGB565``, ``BGR565``, ``RGB565_SWAPPED``, and ``BGR565_SWAPPED``
+//| :param algorithm: The dither algorithm to use, one of the `DitherAlgorithm` values.
+//| """
+//| ...
+//|
+STATIC mp_obj_t bitmaptools_dither(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_dest_bitmap, ARG_source_bitmap, ARG_source_colorspace, ARG_algorithm };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_algorithm, MP_ARG_OBJ, { .u_obj = MP_ROM_PTR((void *)&dither_algorithm_Atkinson_obj) } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ displayio_bitmap_t *source_bitmap = mp_arg_validate_type(args[ARG_source_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);
+ displayio_bitmap_t *dest_bitmap = mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap);
+ bitmaptools_dither_algorithm_t algorithm = cp_enum_value(&bitmaptools_dither_algorithm_type, args[ARG_algorithm].u_obj);
+ displayio_colorspace_t colorspace = cp_enum_value(&displayio_colorspace_type, args[ARG_source_colorspace].u_obj);
+
+ if (source_bitmap->width != dest_bitmap->width || source_bitmap->height != dest_bitmap->height) {
+ mp_raise_TypeError(translate("bitmap sizes must match"));
+ }
+
+ if (dest_bitmap->bits_per_value != 16 && dest_bitmap->bits_per_value != 1) {
+ mp_raise_TypeError(translate("source_bitmap must have value_count of 2 or 65536"));
+ }
+
+
+ switch (colorspace) {
+ case DISPLAYIO_COLORSPACE_RGB565:
+ case DISPLAYIO_COLORSPACE_RGB565_SWAPPED:
+ case DISPLAYIO_COLORSPACE_BGR565:
+ case DISPLAYIO_COLORSPACE_BGR565_SWAPPED:
+ if (source_bitmap->bits_per_value != 16) {
+ mp_raise_TypeError(translate("source_bitmap must have value_count of 65536"));
+ }
+ break;
+
+ case DISPLAYIO_COLORSPACE_L8:
+ if (source_bitmap->bits_per_value != 8) {
+ mp_raise_TypeError(translate("source_bitmap must have value_count of 8"));
+ }
+ break;
+
+ default:
+ mp_raise_TypeError(translate("unsupported colorspace for dither"));
+ }
+
+
+ common_hal_bitmaptools_dither(dest_bitmap, source_bitmap, colorspace, algorithm);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_dither_obj, 0, bitmaptools_dither);
+
+
+STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmaptools) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
+ { MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
+ { MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
+ { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&bitmaptools_dither_obj) },
+ { MP_ROM_QSTR(MP_QSTR_DitherAlgorithm), MP_ROM_PTR(&bitmaptools_dither_algorithm_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table);
+
+const mp_obj_module_t bitmaptools_module = {
+ .base = {&mp_type_module },
+ .globals = (mp_obj_dict_t *)&bitmaptools_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_bitmaptools, bitmaptools_module, CIRCUITPY_BITMAPTOOLS);
diff --git a/circuitpython/shared-bindings/bitmaptools/__init__.h b/circuitpython/shared-bindings/bitmaptools/__init__.h
new file mode 100644
index 0000000..fb5c789
--- /dev/null
+++ b/circuitpython/shared-bindings/bitmaptools/__init__.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Kevin Matocha
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
+
+#include "shared-module/displayio/Bitmap.h"
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/__init__.h"
+#include "shared-module/displayio/Palette.h"
+#include "py/obj.h"
+#include "extmod/vfs_fat.h"
+
+typedef enum {
+ DITHER_ALGORITHM_ATKINSON, DITHER_ALGORITHM_FLOYD_STENBERG,
+} bitmaptools_dither_algorithm_t;
+
+extern const mp_obj_type_t bitmaptools_dither_algorithm_type;
+
+void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy,
+ int16_t dest_clip0_x, int16_t dest_clip0_y,
+ int16_t dest_clip1_x, int16_t dest_clip1_y,
+ displayio_bitmap_t *source, int16_t px, int16_t py,
+ int16_t source_clip0_x, int16_t source_clip0_y,
+ int16_t source_clip1_x, int16_t source_clip1_y,
+ mp_float_t angle,
+ mp_float_t scale,
+ uint32_t skip_index, bool skip_index_none);
+
+void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
+ int16_t x1, int16_t y1,
+ int16_t x2, int16_t y2,
+ uint32_t value);
+
+void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination,
+ int16_t x, int16_t y,
+ uint32_t fill_color_value, uint32_t replaced_color_value);
+
+void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
+ int16_t x0, int16_t y0,
+ int16_t x1, int16_t y1,
+ uint32_t value);
+
+void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, mp_obj_t *file, int element_size, int bits_per_pixel, bool reverse_pixels_in_word, bool swap_bytes, bool reverse_rows);
+void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int element_size, int x1, int y1, int x2, int y2, bool skip_specified, uint32_t skip_index);
+void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm);
+
+void common_hal_bitmaptools_alphablend(displayio_bitmap_t *destination, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, mp_float_t factor1, mp_float_t factor2);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
diff --git a/circuitpython/shared-bindings/bitops/__init__.c b/circuitpython/shared-bindings/bitops/__init__.c
new file mode 100644
index 0000000..5b455dc
--- /dev/null
+++ b/circuitpython/shared-bindings/bitops/__init__.c
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/bitops/__init__.h"
+
+//| """Routines for low-level manipulation of binary data"""
+//|
+//|
+
+//| def bit_transpose(input: ReadableBuffer, output: WriteableBuffer, width:int = 8) -> WriteableBuffer:
+//| """"Transpose" a buffer by assembling each output byte with bits taken from each of ``width`` different input bytes.
+//|
+//| This can be useful to convert a sequence of pixel values into a single
+//| stream of bytes suitable for sending via a parallel conversion method.
+//|
+//| The number of bytes in the input buffer must be a multiple of the width,
+//| and the width can be any value from 2 to 8. If the width is fewer than 8,
+//| then the remaining (less significant) bits of the output are set to zero.
+//|
+//| Let ``stride = len(input)//width``. Then the first byte is made out of the
+//| most significant bits of ``[input[0], input[stride], input[2*stride], ...]``.
+//| The second byte is made out of the second bits, and so on until the 8th output
+//| byte which is made of the first bits of ``input[1], input[1+stride,
+//| input[2*stride], ...]``.
+//|
+//| The required output buffer size is ``len(input) * 8 // width``.
+//|
+//| Returns the output buffer."""
+//| ...
+
+STATIC mp_obj_t bit_transpose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_input, ARG_output, ARG_width };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_input, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_output, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_width, MP_ARG_INT, { .u_int = 8 } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int width = args[ARG_width].u_int;
+ if (width < 2 || width > 8) {
+ mp_raise_ValueError_varg(translate("width must be from 2 to 8 (inclusive), not %d"), width);
+ }
+
+ mp_buffer_info_t input_bufinfo;
+ mp_get_buffer_raise(args[ARG_input].u_obj, &input_bufinfo, MP_BUFFER_READ);
+ int inlen = input_bufinfo.len;
+ if (inlen % width != 0) {
+ mp_raise_ValueError_varg(translate("Input buffer length (%d) must be a multiple of the strand count (%d)"), inlen, width);
+ }
+
+ mp_buffer_info_t output_bufinfo;
+ mp_get_buffer_raise(args[ARG_output].u_obj, &output_bufinfo, MP_BUFFER_WRITE);
+ int avail = output_bufinfo.len;
+ int outlen = 8 * (inlen / width);
+ if (avail < outlen) {
+ mp_raise_ValueError_varg(translate("Output buffer must be at least %d bytes"), outlen);
+ }
+ common_hal_bitops_bit_transpose(output_bufinfo.buf, input_bufinfo.buf, inlen, width);
+ return args[ARG_output].u_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bitops_bit_transpose_obj, 0, bit_transpose);
+
+STATIC const mp_rom_map_elem_t bitops_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitops) },
+ { MP_ROM_QSTR(MP_QSTR_bit_transpose), MP_ROM_PTR(&bitops_bit_transpose_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bitops_module_globals, bitops_module_globals_table);
+
+const mp_obj_module_t bitops_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&bitops_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_bitops, bitops_module, CIRCUITPY_BITOPS);
diff --git a/circuitpython/shared-bindings/bitops/__init__.h b/circuitpython/shared-bindings/bitops/__init__.h
new file mode 100644
index 0000000..4d61d52
--- /dev/null
+++ b/circuitpython/shared-bindings/bitops/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>
+
+void common_hal_bitops_bit_transpose(uint8_t *result, const uint8_t *src, size_t inlen, size_t num_strands);
diff --git a/circuitpython/shared-bindings/board/__init__.c b/circuitpython/shared-bindings/board/__init__.c
new file mode 100644
index 0000000..e4003d4
--- /dev/null
+++ b/circuitpython/shared-bindings/board/__init__.c
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/board/__init__.h"
+#if CIRCUITPY_BOARD_I2C
+#include "shared-bindings/busio/I2C.h"
+#endif
+#if CIRCUITPY_BOARD_SPI
+#include "shared-bindings/busio/SPI.h"
+#endif
+#if CIRCUITPY_BOARD_UART
+#include "shared-bindings/busio/UART.h"
+#endif
+
+//| """Board specific pin names
+//|
+//| Common container for board base pin names. These will vary from board to
+//| board so don't expect portability when using this module.
+//|
+//| Another common use of this module is to use serial communciation buses with
+//| the default pins and settings. For more information about serial communcication
+//| in CircuitPython, see the :mod:`busio`.
+//|
+//| For more information regarding the typical usage of :py:mod:`board`, refer to the `CircuitPython
+//| Essentials Learn guide
+//| <https://learn.adafruit.com/circuitpython-essentials/circuitpython-pins-and-modules>`_
+//|
+//| .. warning:: The board module varies by board. The APIs documented here may or may not be
+//| available on a specific board."""
+
+//| board_id: str
+//| """Board ID string. The unique identifier for the board model in
+//| circuitpython, as well as on circuitpython.org.
+//| Example: "hallowing_m0_express"."""
+
+//| def I2C() -> busio.I2C:
+//| """Returns the `busio.I2C` object for the board's designated I2C bus(es).
+//| The object created is a singleton, and uses the default parameter values for `busio.I2C`."""
+//| ...
+//|
+#if CIRCUITPY_BOARD_I2C
+STATIC mp_obj_t board_i2c_0(void) {
+ return common_hal_board_create_i2c(0);
+}
+#else
+STATIC mp_obj_t board_i2c_0(void) {
+ mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C);
+ return MP_ROM_NONE;
+}
+#endif
+MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c_0);
+
+//| def SPI() -> busio.SPI:
+//| """Returns the `busio.SPI` object for the board's designated SPI bus(es).
+//| The object created is a singleton, and uses the default parameter values for `busio.SPI`."""
+//| ...
+//|
+#if CIRCUITPY_BOARD_SPI
+STATIC mp_obj_t board_spi_0(void) {
+ return common_hal_board_create_spi(0);
+}
+#else
+STATIC mp_obj_t board_spi_0(void) {
+ mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI);
+ return MP_ROM_NONE;
+}
+#endif
+MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi_0);
+
+//| def UART() -> busio.UART:
+//| """Returns the `busio.UART` object for the board's designated UART bus(es).
+//| The object created is a singleton, and uses the default parameter values for `busio.UART`."""
+//| ...
+//|
+#if CIRCUITPY_BOARD_UART
+STATIC mp_obj_t board_uart_0(void) {
+ return common_hal_board_create_uart(0);
+}
+#else
+STATIC mp_obj_t board_uart_0(void) {
+ mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_UART);
+ return MP_ROM_NONE;
+}
+#endif
+MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart_0);
+
+const mp_obj_module_t board_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&board_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_board, board_module, CIRCUITPY_BOARD);
diff --git a/circuitpython/shared-bindings/board/__init__.h b/circuitpython/shared-bindings/board/__init__.h
new file mode 100644
index 0000000..b668e0a
--- /dev/null
+++ b/circuitpython/shared-bindings/board/__init__.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BOARD___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BOARD___INIT___H
+
+#include "py/obj.h"
+#include "py/objstr.h"
+
+#include "shared-bindings/microcontroller/Pin.h" // for the pin definitions
+
+extern const mp_obj_dict_t board_module_globals;
+STATIC const MP_DEFINE_STR_OBJ(board_module_id_obj, CIRCUITPY_BOARD_ID);
+
+bool common_hal_board_is_i2c(mp_obj_t obj);
+mp_obj_t common_hal_board_get_i2c(const mp_int_t instance);
+mp_obj_t common_hal_board_create_i2c(const mp_int_t instance);
+mp_obj_t board_i2c(size_t n_args, const mp_obj_t *args);
+MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj);
+
+bool common_hal_board_is_spi(mp_obj_t obj);
+mp_obj_t common_hal_board_get_spi(const mp_int_t instance);
+mp_obj_t common_hal_board_create_spi(const mp_int_t instance);
+mp_obj_t board_spi(size_t n_args, const mp_obj_t *args);
+MP_DECLARE_CONST_FUN_OBJ_0(board_spi_obj);
+
+bool common_hal_board_is_uart(mp_obj_t obj);
+mp_obj_t common_hal_board_get_uart(const mp_int_t instance);
+mp_obj_t common_hal_board_create_uart(const mp_int_t instance);
+mp_obj_t board_uart(size_t n_args, const mp_obj_t *args);
+MP_DECLARE_CONST_FUN_OBJ_0(board_uart_obj);
+
+#define CIRCUITPY_BOARD_BUS_SINGLETON(name, bus, instance) \
+ STATIC mp_obj_t board_##name(void) { \
+ return common_hal_board_create_##bus(instance); \
+ } \
+ MP_DEFINE_CONST_FUN_OBJ_0(board_##name##_obj, board_##name);
+
+#define CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS \
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, \
+ { MP_ROM_QSTR(MP_QSTR_board_id), MP_ROM_PTR(&board_module_id_obj) },
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BOARD___INIT___H
diff --git a/circuitpython/shared-bindings/busio/I2C.c b/circuitpython/shared-bindings/busio/I2C.c
new file mode 100644
index 0000000..2d67281
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/I2C.c
@@ -0,0 +1,372 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// busio.I2C class.
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/busio/I2C.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class I2C:
+//| """Two wire serial protocol"""
+//|
+//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 100000, timeout: int = 255) -> None:
+//|
+//| """I2C is a two-wire protocol for communicating between devices. At the
+//| physical level it consists of 2 wires: SCL and SDA, the clock and data
+//| lines respectively.
+//|
+//| .. seealso:: Using this class directly requires careful lock management.
+//| Instead, use :class:`~adafruit_bus_device.I2CDevice` to
+//| manage locks.
+//|
+//| .. seealso:: Using this class to directly read registers requires manual
+//| bit unpacking. Instead, use an existing driver or make one with
+//| :ref:`Register <register-module-reference>` data descriptors.
+//|
+//| :param ~microcontroller.Pin scl: The clock pin
+//| :param ~microcontroller.Pin sda: The data pin
+//| :param int frequency: The clock frequency in Hertz
+//| :param int timeout: The maximum clock stretching timeut - (used only for
+//| :class:`bitbangio.I2C`; ignored for :class:`busio.I2C`)
+//| """
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t);
+ self->base.type = &busio_i2c_type;
+ enum { ARG_scl, ARG_sda, ARG_frequency, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj);
+ const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj);
+
+ common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int);
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Releases control of the underlying hardware so other classes can use it."""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_obj_deinit(mp_obj_t self_in) {
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_busio_i2c_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_deinit_obj, busio_i2c_obj_deinit);
+
+STATIC void check_for_deinit(busio_i2c_obj_t *self) {
+ if (common_hal_busio_i2c_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> I2C:
+//| """No-op used in Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware on context exit. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_busio_i2c_deinit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i2c_obj___exit__);
+
+static void check_lock(busio_i2c_obj_t *self) {
+ asm ("");
+ if (!common_hal_busio_i2c_has_lock(self)) {
+ mp_raise_RuntimeError(translate("Function requires lock"));
+ }
+}
+
+//| def scan(self) -> List[int]:
+//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a
+//| list of those that respond.
+//|
+//| :return: List of device ids on the I2C bus
+//| :rtype: list"""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_scan(mp_obj_t self_in) {
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
+ for (int addr = 0x08; addr < 0x78; ++addr) {
+ bool success = common_hal_busio_i2c_probe(self, addr);
+ if (success) {
+ mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
+ }
+ }
+ return list;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_scan_obj, busio_i2c_scan);
+
+//| def try_lock(self) -> bool:
+//| """Attempts to grab the I2C lock. Returns True on success.
+//|
+//| :return: True when lock has been grabbed
+//| :rtype: bool"""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_obj_try_lock(mp_obj_t self_in) {
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_busio_i2c_try_lock(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_try_lock_obj, busio_i2c_obj_try_lock);
+
+//| def unlock(self) -> None:
+//| """Releases the I2C lock."""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_obj_unlock(mp_obj_t self_in) {
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_busio_i2c_unlock(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock);
+
+//| import sys
+//| def readfrom_into(self, address: int, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Read into ``buffer`` from the device selected by ``address``.
+//| At least one byte must be read.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed, but without copying the data.
+//| The number of bytes read will be the length of ``buffer[start:end]``.
+//|
+//| :param int address: 7-bit device address
+//| :param WriteableBuffer buffer: buffer to write into
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``"""
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ size_t length = bufinfo.len;
+ int32_t start = args[ARG_start].u_int;
+ const int32_t end = args[ARG_end].u_int;
+ normalize_buffer_bounds(&start, end, &length);
+ if (length == 0) {
+ mp_raise_ValueError_varg(translate("%q length must be >= 1"), MP_QSTR_buffer);
+ }
+
+ uint8_t status =
+ common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length);
+ if (status != 0) {
+ mp_raise_OSError(status);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 1, busio_i2c_readfrom_into);
+
+//| import sys
+//| def writeto(self, address: int, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``buffer`` to the device selected by ``address`` and
+//| then transmit a stop bit.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``buffer[start:end]``.
+//|
+//| Writing a buffer or slice of length zero is permitted, as it can be used
+//| to poll for the existence of a device.
+//|
+//| :param int address: 7-bit device address
+//| :param ReadableBuffer buffer: buffer containing the bytes to write
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get the buffer to write the data from
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ size_t length = bufinfo.len;
+ int32_t start = args[ARG_start].u_int;
+ const int32_t end = args[ARG_end].u_int;
+ normalize_buffer_bounds(&start, end, &length);
+
+ // do the transfer
+ uint8_t status =
+ common_hal_busio_i2c_write(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length);
+
+ if (status != 0) {
+ mp_raise_OSError(status);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_writeto_obj, 1, busio_i2c_writeto);
+
+//| import sys
+//| def writeto_then_readfrom(self, address: int, out_buffer: ReadableBuffer, in_buffer: WriteableBuffer, *, out_start: int = 0, out_end: int = sys.maxsize, in_start: int = 0, in_end: int = sys.maxsize) -> None:
+//| """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate no stop
+//| bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and
+//| ``in_buffer`` can be the same buffer because they are used sequentially.
+//|
+//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
+//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``out_buffer[start:end]``.
+//|
+//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
+//| as if ``in_buffer[in_start:in_end]`` were passed,
+//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
+
+//| :param int address: 7-bit device address
+//| :param ~circuitpython_typing.ReadableBuffer out_buffer: buffer containing the bytes to write
+//| :param ~circuitpython_typing.WriteableBuffer in_buffer: buffer to write into
+//| :param int out_start: beginning of ``out_buffer`` slice
+//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
+//| :param int in_start: beginning of ``in_buffer`` slice
+//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
+//| """
+//| ...
+//|
+STATIC mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_address, ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t out_bufinfo;
+ mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &out_bufinfo, MP_BUFFER_READ);
+
+ size_t out_length = out_bufinfo.len;
+ int32_t out_start = args[ARG_out_start].u_int;
+ const int32_t out_end = args[ARG_out_end].u_int;
+ normalize_buffer_bounds(&out_start, out_end, &out_length);
+
+ mp_buffer_info_t in_bufinfo;
+ mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &in_bufinfo, MP_BUFFER_WRITE);
+
+ size_t in_length = in_bufinfo.len;
+ int32_t in_start = args[ARG_in_start].u_int;
+ const int32_t in_end = args[ARG_in_end].u_int;
+ normalize_buffer_bounds(&in_start, in_end, &in_length);
+ if (in_length == 0) {
+ mp_raise_ValueError_varg(translate("%q length must be >= 1"), MP_QSTR_out_buffer);
+ }
+
+ uint8_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int,
+ ((uint8_t *)out_bufinfo.buf) + out_start, out_length,((uint8_t *)in_bufinfo.buf) + in_start, in_length);
+ if (status != 0) {
+ mp_raise_OSError(status);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_writeto_then_readfrom_obj, 1, busio_i2c_writeto_then_readfrom);
+
+STATIC const mp_rom_map_elem_t busio_i2c_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_i2c_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_i2c___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&busio_i2c_scan_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&busio_i2c_try_lock_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&busio_i2c_unlock_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&busio_i2c_readfrom_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&busio_i2c_writeto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeto_then_readfrom), MP_ROM_PTR(&busio_i2c_writeto_then_readfrom_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(busio_i2c_locals_dict, busio_i2c_locals_dict_table);
+
+const mp_obj_type_t busio_i2c_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2C,
+ .make_new = busio_i2c_make_new,
+ .locals_dict = (mp_obj_dict_t *)&busio_i2c_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/busio/I2C.h b/circuitpython/shared-bindings/busio/I2C.h
new file mode 100644
index 0000000..0999865
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/I2C.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// Machine is the HAL for low-level, hardware accelerated functions. It is not
+// meant to simplify APIs, its only meant to unify them so that other modules
+// do not require port specific logic.
+//
+// This file includes externs for all functions a port should implement to
+// support the machine module.
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/busio/I2C.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t busio_i2c_type;
+
+// Initializes the hardware peripheral.
+extern void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
+ const mcu_pin_obj_t *scl,
+ const mcu_pin_obj_t *sda,
+ uint32_t frequency,
+ uint32_t timeout);
+
+extern void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self);
+extern bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self);
+
+extern bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self);
+extern bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self);
+extern void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self);
+
+// Probe the bus to see if a device acknowledges the given address.
+extern bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr);
+
+// Write to the device and return 0 on success or an appropriate error code from mperrno.h
+extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address,
+ const uint8_t *data, size_t len);
+
+// Reads memory of the i2c device picking up where it left off and return 0 on
+// success or an appropriate error code from mperrno.h
+extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address,
+ uint8_t *data, size_t len);
+
+// Do a write and then a read in the same I2C transaction.
+uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address,
+ uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len);
+
+// This is used by the supervisor to claim I2C devices indefinitely.
+extern void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H
diff --git a/circuitpython/shared-bindings/busio/SPI.c b/circuitpython/shared-bindings/busio/SPI.c
new file mode 100644
index 0000000..0a6c32f
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/SPI.c
@@ -0,0 +1,463 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// busio.SPI class.
+
+#include <string.h>
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/mperrno.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+
+//| class SPI:
+//| """A 3-4 wire serial protocol
+//|
+//| SPI is a serial protocol that has exclusive pins for data in and out of the
+//| main device. It is typically faster than :py:class:`~bitbangio.I2C` because a
+//| separate pin is used to select a device rather than a transmitted
+//| address. This class only manages three of the four SPI lines: `!clock`,
+//| `!MOSI`, `!MISO`. Its up to the client to manage the appropriate
+//| select line, often abbreviated `!CS` or `!SS`. (This is common because
+//| multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines
+//| and therefore the hardware.)"""
+//|
+//| def __init__(self, clock: microcontroller.Pin, MOSI: Optional[microcontroller.Pin] = None, MISO: Optional[microcontroller.Pin] = None, half_duplex: bool = False) -> None:
+//|
+//| """Construct an SPI object on the given pins.
+//|
+//| .. note:: The SPI peripherals allocated in order of desirability, if possible,
+//| such as highest speed and not shared use first. For instance, on the nRF52840,
+//| there is a single 32MHz SPI peripheral, and multiple 8MHz peripherals,
+//| some of which may also be used for I2C. The 32MHz SPI peripheral is returned
+//| first, then the exclusive 8MHz SPI peripheral, and finally the shared 8MHz
+//| peripherals.
+//|
+//| .. seealso:: Using this class directly requires careful lock management.
+//| Instead, use :class:`~adafruit_bus_device.SPIDevice` to
+//| manage locks.
+//|
+//| .. seealso:: Using this class to directly read registers requires manual
+//| bit unpacking. Instead, use an existing driver or make one with
+//| :ref:`Register <register-module-reference>` data descriptors.
+//|
+//| :param ~microcontroller.Pin clock: the pin to use for the clock.
+//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin.
+//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin.
+//| :param bool half_duplex: True when MOSI is used for bidirectional data. False when SPI is full-duplex or simplex."""
+//| ...
+//|
+
+
+// TODO(tannewt): Support LSB SPI.
+STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ #if CIRCUITPY_BUSIO_SPI
+ busio_spi_obj_t *self = m_new_obj(busio_spi_obj_t);
+ self->base.type = &busio_spi_type;
+ enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_half_duplex, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj);
+ const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj);
+
+ if (!miso && !mosi) {
+ mp_raise_ValueError(translate("Must provide MISO or MOSI pin"));
+ }
+
+ common_hal_busio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool);
+ return MP_OBJ_FROM_PTR(self);
+ #else
+ mp_raise_ValueError(translate("Invalid pins"));
+ #endif // CIRCUITPY_BUSIO_SPI
+}
+
+#if CIRCUITPY_BUSIO_SPI
+//| def deinit(self) -> None:
+//| """Turn off the SPI bus."""
+//| ...
+//|
+STATIC mp_obj_t busio_spi_obj_deinit(mp_obj_t self_in) {
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_busio_spi_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit);
+
+//| def __enter__(self) -> SPI:
+//| """No-op used by Context Managers.
+//| Provided by context manager helper."""
+//| ...
+//|
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t busio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_busio_spi_deinit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_spi_obj___exit___obj, 4, 4, busio_spi_obj___exit__);
+
+STATIC void check_lock(busio_spi_obj_t *self) {
+ asm ("");
+ if (!common_hal_busio_spi_has_lock(self)) {
+ mp_raise_RuntimeError(translate("Function requires lock"));
+ }
+}
+
+STATIC void check_for_deinit(busio_spi_obj_t *self) {
+ if (common_hal_busio_spi_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def configure(self, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, bits: int = 8) -> None:
+//| """Configures the SPI bus. The SPI object must be locked.
+//|
+//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower
+//| due to the granularity of available clock settings.
+//| Check the `frequency` attribute for the actual clock rate.
+//| :param int polarity: the base state of the clock line (0 or 1)
+//| :param int phase: the edge of the clock that data is captured. First (0)
+//| or second (1). Rising or falling depends on clock polarity.
+//| :param int bits: the number of bits per word
+//|
+//| .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that
+//| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is
+//| within spec for the SAMD21.
+//|
+//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz,
+//| and 8MHz.
+//| If you pick a a baudrate other than one of these, the nearest lower
+//| baudrate will be chosen, with a minimum of 125kHz.
+//| Two SPI objects may be created, except on the Circuit Playground Bluefruit,
+//| which allows only one (to allow for an additional I2C object)."""
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ };
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t polarity = args[ARG_polarity].u_int;
+ if (polarity != 0 && polarity != 1) {
+ mp_raise_ValueError(translate("Invalid polarity"));
+ }
+ uint8_t phase = args[ARG_phase].u_int;
+ if (phase != 0 && phase != 1) {
+ mp_raise_ValueError(translate("Invalid phase"));
+ }
+ uint8_t bits = args[ARG_bits].u_int;
+ if (bits != 8 && bits != 9) {
+ mp_raise_ValueError(translate("Invalid number of bits"));
+ }
+
+ if (!common_hal_busio_spi_configure(self, args[ARG_baudrate].u_int,
+ polarity, phase, bits)) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_configure_obj, 1, busio_spi_configure);
+
+//| def try_lock(self) -> bool:
+//| """Attempts to grab the SPI lock. Returns True on success.
+//|
+//| :return: True when lock has been grabbed
+//| :rtype: bool"""
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_obj_try_lock(mp_obj_t self_in) {
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_busio_spi_try_lock(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_try_lock_obj, busio_spi_obj_try_lock);
+
+//| def unlock(self) -> None:
+//| """Releases the SPI lock."""
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_obj_unlock(mp_obj_t self_in) {
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_busio_spi_unlock(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock);
+
+//| import sys
+//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None:
+//| """Write the data contained in ``buffer``. The SPI object must be locked.
+//| If the buffer is empty, nothing happens.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``buffer[start:end]``.
+//|
+//| :param ReadableBuffer buffer: write out bytes from this buffer
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, use ``len(buffer)``
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+ int32_t start = args[ARG_start].u_int;
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+
+ if (length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = common_hal_busio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 1, busio_spi_write);
+
+
+//| import sys
+//| def readinto(self, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize, write_value: int = 0) -> None:
+//| """Read into ``buffer`` while writing ``write_value`` for each byte read.
+//| The SPI object must be locked.
+//| If the number of bytes to read is 0, nothing happens.
+//|
+//| If ``start`` or ``end`` is provided, then the buffer will be sliced
+//| as if ``buffer[start:end]`` were passed.
+//| The number of bytes read will be the length of ``buffer[start:end]``.
+//|
+//| :param WriteableBuffer buffer: read bytes into this buffer
+//| :param int start: beginning of buffer slice
+//| :param int end: end of buffer slice; if not specified, it will be the equivalent value
+//| of ``len(buffer)`` and for any value provided it will take the value of
+//| ``min(end, len(buffer))``
+//| :param int write_value: value to write while reading
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_write_value,MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+ int32_t start = args[ARG_start].u_int;
+ size_t length = bufinfo.len;
+ normalize_buffer_bounds(&start, args[ARG_end].u_int, &length);
+
+ if (length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = common_hal_busio_spi_read(self, ((uint8_t *)bufinfo.buf) + start, length, args[ARG_write_value].u_int);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 1, busio_spi_readinto);
+
+//| import sys
+//| def write_readinto(self, out_buffer: ReadableBuffer, in_buffer: WriteableBuffer, *, out_start: int = 0, out_end: int = sys.maxsize, in_start: int = 0, in_end: int = sys.maxsize) -> None:
+//| """Write out the data in ``out_buffer`` while simultaneously reading data into ``in_buffer``.
+//| The SPI object must be locked.
+//|
+//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
+//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
+//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``.
+//|
+//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
+//| as if ``in_buffer[in_start:in_end]`` were passed,
+//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
+//|
+//| The lengths of the slices defined by ``out_buffer[out_start:out_end]``
+//| and ``in_buffer[in_start:in_end]`` must be equal.
+//| If buffer slice lengths are both 0, nothing happens.
+//|
+//| :param ReadableBuffer out_buffer: write out bytes from this buffer
+//| :param WriteableBuffer in_buffer: read bytes into this buffer
+//| :param int out_start: beginning of ``out_buffer`` slice
+//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
+//| :param int in_start: beginning of ``in_buffer`` slice
+//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
+ };
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ check_lock(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t buf_out_info;
+ mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &buf_out_info, MP_BUFFER_READ);
+ int32_t out_start = args[ARG_out_start].u_int;
+ size_t out_length = buf_out_info.len;
+ normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length);
+
+ mp_buffer_info_t buf_in_info;
+ mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &buf_in_info, MP_BUFFER_WRITE);
+ int32_t in_start = args[ARG_in_start].u_int;
+ size_t in_length = buf_in_info.len;
+ normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length);
+
+ if (out_length != in_length) {
+ mp_raise_ValueError(translate("buffer slices must be of equal length"));
+ }
+
+ if (out_length == 0) {
+ return mp_const_none;
+ }
+
+ bool ok = common_hal_busio_spi_transfer(self,
+ ((uint8_t *)buf_out_info.buf) + out_start,
+ ((uint8_t *)buf_in_info.buf) + in_start,
+ out_length);
+ if (!ok) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 1, busio_spi_write_readinto);
+
+//| frequency: int
+//| """The actual SPI bus frequency. This may not match the frequency requested
+//| due to internal limitations."""
+//|
+
+STATIC mp_obj_t busio_spi_obj_get_frequency(mp_obj_t self_in) {
+ busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_busio_spi_get_frequency(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_get_frequency_obj, busio_spi_obj_get_frequency);
+
+MP_PROPERTY_GETTER(busio_spi_frequency_obj,
+ (mp_obj_t)&busio_spi_get_frequency_obj);
+#endif // CIRCUITPY_BUSIO_SPI
+
+
+STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = {
+ #if CIRCUITPY_BUSIO_SPI
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_spi_obj___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&busio_spi_configure_obj) },
+ { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&busio_spi_try_lock_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&busio_spi_unlock_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&busio_spi_frequency_obj) }
+ #endif // CIRCUITPY_BUSIO_SPI
+};
+STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table);
+
+const mp_obj_type_t busio_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .make_new = busio_spi_make_new,
+ .locals_dict = (mp_obj_dict_t *)&busio_spi_locals_dict,
+};
+
+busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj) {
+ if (!mp_obj_is_type(obj, &busio_spi_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), busio_spi_type.name);
+ }
+ return MP_OBJ_TO_PTR(obj);
+}
diff --git a/circuitpython/shared-bindings/busio/SPI.h b/circuitpython/shared-bindings/busio/SPI.h
new file mode 100644
index 0000000..7616658
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/SPI.h
@@ -0,0 +1,75 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/busio/SPI.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t busio_spi_type;
+
+// Construct an underlying SPI object.
+extern void common_hal_busio_spi_construct(busio_spi_obj_t *self,
+ const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi,
+ const mcu_pin_obj_t *miso, bool half_duplex);
+
+extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self);
+extern bool common_hal_busio_spi_deinited(busio_spi_obj_t *self);
+
+extern bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits);
+
+extern bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self);
+extern bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self);
+extern void common_hal_busio_spi_unlock(busio_spi_obj_t *self);
+
+// Writes out the given data.
+extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len);
+
+// Reads in len bytes while outputting the byte write_value.
+extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value);
+
+// Reads and write len bytes simultaneously.
+extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len);
+
+// Return actual SPI bus frequency.
+uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self);
+
+// Return SPI bus phase.
+uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self);
+
+// Return SPI bus polarity.
+uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self);
+
+// This is used by the supervisor to claim SPI devices indefinitely.
+extern void common_hal_busio_spi_never_reset(busio_spi_obj_t *self);
+
+extern busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj_in);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H
diff --git a/circuitpython/shared-bindings/busio/UART.c b/circuitpython/shared-bindings/busio/UART.c
new file mode 100644
index 0000000..ae14e31
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/UART.c
@@ -0,0 +1,462 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/busio/UART.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "shared/runtime/interrupt_char.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "supervisor/shared/translate.h"
+
+#define STREAM_DEBUG(...) (void)0
+// #define STREAM_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
+
+//| class UART:
+//| """A bidirectional serial protocol"""
+//| def __init__(self, tx: microcontroller.Pin, rx: microcontroller.Pin, *, baudrate: int = 9600, bits: int = 8, parity: Optional[Parity] = None, stop: int = 1, timeout: float = 1, receiver_buffer_size: int = 64) -> None:
+//| """A common bidirectional serial protocol that uses an an agreed upon speed
+//| rather than a shared clock line.
+//|
+//| :param ~microcontroller.Pin tx: the pin to transmit with, or ``None`` if this ``UART`` is receive-only.
+//| :param ~microcontroller.Pin rx: the pin to receive on, or ``None`` if this ``UART`` is transmit-only.
+//| :param ~microcontroller.Pin rts: the pin for rts, or ``None`` if rts not in use.
+//| :param ~microcontroller.Pin cts: the pin for cts, or ``None`` if cts not in use.
+//| :param ~microcontroller.Pin rs485_dir: the output pin for rs485 direction setting, or ``None`` if rs485 not in use.
+//| :param bool rs485_invert: rs485_dir pin active high when set. Active low otherwise.
+//| :param int baudrate: the transmit and receive speed.
+//| :param int bits: the number of bits per byte, 5 to 9.
+//| :param Parity parity: the parity used for error checking.
+//| :param int stop: the number of stop bits, 1 or 2.
+//| :param float timeout: the timeout in seconds to wait for the first character and between subsequent characters when reading. Raises ``ValueError`` if timeout >100 seconds.
+//| :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.)
+//|
+//| *New in CircuitPython 4.0:* ``timeout`` has incompatibly changed units from milliseconds to seconds.
+//| The new upper limit on ``timeout`` is meant to catch mistaken use of milliseconds.
+//|
+//| .. note:: RS485 support on i.MX and Raspberry Pi RP2040 is implemented in software.
+//| The timing for the ``rs485_dir`` pin signal is done on a best-effort basis, and may not meet
+//| RS485 specifications intermittently.
+//| """
+//| ...
+//|
+typedef struct {
+ mp_obj_base_t base;
+} busio_uart_parity_obj_t;
+extern const busio_uart_parity_obj_t busio_uart_parity_even_obj;
+extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj;
+
+#if CIRCUITPY_BUSIO_UART
+STATIC void validate_timeout(mp_float_t timeout) {
+ if (timeout < (mp_float_t)0.0f || timeout > (mp_float_t)100.0f) {
+ mp_raise_ValueError(translate("timeout must be 0.0-100.0 seconds"));
+ }
+}
+#endif // CIRCUITPY_BUSIO_UART
+
+STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ #if CIRCUITPY_BUSIO_UART
+ enum { ARG_tx, ARG_rx, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_receiver_buffer_size,
+ ARG_rts, ARG_cts, ARG_rs485_dir,ARG_rs485_invert};
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_rx, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 9600} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
+ { MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} },
+ { MP_QSTR_receiver_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_rs485_dir, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none } },
+ { MP_QSTR_rs485_invert, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *rx = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj);
+ const mcu_pin_obj_t *tx = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj);
+
+ if ((tx == NULL) && (rx == NULL)) {
+ mp_raise_ValueError(translate("tx and rx cannot both be None"));
+ }
+
+ if (args[ARG_bits].u_int < 5 || args[ARG_bits].u_int > 9) {
+ mp_raise_ValueError(translate("bits must be in range 5 to 9"));
+ }
+ uint8_t bits = args[ARG_bits].u_int;
+
+ busio_uart_parity_t parity = BUSIO_UART_PARITY_NONE;
+ if (args[ARG_parity].u_obj == MP_OBJ_FROM_PTR(&busio_uart_parity_even_obj)) {
+ parity = BUSIO_UART_PARITY_EVEN;
+ } else if (args[ARG_parity].u_obj == MP_OBJ_FROM_PTR(&busio_uart_parity_odd_obj)) {
+ parity = BUSIO_UART_PARITY_ODD;
+ }
+
+ uint8_t stop = args[ARG_stop].u_int;
+ if (stop != 1 && stop != 2) {
+ mp_raise_ValueError(translate("stop must be 1 or 2"));
+ }
+
+ mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ validate_timeout(timeout);
+
+ const mcu_pin_obj_t *rts = validate_obj_is_free_pin_or_none(args[ARG_rts].u_obj);
+ const mcu_pin_obj_t *cts = validate_obj_is_free_pin_or_none(args[ARG_cts].u_obj);
+ const mcu_pin_obj_t *rs485_dir = validate_obj_is_free_pin_or_none(args[ARG_rs485_dir].u_obj);
+
+ const bool rs485_invert = args[ARG_rs485_invert].u_bool;
+
+ // Always initially allocate the UART object within the long-lived heap.
+ // This is needed to avoid crashes with certain UART implementations which
+ // cannot accomodate being moved after creation. (See
+ // https://github.com/adafruit/circuitpython/issues/1056)
+ busio_uart_obj_t *self = m_new_ll_obj_with_finaliser(busio_uart_obj_t);
+ self->base.type = &busio_uart_type;
+
+ common_hal_busio_uart_construct(self, tx, rx, rts, cts, rs485_dir, rs485_invert,
+ args[ARG_baudrate].u_int, bits, parity, stop, timeout,
+ args[ARG_receiver_buffer_size].u_int, NULL, false);
+ return (mp_obj_t)self;
+ #else
+ mp_raise_ValueError(translate("Invalid pins"));
+ #endif // CIRCUITPY_BUSIO_UART
+}
+
+#if CIRCUITPY_BUSIO_UART
+
+// Helper to ensure we have the native super class instead of a subclass.
+STATIC busio_uart_obj_t *native_uart(mp_obj_t uart_obj) {
+ mp_obj_t native_uart = mp_obj_cast_to_native_base(uart_obj, MP_OBJ_FROM_PTR(&busio_uart_type));
+ if (native_uart == MP_OBJ_NULL) {
+ mp_raise_ValueError_varg(translate("Must be a %q subclass."), MP_QSTR_UART);
+ }
+ mp_obj_assert_native_inited(native_uart);
+ return MP_OBJ_TO_PTR(native_uart);
+}
+
+
+//| def deinit(self) -> None:
+//| """Deinitialises the UART and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t busio_uart_obj_deinit(mp_obj_t self_in) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ common_hal_busio_uart_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_deinit_obj, busio_uart_obj_deinit);
+
+STATIC void check_for_deinit(busio_uart_obj_t *self) {
+ if (common_hal_busio_uart_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> UART:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t busio_uart_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_busio_uart_deinit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_uart___exit___obj, 4, 4, busio_uart_obj___exit__);
+
+// These are standard stream methods. Code is in py/stream.c.
+//
+//| def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+//| """Read characters. If ``nbytes`` is specified then read at most that many
+//| bytes. Otherwise, read everything that arrives until the connection
+//| times out. Providing the number of bytes expected is highly recommended
+//| because it will be faster.
+//|
+//| :return: Data read
+//| :rtype: bytes or None"""
+//| ...
+//|
+
+//| def readinto(self, buf: WriteableBuffer) -> Optional[int]:
+//| """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: int or None (on a non-blocking error)
+//|
+//| *New in CircuitPython 4.0:* No length parameter is permitted."""
+//| ...
+//|
+
+//| def readline(self) -> bytes:
+//| """Read a line, ending in a newline character, or
+//| return None if a timeout occurs sooner, or
+//| return everything readable if no newline is found and timeout=0
+//|
+//| :return: the line read
+//| :rtype: bytes or None"""
+//| ...
+//|
+
+//| def write(self, buf: WriteableBuffer) -> Optional[int]:
+//| """Write the buffer of bytes to the bus.
+//|
+//| *New in CircuitPython 4.0:* ``buf`` must be bytes, not a string.
+//|
+//| :return: the number of bytes written
+//| :rtype: int or None"""
+//| ...
+//|
+
+// These three methods are used by the shared stream methods.
+STATIC mp_uint_t busio_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ STREAM_DEBUG("busio_uart_read stream %d\n", size);
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ byte *buf = buf_in;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ return common_hal_busio_uart_read(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ const byte *buf = buf_in;
+
+ return common_hal_busio_uart_write(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_busio_uart_rx_characters_available(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_busio_uart_ready_to_tx(self)) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+//| baudrate: int
+//| """The current baudrate."""
+//|
+STATIC mp_obj_t busio_uart_obj_get_baudrate(mp_obj_t self_in) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_busio_uart_get_baudrate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_baudrate_obj, busio_uart_obj_get_baudrate);
+
+STATIC mp_obj_t busio_uart_obj_set_baudrate(mp_obj_t self_in, mp_obj_t baudrate) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ common_hal_busio_uart_set_baudrate(self, mp_obj_get_int(baudrate));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(busio_uart_set_baudrate_obj, busio_uart_obj_set_baudrate);
+
+
+MP_PROPERTY_GETSET(busio_uart_baudrate_obj,
+ (mp_obj_t)&busio_uart_get_baudrate_obj,
+ (mp_obj_t)&busio_uart_set_baudrate_obj);
+
+//| in_waiting: int
+//| """The number of bytes in the input buffer, available to be read"""
+//|
+STATIC mp_obj_t busio_uart_obj_get_in_waiting(mp_obj_t self_in) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_busio_uart_rx_characters_available(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_in_waiting_obj, busio_uart_obj_get_in_waiting);
+
+MP_PROPERTY_GETTER(busio_uart_in_waiting_obj,
+ (mp_obj_t)&busio_uart_get_in_waiting_obj);
+
+//| timeout: float
+//| """The current timeout, in seconds (float)."""
+//|
+STATIC mp_obj_t busio_uart_obj_get_timeout(mp_obj_t self_in) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_busio_uart_get_timeout(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_timeout_obj, busio_uart_obj_get_timeout);
+
+STATIC mp_obj_t busio_uart_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ mp_float_t timeout_float = mp_obj_get_float(timeout);
+ validate_timeout(timeout_float);
+ common_hal_busio_uart_set_timeout(self, timeout_float);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(busio_uart_set_timeout_obj, busio_uart_obj_set_timeout);
+
+
+MP_PROPERTY_GETSET(busio_uart_timeout_obj,
+ (mp_obj_t)&busio_uart_get_timeout_obj,
+ (mp_obj_t)&busio_uart_set_timeout_obj);
+
+//| def reset_input_buffer(self) -> None:
+//| """Discard any unread characters in the input buffer."""
+//| ...
+//|
+STATIC mp_obj_t busio_uart_obj_reset_input_buffer(mp_obj_t self_in) {
+ busio_uart_obj_t *self = native_uart(self_in);
+ check_for_deinit(self);
+ common_hal_busio_uart_clear_rx_buffer(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer);
+#endif // CIRCUITPY_BUSIO_UART
+
+//| class Parity:
+//| """Enum-like class to define the parity used to verify correct data transfer."""
+//|
+//| ODD: int
+//| """Total number of ones should be odd."""
+//|
+//| EVEN: int
+//| """Total number of ones should be even."""
+//|
+const mp_obj_type_t busio_uart_parity_type;
+
+const busio_uart_parity_obj_t busio_uart_parity_odd_obj = {
+ { &busio_uart_parity_type },
+};
+
+const busio_uart_parity_obj_t busio_uart_parity_even_obj = {
+ { &busio_uart_parity_type },
+};
+
+STATIC const mp_rom_map_elem_t busio_uart_parity_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_ODD), MP_ROM_PTR(&busio_uart_parity_odd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_EVEN), MP_ROM_PTR(&busio_uart_parity_even_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(busio_uart_parity_locals_dict, busio_uart_parity_locals_dict_table);
+
+STATIC void busio_uart_parity_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr parity = MP_QSTR_ODD;
+ if (self_in == MP_ROM_PTR(&busio_uart_parity_even_obj)) {
+ parity = MP_QSTR_EVEN;
+ }
+ mp_printf(print, "%q.%q.%q.%q", MP_QSTR_busio, MP_QSTR_UART, MP_QSTR_Parity, parity);
+}
+
+const mp_obj_type_t busio_uart_parity_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Parity,
+ .print = busio_uart_parity_print,
+ .locals_dict = (mp_obj_dict_t *)&busio_uart_parity_locals_dict,
+};
+
+STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
+ #if CIRCUITPY_BUSIO_UART
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_uart_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_uart_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_uart___exit___obj) },
+
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&busio_uart_reset_input_buffer_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&busio_uart_timeout_obj) },
+ #endif // CIRCUITPY_BUSIO_UART
+
+ // Nested Enum-like Classes.
+ { MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(busio_uart_locals_dict, busio_uart_locals_dict_table);
+
+#if CIRCUITPY_BUSIO_UART
+STATIC const mp_stream_p_t uart_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = busio_uart_read,
+ .write = busio_uart_write,
+ .ioctl = busio_uart_ioctl,
+ .is_text = false,
+ // Disallow optional length argument for .readinto()
+ .pyserial_readinto_compatibility = true,
+};
+
+const mp_obj_type_t busio_uart_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_UART,
+ .make_new = busio_uart_make_new,
+ .locals_dict = (mp_obj_dict_t *)&busio_uart_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &uart_stream_p,
+ ),
+};
+#else
+const mp_obj_type_t busio_uart_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_UART,
+ .make_new = busio_uart_make_new,
+ .locals_dict = (mp_obj_dict_t *)&busio_uart_locals_dict,
+};
+#endif // CIRCUITPY_BUSIO_UART
diff --git a/circuitpython/shared-bindings/busio/UART.h b/circuitpython/shared-bindings/busio/UART.h
new file mode 100644
index 0000000..31b062a
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/UART.h
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/busio/UART.h"
+#include "py/ringbuf.h"
+
+extern const mp_obj_type_t busio_uart_type;
+
+typedef enum {
+ BUSIO_UART_PARITY_NONE,
+ BUSIO_UART_PARITY_EVEN,
+ BUSIO_UART_PARITY_ODD
+} busio_uart_parity_t;
+
+// Construct an underlying UART object.
+extern void common_hal_busio_uart_construct(busio_uart_obj_t *self,
+ const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx,
+ const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts,
+ const mcu_pin_obj_t *rs485_dir, bool rs485_invert,
+ uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop,
+ mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer,
+ bool sigint_enabled);
+
+extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self);
+extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self);
+
+// Read characters. len is in characters NOT bytes!
+extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self,
+ uint8_t *data, size_t len, int *errcode);
+
+// Write characters. len is in characters NOT bytes!
+extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self,
+ const uint8_t *data, size_t len, int *errcode);
+
+extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self);
+extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate);
+extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self);
+extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout);
+
+extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self);
+extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self);
+extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self);
+
+extern void common_hal_busio_uart_never_reset(busio_uart_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H
diff --git a/circuitpython/shared-bindings/busio/__init__.c b/circuitpython/shared-bindings/busio/__init__.c
new file mode 100644
index 0000000..38bbfaf
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/__init__.c
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/busio/__init__.h"
+#include "shared-bindings/busio/I2C.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/busio/UART.h"
+#if CIRCUITPY_ONEWIREIO
+#include "shared-bindings/onewireio/OneWire.h"
+#endif
+
+#include "py/runtime.h"
+
+//| """Hardware accelerated external bus access
+//|
+//| The `busio` module contains classes to support a variety of serial
+//| protocols.
+//|
+//| When the microcontroller does not support the behavior in a hardware
+//| accelerated fashion it may internally use a bitbang routine. However, if
+//| hardware support is available on a subset of pins but not those provided,
+//| then a RuntimeError will be raised. Use the `bitbangio` module to explicitly
+//| bitbang a serial protocol on any general purpose pins.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import busio
+//| from board import *
+//|
+//| i2c = busio.I2C(SCL, SDA)
+//| print(i2c.scan())
+//| i2c.deinit()
+//|
+//| This example will initialize the the device, run
+//| :py:meth:`~busio.I2C.scan` and then :py:meth:`~busio.I2C.deinit` the
+//| hardware. The last step is optional because CircuitPython automatically
+//| resets hardware after a program finishes.
+//|
+//| Note that drivers will typically handle communication if provided the bus
+//| instance (such as ``busio.I2C(board.SCL, board.SDA)``), and that many of
+//| the methods listed here are lower level functionalities that are needed
+//| for working with custom drivers.
+//|
+//| Tutorial for I2C and SPI:
+//| https://learn.adafruit.com/circuitpython-basics-i2c-and-spi
+//|
+//| Tutorial for UART:
+//| https://learn.adafruit.com/circuitpython-essentials/circuitpython-uart-serial
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t busio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busio) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) },
+ #if CIRCUITPY_ONEWIREIO
+ { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&onewireio_onewire_type) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table);
+
+const mp_obj_module_t busio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&busio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_busio, busio_module, CIRCUITPY_BUSIO);
diff --git a/circuitpython/shared-bindings/busio/__init__.h b/circuitpython/shared-bindings/busio/__init__.h
new file mode 100644
index 0000000..bcea305
--- /dev/null
+++ b/circuitpython/shared-bindings/busio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO___INIT___H
diff --git a/circuitpython/shared-bindings/camera/Camera.c b/circuitpython/shared-bindings/camera/Camera.c
new file mode 100644
index 0000000..f7bc9ee
--- /dev/null
+++ b/circuitpython/shared-bindings/camera/Camera.c
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2020 Sony Semiconductor Solutions Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/camera/Camera.h"
+#include "shared-bindings/util.h"
+
+//| class Camera:
+//| """The class to control camera.
+//|
+//| Usage::
+//|
+//| import board
+//| import sdioio
+//| import storage
+//| import camera
+//|
+//| sd = sdioio.SDCard(
+//| clock=board.SDIO_CLOCK,
+//| command=board.SDIO_COMMAND,
+//| data=board.SDIO_DATA,
+//| frequency=25000000)
+//| vfs = storage.VfsFat(sd)
+//| storage.mount(vfs, '/sd')
+//|
+//| cam = camera.Camera()
+//|
+//| buffer = bytearray(512 * 1024)
+//| file = open("/sd/image.jpg","wb")
+//| size = cam.take_picture(buffer, width=1920, height=1080, format=camera.ImageFormat.JPG)
+//| file.write(buffer, size)
+//| file.close()"""
+//|
+
+//| def __init__(self) -> None:
+//| """Initialize camera."""
+//| ...
+//|
+STATIC mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ camera_obj_t *self = m_new_obj(camera_obj_t);
+ self->base.type = &camera_type;
+ // No arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ common_hal_camera_construct(self);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """De-initialize camera."""
+//| ...
+//|
+STATIC mp_obj_t camera_obj_deinit(mp_obj_t self_in) {
+ camera_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_camera_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(camera_deinit_obj, camera_obj_deinit);
+
+STATIC void check_for_deinit(camera_obj_t *self) {
+ if (common_hal_camera_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def take_picture(self, buf: WriteableBuffer, format: ImageFormat) -> int:
+//| """Take picture and save to ``buf`` in the given ``format``. The size of the picture
+//| taken is ``width`` by ``height`` in pixels.
+//|
+//| :return: the number of bytes written into buf
+//| :rtype: int"""
+//| ...
+//|
+STATIC mp_obj_t camera_obj_take_picture(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_width, ARG_height, ARG_format };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+ camera_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ camera_imageformat_t format = camera_imageformat_obj_to_type(args[ARG_format].u_obj);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_camera_take_picture(self, (uint8_t *)bufinfo.buf, bufinfo.len, args[ARG_width].u_int, args[ARG_height].u_int, format));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(camera_take_picture_obj, 1, camera_obj_take_picture);
+
+STATIC const mp_rom_map_elem_t camera_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&camera_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_take_picture), MP_ROM_PTR(&camera_take_picture_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(camera_locals_dict, camera_locals_dict_table);
+
+const mp_obj_type_t camera_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Camera,
+ .make_new = camera_make_new,
+ .locals_dict = (mp_obj_dict_t *)&camera_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/camera/Camera.h b/circuitpython/shared-bindings/camera/Camera.h
new file mode 100644
index 0000000..8102672
--- /dev/null
+++ b/circuitpython/shared-bindings/camera/Camera.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2020 Sony Semiconductor Solutions Corporation
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H
+
+#include "common-hal/camera/Camera.h"
+#include "shared-bindings/camera/ImageFormat.h"
+
+extern const mp_obj_type_t camera_type;
+
+void common_hal_camera_construct(camera_obj_t *self);
+void common_hal_camera_deinit(camera_obj_t *self);
+bool common_hal_camera_deinited(camera_obj_t *self);
+size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, uint16_t width, uint16_t height, camera_imageformat_t format);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_CAMERA_H
diff --git a/circuitpython/shared-bindings/camera/ImageFormat.c b/circuitpython/shared-bindings/camera/ImageFormat.c
new file mode 100644
index 0000000..3ff687b
--- /dev/null
+++ b/circuitpython/shared-bindings/camera/ImageFormat.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2020 Sony Semiconductor Solutions Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/camera/ImageFormat.h"
+
+//| class ImageFormat:
+//| """Image format"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the image format."""
+//|
+//| JPG: ImageFormat
+//| """JPG format."""
+//|
+//| RGB565: ImageFormat
+//| """RGB565 format."""
+//|
+
+const camera_imageformat_obj_t camera_imageformat_jpg_obj = {
+ { &camera_imageformat_type },
+};
+
+const camera_imageformat_obj_t camera_imageformat_rgb565_obj = {
+ { &camera_imageformat_type },
+};
+
+camera_imageformat_t camera_imageformat_obj_to_type(mp_obj_t obj) {
+ if (obj == MP_ROM_PTR(&camera_imageformat_jpg_obj)) {
+ return IMAGEFORMAT_JPG;
+ } else if (obj == MP_ROM_PTR(&camera_imageformat_rgb565_obj)) {
+ return IMAGEFORMAT_RGB565;
+ }
+ return IMAGEFORMAT_NONE;
+}
+
+mp_obj_t camera_imageformat_type_to_obj(camera_imageformat_t format) {
+ switch (format) {
+ case IMAGEFORMAT_JPG:
+ return (mp_obj_t)MP_ROM_PTR(&camera_imageformat_jpg_obj);
+ case IMAGEFORMAT_RGB565:
+ return (mp_obj_t)MP_ROM_PTR(&camera_imageformat_rgb565_obj);
+ case IMAGEFORMAT_NONE:
+ default:
+ return MP_ROM_NONE;
+ }
+}
+
+STATIC const mp_rom_map_elem_t camera_imageformat_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_JPG), MP_ROM_PTR(&camera_imageformat_jpg_obj)},
+ {MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_PTR(&camera_imageformat_rgb565_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(camera_imageformat_locals_dict, camera_imageformat_locals_dict_table);
+
+STATIC void camera_imageformat_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr format = MP_QSTR_None;
+ if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imageformat_jpg_obj)) {
+ format = MP_QSTR_JPG;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&camera_imageformat_rgb565_obj)) {
+ format = MP_QSTR_RGB565;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_camera, MP_QSTR_ImageSize, format);
+}
+
+const mp_obj_type_t camera_imageformat_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ImageFormat,
+ .print = camera_imageformat_print,
+ .locals_dict = (mp_obj_t)&camera_imageformat_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/camera/ImageFormat.h b/circuitpython/shared-bindings/camera/ImageFormat.h
new file mode 100644
index 0000000..32a3635
--- /dev/null
+++ b/circuitpython/shared-bindings/camera/ImageFormat.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2020 Sony Semiconductor Solutions Corporation
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H
+
+#include "py/obj.h"
+
+typedef enum {
+ IMAGEFORMAT_NONE,
+ IMAGEFORMAT_JPG,
+ IMAGEFORMAT_RGB565,
+} camera_imageformat_t;
+
+extern const mp_obj_type_t camera_imageformat_type;
+
+camera_imageformat_t camera_imageformat_obj_to_type(mp_obj_t obj);
+mp_obj_t camera_imageformat_type_to_obj(camera_imageformat_t mode);
+
+typedef struct {
+ mp_obj_base_t base;
+} camera_imageformat_obj_t;
+extern const camera_imageformat_obj_t camera_imageformat_jpg_obj;
+extern const camera_imageformat_obj_t camera_imageformat_rgb565_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_CAMERA_IMAGEFORMAT_H
diff --git a/circuitpython/shared-bindings/camera/__init__.c b/circuitpython/shared-bindings/camera/__init__.c
new file mode 100644
index 0000000..12cebae
--- /dev/null
+++ b/circuitpython/shared-bindings/camera/__init__.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright 2020 Sony Semiconductor Solutions Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared-bindings/camera/Camera.h"
+#include "shared-bindings/util.h"
+
+//| """Support for camera input
+//|
+//| The `camera` module contains classes to control the camera and take pictures."""
+//|
+STATIC const mp_rom_map_elem_t camera_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_camera) },
+ { MP_ROM_QSTR(MP_QSTR_Camera), MP_ROM_PTR(&camera_type) },
+
+ // Enum-like Classes.
+ { MP_ROM_QSTR(MP_QSTR_ImageFormat), MP_ROM_PTR(&camera_imageformat_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(camera_module_globals, camera_module_globals_table);
+
+const mp_obj_module_t camera_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&camera_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_camera, camera_module, CIRCUITPY_CAMERA);
diff --git a/circuitpython/shared-bindings/canio/CAN.c b/circuitpython/shared-bindings/canio/CAN.c
new file mode 100644
index 0000000..e8aec7f
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/CAN.c
@@ -0,0 +1,360 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/enum.h"
+#include "common-hal/canio/CAN.h"
+#include "common-hal/canio/Listener.h"
+#include "shared-bindings/canio/__init__.h"
+#include "shared-bindings/canio/CAN.h"
+#include "shared-bindings/canio/Listener.h"
+#include "shared-bindings/canio/Match.h"
+#include "shared-bindings/canio/Message.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//|
+//| class CAN:
+//| """CAN bus protocol"""
+//|
+//| def __init__(self,
+//| tx: microcontroller.Pin,
+//| rx: microcontroller.Pin,
+//| *,
+//| baudrate: int = 250000,
+//| loopback: bool = False,
+//| silent: bool = False,
+//| auto_restart: bool = False,
+//| ) -> None:
+//| """A common shared-bus protocol. The rx and tx pins are generally
+//| connected to a transceiver which controls the H and L pins on a
+//| shared bus.
+//|
+//| :param ~microcontroller.Pin rx: the pin to receive with
+//| :param ~microcontroller.Pin tx: the pin to transmit with
+//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value.
+//| :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends.
+//| :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering.
+//| :param bool auto_restart: If True, will restart communications after entering bus-off state
+//| """
+//| ...
+//|
+STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_tx, ARG_rx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_tx, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} },
+ { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj);
+ const mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj);
+ if (!rx_pin && !tx_pin) {
+ mp_raise_ValueError(translate("tx and rx cannot both be None"));
+ }
+
+ canio_can_obj_t *self = m_new_obj(canio_can_obj_t);
+ self->base.type = &canio_can_type;
+ common_hal_canio_can_construct(self, tx_pin, rx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool);
+
+ common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+//| auto_restart: bool
+//| """If True, will restart communications after entering bus-off state"""
+//|
+STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get);
+
+STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set);
+
+MP_PROPERTY_GETSET(canio_can_auto_restart_obj,
+ (mp_obj_t)&canio_can_auto_restart_get_obj,
+ (mp_obj_t)&canio_can_auto_restart_set_obj);
+
+
+//| baudrate: int
+//| """The baud rate (read-only)"""
+//|
+STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get);
+
+MP_PROPERTY_GETTER(canio_can_baudrate_obj,
+ (mp_obj_t)&canio_can_baudrate_get_obj);
+
+//| transmit_error_count: int
+//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC."""
+//|
+STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get);
+
+MP_PROPERTY_GETTER(canio_can_transmit_error_count_obj,
+ (mp_obj_t)&canio_can_transmit_error_count_get_obj);
+
+//| receive_error_count: int
+//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC."""
+//|
+STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get);
+
+MP_PROPERTY_GETTER(canio_can_receive_error_count_obj,
+ (mp_obj_t)&canio_can_receive_error_count_get_obj);
+
+//| state: BusState
+//| """The current state of the bus. (read-only)"""
+STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get);
+
+MP_PROPERTY_GETTER(canio_can_state_obj,
+ (mp_obj_t)&canio_can_state_get_obj);
+
+
+//| def restart(self) -> None:
+//| """If the device is in the bus off state, restart it."""
+//| ...
+//|
+STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ common_hal_canio_can_restart(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart);
+
+//| def listen(self, matches: Optional[Sequence[Match]]=None, *, timeout: float=10) -> Listener:
+//| """Start receiving messages that match any one of the filters.
+//|
+//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners.
+//|
+//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters.
+//|
+//| If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos.
+//|
+//| A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it.
+//|
+//| An empty filter list causes all messages to be accepted.
+//|
+//| Timeout dictates how long receive() and next() will block.
+//|
+//| Platform specific notes:
+//|
+//| SAM E5x supports two Listeners. Filter blocks are shared between the two
+//| listeners. There are 4 standard filter blocks and 4 extended filter blocks.
+//| Each block can either match 2 single addresses or a mask of addresses.
+//| The number of filter blocks can be increased, up to a hardware maximum, by
+//| rebuilding CircuitPython, but this decreases the CircuitPython free
+//| memory even if canio is not used.
+//|
+//| STM32F405 supports two Listeners. Filter blocks are shared between the two listeners.
+//| There are 14 filter blocks. Each block can match 2 standard addresses with
+//| mask or 1 extended address with mask.
+//|
+//| ESP32S2 supports one Listener. There is a single filter block, which can either match a
+//| standard address with mask or an extended address with mask.
+//| """
+//| ...
+//|
+STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ common_hal_canio_can_check_for_deinit(self);
+
+ enum { ARG_matches, ARG_timeout, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_matches, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ size_t nmatch = 0;
+ mp_obj_t *match_objects = NULL;
+
+ if (args[ARG_matches].u_obj) {
+ mp_obj_get_array(args[ARG_matches].u_obj, &nmatch, &match_objects);
+ }
+
+ canio_match_obj_t *matches[nmatch];
+ for (size_t i = 0; i < nmatch; i++) {
+ const mp_obj_type_t *type = mp_obj_get_type(match_objects[i]);
+ if (type != &canio_match_type) {
+ mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Match, type->name);
+ }
+ matches[i] = MP_OBJ_TO_PTR(match_objects[i]);
+ }
+
+ float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f;
+ canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t);
+ listener->base.type = &canio_listener_type;
+ common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout);
+ return listener;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen);
+
+//| loopback: bool
+//| """True if the device was created in loopback mode, False
+//| otherwise (read-only)"""
+//|
+STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_canio_can_loopback_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get);
+
+MP_PROPERTY_GETTER(canio_can_loopback_obj,
+ (mp_obj_t)&canio_can_loopback_get_obj);
+
+
+//| def send(self, message: Union[RemoteTransmissionRequest, Message]) -> None:
+//| """Send a message on the bus with the given data and id.
+//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised.
+//| """
+//| ...
+//|
+STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ const mp_obj_type_t *message_type = mp_obj_get_type(message_in);
+ if (message_type != &canio_message_type && message_type != &canio_remote_transmission_request_type) {
+ mp_raise_TypeError_varg(translate("expected '%q' or '%q' but got '%q'"), MP_QSTR_Message, MP_QSTR_RemoteTransmissionRequest, message_type->name);
+ }
+
+ canio_message_obj_t *message = message_in;
+ common_hal_canio_can_send(self, message);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send);
+
+//| silent: bool
+//| """True if the device was created in silent mode, False
+//| otherwise (read-only)"""
+//|
+STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_canio_can_silent_get(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get);
+
+MP_PROPERTY_GETTER(canio_can_silent_obj,
+ (mp_obj_t)&canio_can_silent_get_obj);
+
+
+//| def deinit(self) -> None:
+//| """Deinitialize this object, freeing its hardware resources"""
+//| ...
+//|
+STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit);
+
+//| def __enter__(self) -> CAN:
+//| """Returns self, to allow the object to be used in a `with` statement for resource control"""
+//| ...
+//|
+STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_can_check_for_deinit(self);
+ return self_in;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter);
+
+//| def __exit__(self, unused1: Optional[Type[BaseException]], unused2: Optional[BaseException], unused3: Optional[TracebackType]) -> None:
+//| """Calls deinit()"""
+//| ...
+STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) {
+ canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ common_hal_canio_can_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit);
+
+STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) },
+ { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) },
+ { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) },
+ { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table);
+
+const mp_obj_type_t canio_can_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_CAN,
+ .make_new = canio_can_make_new,
+ .locals_dict = (mp_obj_t)&canio_can_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/canio/CAN.h b/circuitpython/shared-bindings/canio/CAN.h
new file mode 100644
index 0000000..b25d2fd
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/CAN.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/canio/__init__.h"
+#include "shared-bindings/canio/Message.h"
+
+extern const mp_obj_type_t canio_can_type;
+
+typedef struct canio_can_obj canio_can_obj_t;
+
+void common_hal_canio_can_construct(canio_can_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent);
+bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self);
+bool common_hal_canio_can_deinited(canio_can_obj_t *self);
+int common_hal_canio_can_baudrate_get(canio_can_obj_t *self);
+bool common_hal_canio_can_loopback_get(canio_can_obj_t *self);
+int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
+canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self);
+bool common_hal_canio_can_silent_get(canio_can_obj_t *self);
+int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
+void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart);
+void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self);
+void common_hal_canio_can_deinit(canio_can_obj_t *self);
+void common_hal_canio_can_restart(canio_can_obj_t *self);
+void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message);
+void common_hal_canio_reset(void);
diff --git a/circuitpython/shared-bindings/canio/Listener.c b/circuitpython/shared-bindings/canio/Listener.c
new file mode 100644
index 0000000..e59801d
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Listener.c
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/canio/Listener.h"
+#include "shared-bindings/canio/Message.h"
+#include "common-hal/canio/Listener.h"
+
+#include "py/runtime.h"
+#include "py/objproperty.h"
+
+//| class Listener:
+//| """Listens for CAN message
+//|
+//| `canio.Listener` is not constructed directly, but instead by calling
+//| `canio.CAN.listen`.
+//|
+//| In addition to using the `receive` method to retrieve a message or
+//| the `in_waiting` method to check for an available message, a
+//| listener can be used as an iterable, yielding messages until no
+//| message arrives within ``self.timeout`` seconds."""
+//|
+
+//| def receive(self) -> Optional[Union[RemoteTransmissionRequest,Message]]:
+//| """Reads a message, after waiting up to ``self.timeout`` seconds
+//|
+//| If no message is received in time, `None` is returned. Otherwise,
+//| a `Message` or `RemoteTransmissionRequest` is returned."""
+//| ...
+//|
+STATIC mp_obj_t canio_listener_receive(mp_obj_t self_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_check_for_deinit(self);
+
+ mp_obj_t message = common_hal_canio_listener_receive(self);
+ // note: receive fills out the type field of the message
+
+ if (message) {
+ return message;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_receive_obj, canio_listener_receive);
+
+//| def in_waiting(self) -> int:
+//| """Returns the number of messages (including remote
+//| transmission requests) waiting"""
+//| ...
+//|
+STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting);
+
+//| def __iter__(self) -> Listener:
+//| """Returns self
+//|
+//| This method exists so that `Listener` can be used as an
+//| iterable"""
+//| ...
+//|
+//| def __next__(self) -> Union[RemoteTransmissionRequest,Message]:
+//| """Reads a message, after waiting up to self.timeout seconds
+//|
+//| If no message is received in time, raises StopIteration. Otherwise,
+//| a Message or is returned.
+//|
+//| This method enables the `Listener` to be used as an
+//| iterable, for instance in a for-loop."""
+//| ...
+//|
+STATIC mp_obj_t canio_iternext(mp_obj_t self_in) {
+ mp_obj_t result = canio_listener_receive(self_in);
+ if (result == mp_const_none) {
+ return MP_OBJ_STOP_ITERATION;
+ }
+ return result;
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialize this object, freeing its hardware resources"""
+//| ...
+//|
+STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit);
+
+//| def __enter__(self) -> CAN:
+//| """Returns self, to allow the object to be used in a `with` statement for resource control"""
+//| ...
+//|
+STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_check_for_deinit(self);
+ return self_in;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter);
+
+//| def __exit__(self, unused1: Optional[Type[BaseException]], unused2: Optional[BaseException], unused3: Optional[TracebackType]) -> None:
+//| """Calls deinit()"""
+//| ...
+STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ common_hal_canio_listener_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit);
+
+
+//| timeout : float
+STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_check_for_deinit(self);
+ return mp_obj_new_float(common_hal_canio_listener_get_timeout(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get);
+
+STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) {
+ canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_canio_listener_check_for_deinit(self);
+ common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set);
+
+MP_PROPERTY_GETSET(canio_listener_timeout_obj,
+ (mp_obj_t)&canio_listener_timeout_get_obj,
+ (mp_obj_t)&canio_listener_timeout_set_obj);
+
+
+
+STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) },
+ { MP_ROM_QSTR(MP_QSTR_receive), MP_ROM_PTR(&canio_listener_receive_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table);
+
+const mp_obj_type_t canio_listener_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Listener,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .locals_dict = (mp_obj_dict_t *)&canio_listener_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = canio_iternext,
+ ),
+};
diff --git a/circuitpython/shared-bindings/canio/Listener.h b/circuitpython/shared-bindings/canio/Listener.h
new file mode 100644
index 0000000..527ffe4
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Listener.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-bindings/canio/CAN.h"
+#include "shared-bindings/canio/Match.h"
+
+extern const mp_obj_type_t canio_listener_type;
+
+typedef struct canio_listener_obj canio_listener_obj_t;
+
+void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout);
+void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self);
+void common_hal_canio_listener_deinit(canio_listener_obj_t *self);
+mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self);
+int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self);
+float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self);
+void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout);
diff --git a/circuitpython/shared-bindings/canio/Match.c b/circuitpython/shared-bindings/canio/Match.c
new file mode 100644
index 0000000..52262b0
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Match.c
@@ -0,0 +1,127 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/canio/Match.h"
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class Match:
+//| """Describe CAN bus messages to match"""
+//|
+//|
+//| def __init__(self, id: int, *, mask: Optional[int] = None, extended: bool = False) -> None:
+//| """Construct a Match with the given properties.
+//|
+//| If mask is not None, then the filter is for any id which matches all
+//| the nonzero bits in mask. Otherwise, it matches exactly the given id.
+//| If extended is true then only extended ids are matched, otherwise
+//| only standard ids are matched."""
+//|
+
+STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_mask, ARG_extended, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_mask, MP_ARG_OBJ, {.u_obj = mp_const_none } },
+ { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int id_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff;
+ int id = args[ARG_id].u_int;
+ int mask = args[ARG_mask].u_obj == mp_const_none ? id_bits : mp_obj_get_int(args[ARG_mask].u_obj);
+
+ if (id & ~id_bits) {
+ mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_id);
+ }
+
+ if (mask & ~id_bits) {
+ mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask);
+ }
+
+ canio_match_obj_t *self = m_new_obj(canio_match_obj_t);
+ self->base.type = &canio_match_type;
+ common_hal_canio_match_construct(self, id, mask, args[ARG_extended].u_bool);
+ return self;
+}
+
+//| id: int
+//| """The id to match"""
+//|
+
+STATIC mp_obj_t canio_match_id_get(mp_obj_t self_in) {
+ canio_match_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_id(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_match_id_get_obj, canio_match_id_get);
+
+MP_PROPERTY_GETTER(canio_match_id_obj,
+ (mp_obj_t)&canio_match_id_get_obj);
+
+//|
+//| mask: int
+//| """The optional mask of ids to match"""
+//|
+
+STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) {
+ canio_match_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get);
+
+MP_PROPERTY_GETTER(canio_match_mask_obj,
+ (mp_obj_t)&canio_match_mask_get_obj);
+
+//| extended: bool
+//| """True to match extended ids, False to match standard ides"""
+//|
+
+STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) {
+ canio_match_obj_t *self = self_in;
+ return mp_obj_new_bool(common_hal_canio_match_get_extended(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get);
+
+MP_PROPERTY_GETTER(canio_match_extended_obj,
+ (mp_obj_t)&canio_match_extended_get_obj);
+
+STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_match_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) },
+ { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table);
+
+const mp_obj_type_t canio_match_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Match,
+ .make_new = canio_match_make_new,
+ .locals_dict = (mp_obj_dict_t *)&canio_match_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/canio/Match.h b/circuitpython/shared-bindings/canio/Match.h
new file mode 100644
index 0000000..01a75fd
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Match.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-module/canio/Match.h"
+
+extern const mp_obj_type_t canio_match_type;
+
+void common_hal_canio_match_construct(canio_match_obj_t *self, int id, int mask, bool extended);
+int common_hal_canio_match_get_id(const canio_match_obj_t *self);
+int common_hal_canio_match_get_mask(const canio_match_obj_t *self);
+bool common_hal_canio_match_get_extended(const canio_match_obj_t *self);
diff --git a/circuitpython/shared-bindings/canio/Message.c b/circuitpython/shared-bindings/canio/Message.c
new file mode 100644
index 0000000..64d4094
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Message.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/canio/Message.h"
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class Message:
+//| def __init__(self, id: int, data: bytes, *, extended: bool = False) -> None:
+//| """Construct a Message to send on a CAN bus.
+//|
+//| :param int id: The numeric ID of the message
+//| :param bytes data: The content of the message
+//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier
+//|
+//| In CAN, messages can have a length from 0 to 8 bytes.
+//| """
+//| ...
+//|
+STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_data, ARG_extended, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t data;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ);
+
+ if (data.len > 8) {
+ mp_raise_ValueError(translate("Messages limited to 8 bytes"));
+ }
+
+ canio_message_obj_t *self = m_new_obj(canio_message_obj_t);
+ self->base.type = &canio_message_type;
+ common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, args[ARG_extended].u_bool);
+ return self;
+}
+
+//| id: int
+//| """The numeric ID of the message"""
+//|
+STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) {
+ canio_message_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get);
+
+STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) {
+ canio_message_obj_t *self = self_in;
+ common_hal_canio_message_set_id(self, mp_obj_get_int(id));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set);
+
+MP_PROPERTY_GETSET(canio_message_id_obj,
+ (mp_obj_t)&canio_message_id_get_obj,
+ (mp_obj_t)&canio_message_id_set_obj);
+
+//| data: bytes
+//| """The content of the message"""
+//|
+STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) {
+ canio_message_obj_t *self = self_in;
+ return mp_obj_new_bytes((const byte *)common_hal_canio_message_get_data(self), common_hal_canio_message_get_length(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get);
+
+STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) {
+ canio_message_obj_t *self = self_in;
+ mp_buffer_info_t data;
+ mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ);
+ if (data.len > 8) {
+ mp_raise_ValueError(translate("Messages limited to 8 bytes"));
+ }
+ common_hal_canio_message_set_data(self, data.buf, data.len);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set);
+
+
+MP_PROPERTY_GETSET(canio_message_data_obj,
+ (mp_obj_t)&canio_message_data_get_obj,
+ (mp_obj_t)&canio_message_data_set_obj);
+
+
+//| extended: bool
+//| """True if the message's id is an extended id"""
+//|
+STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) {
+ canio_message_obj_t *self = self_in;
+ return mp_obj_new_bool(common_hal_canio_message_get_extended(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get);
+
+STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) {
+ canio_message_obj_t *self = self_in;
+ common_hal_canio_message_set_extended(self, mp_obj_is_true(extended));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set);
+
+
+MP_PROPERTY_GETSET(canio_message_extended_obj,
+ (mp_obj_t)&canio_message_extended_get_obj,
+ (mp_obj_t)&canio_message_extended_set_obj);
+
+STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) },
+ { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table);
+
+const mp_obj_type_t canio_message_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Message,
+ .make_new = canio_message_make_new,
+ .locals_dict = (mp_obj_t)&canio_message_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/canio/Message.h b/circuitpython/shared-bindings/canio/Message.h
new file mode 100644
index 0000000..b765359
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/Message.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-module/canio/Message.h"
+
+extern const mp_obj_type_t canio_message_type;
+extern const mp_obj_type_t canio_remote_transmission_request_type;
+
+void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool extended);
+const void *common_hal_canio_message_get_data(const canio_message_obj_t *self);
+void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size);
+bool common_hal_canio_message_get_extended(const canio_message_obj_t *self);
+void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended);
+int common_hal_canio_message_get_id(const canio_message_obj_t *self);
+void common_hal_canio_message_set_id(canio_message_obj_t *self, int id);
+size_t common_hal_canio_message_get_length(const canio_message_obj_t *self);
diff --git a/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.c b/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.c
new file mode 100644
index 0000000..58ac3aa
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.c
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/canio/RemoteTransmissionRequest.h"
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class RemoteTransmissionRequest:
+//| def __init__(self, id: int, length: int, *, extended: bool = False) -> None:
+//| """Construct a RemoteTransmissionRequest to send on a CAN bus.
+//|
+//| :param int id: The numeric ID of the requested message
+//| :param int length: The length of the requested message
+//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier
+//|
+//| In CAN, messages can have a length from 0 to 8 bytes.
+//| """
+//| ...
+//|
+STATIC mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_length, ARG_extended, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int length = args[ARG_length].u_int;
+ if (length < 0 || length > 8) {
+ mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes"));
+ }
+
+ canio_remote_transmission_request_obj_t *self = m_new_obj(canio_remote_transmission_request_obj_t);
+ self->base.type = &canio_remote_transmission_request_type;
+ common_hal_canio_remote_transmission_request_construct(self, args[ARG_id].u_int, length, args[ARG_extended].u_bool);
+ return self;
+}
+
+
+//| id: int
+//| """The numeric ID of the message"""
+//|
+STATIC mp_obj_t canio_remote_transmission_request_id_get(const mp_obj_t self_in) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_id(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_id_get_obj, canio_remote_transmission_request_id_get);
+
+STATIC mp_obj_t canio_remote_transmission_request_id_set(const mp_obj_t self_in, const mp_obj_t id) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ common_hal_canio_remote_transmission_request_set_id(self, mp_obj_get_int(id));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_id_set_obj, canio_remote_transmission_request_id_set);
+
+MP_PROPERTY_GETSET(canio_remote_transmission_request_id_obj,
+ (mp_obj_t)&canio_remote_transmission_request_id_get_obj,
+ (mp_obj_t)&canio_remote_transmission_request_id_set_obj);
+
+//| extended: bool
+//| """True if the message's id is an extended id"""
+//|
+STATIC mp_obj_t canio_remote_transmission_request_extended_get(const mp_obj_t self_in) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ return mp_obj_new_bool(common_hal_canio_remote_transmission_request_get_extended(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_extended_get_obj, canio_remote_transmission_request_extended_get);
+
+STATIC mp_obj_t canio_remote_transmission_request_extended_set(const mp_obj_t self_in, const mp_obj_t extended) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ common_hal_canio_remote_transmission_request_set_extended(self, mp_obj_is_true(extended));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_extended_set_obj, canio_remote_transmission_request_extended_set);
+
+
+MP_PROPERTY_GETSET(canio_remote_transmission_request_extended_obj,
+ (mp_obj_t)&canio_remote_transmission_request_extended_get_obj,
+ (mp_obj_t)&canio_remote_transmission_request_extended_set_obj);
+
+//| length: int
+//| """The length of the requested message."""
+//|
+STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_length(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get);
+
+STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) {
+ canio_remote_transmission_request_obj_t *self = self_in;
+ int length = mp_obj_get_int(length_in);
+ if (length < 0 || length > 8) {
+ mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes"));
+ }
+ common_hal_canio_remote_transmission_request_set_length(self, length);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set);
+
+
+MP_PROPERTY_GETSET(canio_remote_transmission_request_length_obj,
+ (mp_obj_t)&canio_remote_transmission_request_length_get_obj,
+ (mp_obj_t)&canio_remote_transmission_request_length_set_obj);
+
+STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_remote_transmission_request_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) },
+ { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_remote_transmission_request_extended_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table);
+
+const mp_obj_type_t canio_remote_transmission_request_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RemoteTransmissionRequest,
+ .make_new = canio_remote_transmission_request_make_new,
+ .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.h b/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.h
new file mode 100644
index 0000000..8956587
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/RemoteTransmissionRequest.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "shared-module/canio/RemoteTransmissionRequest.h"
+
+extern const mp_obj_type_t canio_remote_transmission_request_type;
+
+void common_hal_canio_remote_transmission_request_construct(canio_remote_transmission_request_obj_t *self, int id, size_t size, bool extended);
+const void *common_hal_canio_remote_transmission_request_get_data(const canio_remote_transmission_request_obj_t *self);
+void common_hal_canio_remote_transmission_request_set_data(canio_remote_transmission_request_obj_t *self, const void *data, size_t size);
+bool common_hal_canio_remote_transmission_request_get_extended(const canio_remote_transmission_request_obj_t *self);
+void common_hal_canio_remote_transmission_request_set_extended(canio_remote_transmission_request_obj_t *self, bool extended);
+int common_hal_canio_remote_transmission_request_get_id(const canio_remote_transmission_request_obj_t *self);
+void common_hal_canio_remote_transmission_request_set_id(canio_remote_transmission_request_obj_t *self, int id);
+size_t common_hal_canio_remote_transmission_request_get_length(const canio_remote_transmission_request_obj_t *self);
+void common_hal_canio_remote_transmission_request_set_length(canio_remote_transmission_request_obj_t *self, size_t length);
diff --git a/circuitpython/shared-bindings/canio/__init__.c b/circuitpython/shared-bindings/canio/__init__.c
new file mode 100644
index 0000000..ef1b90d
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/__init__.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+//| """CAN bus access
+//|
+//| The `canio` module contains low level classes to support the CAN bus
+//| protocol.
+//|
+//| CAN and Listener classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import canio
+//| from board import *
+//|
+//| can = canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000)
+//| message = canio.Message(id=0x0408, data=b"adafruit")
+//| can.send(message)
+//| can.deinit()
+//|
+//| This example will write the data 'adafruit' onto the CAN bus to any
+//| device listening for message id 0x0408.
+//|
+//| A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin.
+//| If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False
+//| to enable the transceiver.
+//|
+//| Other implementations of the CAN device may exist (for instance, attached
+//| via an SPI bus). If so their constructor arguments may differ, but
+//| otherwise we encourage implementors to follow the API that the core uses.
+//| """
+//|
+
+#include "py/obj.h"
+#include "py/enum.h"
+
+#include "shared-bindings/canio/__init__.h"
+#include "shared-bindings/canio/CAN.h"
+#include "shared-bindings/canio/Match.h"
+#include "shared-bindings/canio/Message.h"
+#include "shared-bindings/canio/Listener.h"
+
+MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_ACTIVE, BUS_STATE_ERROR_ACTIVE);
+MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_PASSIVE, BUS_STATE_ERROR_PASSIVE);
+MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_WARNING, BUS_STATE_ERROR_WARNING);
+MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, BUS_OFF, BUS_STATE_OFF);
+
+//| class BusState:
+//| """The state of the CAN bus"""
+//|
+//| ERROR_ACTIVE: object
+//| """The bus is in the normal (active) state"""
+//|
+//| ERROR_WARNING: object
+//| """The bus is in the normal (active) state, but a moderate number of errors have occurred recently.
+//|
+//| .. note:: Not all implementations may use ``ERROR_WARNING``. Do not rely on seeing ``ERROR_WARNING`` before ``ERROR_PASSIVE``."""
+//|
+//| ERROR_PASSIVE: object
+//| """The bus is in the passive state due to the number of errors that have occurred recently.
+//|
+//| This device will acknowledge packets it receives, but cannot transmit messages.
+//| If additional errors occur, this device may progress to BUS_OFF.
+//| If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets.
+//| """
+//|
+//| BUS_OFF: object
+//| """The bus has turned off due to the number of errors that have
+//| occurred recently. It must be restarted before it will send or receive
+//| packets. This device will neither send or acknowledge packets on the bus."""
+//|
+MAKE_ENUM_MAP(canio_bus_state) {
+ MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_ACTIVE),
+ MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_PASSIVE),
+ MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_WARNING),
+ MAKE_ENUM_MAP_ENTRY(bus_state, BUS_OFF),
+};
+STATIC MP_DEFINE_CONST_DICT(canio_bus_state_locals_dict, canio_bus_state_locals_table);
+
+MAKE_PRINTER(canio, canio_bus_state);
+
+MAKE_ENUM_TYPE(canio, BusState, canio_bus_state);
+
+STATIC const mp_rom_map_elem_t canio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_canio) },
+ { MP_ROM_QSTR(MP_QSTR_BusState), MP_ROM_PTR(&canio_bus_state_type) },
+ { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) },
+ { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) },
+ { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) },
+ { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) },
+ { MP_ROM_QSTR(MP_QSTR_RemoteTransmissionRequest), MP_ROM_PTR(&canio_remote_transmission_request_type) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table);
+
+const mp_obj_module_t canio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&canio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_canio, canio_module, CIRCUITPY_CANIO);
diff --git a/circuitpython/shared-bindings/canio/__init__.h b/circuitpython/shared-bindings/canio/__init__.h
new file mode 100644
index 0000000..e24eba9
--- /dev/null
+++ b/circuitpython/shared-bindings/canio/__init__.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+typedef enum {
+ BUS_STATE_ERROR_ACTIVE, BUS_STATE_ERROR_PASSIVE, BUS_STATE_ERROR_WARNING, BUS_STATE_OFF
+} canio_bus_state_t;
+
+extern const mp_obj_type_t canio_bus_state_type;
diff --git a/circuitpython/shared-bindings/countio/Counter.c b/circuitpython/shared-bindings/countio/Counter.c
new file mode 100644
index 0000000..1914124
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/Counter.c
@@ -0,0 +1,149 @@
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/countio/Counter.h"
+#include "shared-bindings/countio/Edge.h"
+#include "shared-bindings/util.h"
+
+//| class Counter:
+//| """Count the number of rising- and/or falling-edge transitions on a given pin.
+//| """
+//|
+//| def __init__(self, pin: microcontroller.Pin, *, edge: Edge = Edge.FALL, pull: Optional[digitalio.Pull] = None) -> None:
+//| """Create a Counter object associated with the given pin that counts
+//| rising- and/or falling-edge transitions. At least one of ``rise`` and ``fall`` must be True.
+//| The default is to count only falling edges, and is for historical backward compatibility.
+//|
+//| :param ~microcontroller.Pin pin: pin to monitor
+//| :param Edge edge: which edge transitions to count
+//| :param Optional[digitalio.Pull] pull: enable a pull-up or pull-down if not None
+//|
+//|
+//| For example::
+//|
+//| import board
+//| import countio
+//|
+//| # Count rising edges only.
+//| pin_counter = countio.Counter(board.D1, edge=Edge.RISE)
+//| # Reset the count after 100 counts.
+//| while True:
+//| if pin_counter.count >= 100:
+//| pin_counter.reset()
+//| print(pin_counter.count)
+//| """
+//| ...
+//|
+STATIC mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin, ARG_edge, ARG_pull };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_edge, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_FROM_PTR(&edge_FALL_obj) } },
+ { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+ const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge);
+ const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull);
+ // Make long-lived because some implementations use a pointer to the object as interrupt-handler data.
+ countio_counter_obj_t *self = m_new_ll_obj(countio_counter_obj_t);
+ self->base.type = &countio_counter_type;
+
+ common_hal_countio_counter_construct(self, pin, edge, pull);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitializes the Counter and releases any hardware resources for reuse."""
+//|
+STATIC mp_obj_t countio_counter_deinit(mp_obj_t self_in) {
+ countio_counter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_countio_counter_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(countio_counter_deinit_obj, countio_counter_deinit);
+
+STATIC void check_for_deinit(countio_counter_obj_t *self) {
+ if (common_hal_countio_counter_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> Counter:
+//| """No-op used by Context Managers."""
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//|
+STATIC mp_obj_t countio_counter_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_countio_counter_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(countio_counter___exit___obj, 4, 4, countio_counter_obj___exit__);
+
+
+//| count: int
+//| """The current count in terms of pulses."""
+//|
+STATIC mp_obj_t countio_counter_obj_get_count(mp_obj_t self_in) {
+ countio_counter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_int(common_hal_countio_counter_get_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(countio_counter_get_count_obj, countio_counter_obj_get_count);
+
+STATIC mp_obj_t countio_counter_obj_set_count(mp_obj_t self_in, mp_obj_t new_count) {
+ countio_counter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_countio_counter_set_count(self, mp_obj_get_int(new_count));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(countio_counter_set_count_obj, countio_counter_obj_set_count);
+
+MP_PROPERTY_GETSET(countio_counter_count_obj,
+ (mp_obj_t)&countio_counter_get_count_obj,
+ (mp_obj_t)&countio_counter_set_count_obj);
+
+//| def reset(self) -> None:
+//| """Resets the count back to 0."""
+//|
+STATIC mp_obj_t countio_counter_reset(mp_obj_t self_in) {
+ countio_counter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_countio_counter_set_count(self, 0);
+ return mp_const_none;
+}
+
+
+MP_DEFINE_CONST_FUN_OBJ_1(countio_counter_reset_obj, countio_counter_reset);
+
+STATIC const mp_rom_map_elem_t countio_counter_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&countio_counter_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&countio_counter___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&countio_counter_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&countio_counter_reset_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(countio_counter_locals_dict, countio_counter_locals_dict_table);
+
+const mp_obj_type_t countio_counter_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Counter,
+ .make_new = countio_counter_make_new,
+ .locals_dict = (mp_obj_dict_t *)&countio_counter_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/countio/Counter.h b/circuitpython/shared-bindings/countio/Counter.h
new file mode 100644
index 0000000..d660cc8
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/Counter.h
@@ -0,0 +1,19 @@
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_COUNTER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_COUNTER_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/countio/Counter.h"
+#include "shared-bindings/countio/Edge.h"
+#include "shared-bindings/digitalio/Pull.h"
+
+extern const mp_obj_type_t countio_counter_type;
+
+extern void common_hal_countio_counter_construct(countio_counter_obj_t *self,
+ const mcu_pin_obj_t *pin, countio_edge_t edge, digitalio_pull_t pull);
+extern void common_hal_countio_counter_deinit(countio_counter_obj_t *self);
+extern bool common_hal_countio_counter_deinited(countio_counter_obj_t *self);
+extern mp_int_t common_hal_countio_counter_get_count(countio_counter_obj_t *self);
+extern void common_hal_countio_counter_set_count(countio_counter_obj_t *self,
+ mp_int_t new_count);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_COUNTER_H
diff --git a/circuitpython/shared-bindings/countio/Edge.c b/circuitpython/shared-bindings/countio/Edge.c
new file mode 100644
index 0000000..980b3a3
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/Edge.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/enum.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/countio/Edge.h"
+
+MAKE_ENUM_VALUE(countio_edge_type, edge, RISE, EDGE_RISE);
+MAKE_ENUM_VALUE(countio_edge_type, edge, FALL, EDGE_FALL);
+MAKE_ENUM_VALUE(countio_edge_type, edge, RISE_AND_FALL, EDGE_RISE_AND_FALL);
+
+//| class Edge:
+//| """Enumerates which signal transitions can be counted."""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define which signal transitions to count."""
+//| ...
+//|
+//| RISE: Edge
+//| """Count the rising edges."""
+//|
+//| FALL: Edge
+//| """Count the falling edges."""
+//|
+//| RISE_AND_FALL: Edge
+//| """Count the rising and falling edges."""
+//|
+MAKE_ENUM_MAP(countio_edge) {
+ MAKE_ENUM_MAP_ENTRY(edge, RISE),
+ MAKE_ENUM_MAP_ENTRY(edge, FALL),
+ MAKE_ENUM_MAP_ENTRY(edge, RISE_AND_FALL),
+};
+
+STATIC MP_DEFINE_CONST_DICT(countio_edge_locals_dict, countio_edge_locals_table);
+
+MAKE_PRINTER(countio, countio_edge);
+
+MAKE_ENUM_TYPE(countio, Edge, countio_edge);
+
+countio_edge_t validate_edge(mp_obj_t obj, qstr arg_name) {
+ return cp_enum_value(&countio_edge_type, mp_arg_validate_type(obj, &countio_edge_type, arg_name));
+}
diff --git a/circuitpython/shared-bindings/countio/Edge.h b/circuitpython/shared-bindings/countio/Edge.h
new file mode 100644
index 0000000..ca4cddb
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/Edge.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 an Halbertfor Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_EDGE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_EDGE_H
+
+#include "py/enum.h"
+#include "py/obj.h"
+
+typedef enum _countio_edge_t {
+ EDGE_RISE,
+ EDGE_FALL,
+ EDGE_RISE_AND_FALL,
+} countio_edge_t;
+
+extern const mp_obj_type_t countio_edge_type;
+extern const cp_enum_obj_t edge_FALL_obj;
+
+countio_edge_t validate_edge(mp_obj_t obj, qstr arg_name);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO_EDGE_H
diff --git a/circuitpython/shared-bindings/countio/__init__.c b/circuitpython/shared-bindings/countio/__init__.c
new file mode 100644
index 0000000..d72ed9f
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/__init__.c
@@ -0,0 +1,35 @@
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/countio/__init__.h"
+#include "shared-bindings/countio/Counter.h"
+#include "shared-bindings/countio/Edge.h"
+
+//| """Support for edge counting
+//|
+//| The `countio` module contains logic to read and count edge transistions
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//|
+
+STATIC const mp_rom_map_elem_t countio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_countio) },
+ { MP_ROM_QSTR(MP_QSTR_Counter), MP_ROM_PTR(&countio_counter_type) },
+ { MP_ROM_QSTR(MP_QSTR_Edge), MP_ROM_PTR(&countio_edge_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(countio_module_globals, countio_module_globals_table);
+
+const mp_obj_module_t countio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&countio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_countio, countio_module, CIRCUITPY_COUNTIO);
diff --git a/circuitpython/shared-bindings/countio/__init__.h b/circuitpython/shared-bindings/countio/__init__.h
new file mode 100644
index 0000000..35ae9f0
--- /dev/null
+++ b/circuitpython/shared-bindings/countio/__init__.h
@@ -0,0 +1,9 @@
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_COUNTIO___INIT___H
diff --git a/circuitpython/shared-bindings/digitalio/DigitalInOut.c b/circuitpython/shared-bindings/digitalio/DigitalInOut.c
new file mode 100644
index 0000000..37093ad
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/DigitalInOut.c
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+
+#include "py/nlr.h"
+#include "py/objtype.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/digitalio/Direction.h"
+#include "shared-bindings/digitalio/DriveMode.h"
+#include "shared-bindings/digitalio/Pull.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class DigitalInOut:
+//| """Digital input and output
+//|
+//| A DigitalInOut is used to digitally control I/O pins. For analog control of
+//| a pin, see the :py:class:`analogio.AnalogIn` and
+//| :py:class:`analogio.AnalogOut` classes."""
+//|
+//| def __init__(self, pin: microcontroller.Pin) -> None:
+//| """Create a new DigitalInOut object associated with the pin. Defaults to input
+//| with no pull. Use :py:meth:`switch_to_input` and
+//| :py:meth:`switch_to_output` to change the direction.
+//|
+//| :param ~microcontroller.Pin pin: The pin to control"""
+//| ...
+//|
+STATIC mp_obj_t digitalio_digitalinout_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ digitalio_digitalinout_obj_t *self = m_new_obj(digitalio_digitalinout_obj_t);
+ self->base.type = &digitalio_digitalinout_type;
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]);
+ common_hal_digitalio_digitalinout_construct(self, pin);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the DigitalInOut and release the pin for other use."""
+//| ...
+//|
+STATIC mp_obj_t digitalio_digitalinout_obj_deinit(mp_obj_t self_in) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_digitalio_digitalinout_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_deinit_obj, digitalio_digitalinout_obj_deinit);
+
+//| def __enter__(self) -> DigitalInOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t digitalio_digitalinout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_digitalio_digitalinout_deinit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(digitalio_digitalinout_obj___exit___obj, 4, 4, digitalio_digitalinout_obj___exit__);
+
+STATIC void check_for_deinit(digitalio_digitalinout_obj_t *self) {
+ if (common_hal_digitalio_digitalinout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def switch_to_output(self, value: bool = False, drive_mode: DriveMode = DriveMode.PUSH_PULL) -> None:
+//| """Set the drive mode and value and then switch to writing out digital
+//| values.
+//|
+//| :param bool value: default value to set upon switching
+//| :param ~digitalio.DriveMode drive_mode: drive mode for the output
+//| """
+//| ...
+//|
+STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_value, ARG_drive_mode };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_value, MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)} },
+ };
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL;
+ if (args[ARG_drive_mode].u_rom_obj == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) {
+ drive_mode = DRIVE_MODE_OPEN_DRAIN;
+ }
+ // do the transfer
+ digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(self, args[ARG_value].u_bool, drive_mode);
+ if (result == DIGITALINOUT_INPUT_ONLY) {
+ mp_raise_NotImplementedError(translate("Pin is input only"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(digitalio_digitalinout_switch_to_output_obj, 1, digitalio_digitalinout_switch_to_output);
+
+//| def switch_to_input(self, pull: Optional[Pull] = None) -> None:
+//| """Set the pull and then switch to read in digital values.
+//|
+//| :param Pull pull: pull configuration for the input
+//|
+//| Example usage::
+//|
+//| import digitalio
+//| import board
+//|
+//| switch = digitalio.DigitalInOut(board.SLIDE_SWITCH)
+//| switch.switch_to_input(pull=digitalio.Pull.UP)
+//| # Or, after switch_to_input
+//| switch.pull = digitalio.Pull.UP
+//| print(switch.value)"""
+//| ...
+//|
+STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_pull };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
+ };
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ common_hal_digitalio_digitalinout_switch_to_input(self, validate_pull(args[ARG_pull].u_rom_obj, MP_QSTR_pull));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(digitalio_digitalinout_switch_to_input_obj, 1, digitalio_digitalinout_switch_to_input);
+
+//| direction: Direction
+//| """The direction of the pin.
+//|
+//| Setting this will use the defaults from the corresponding
+//| :py:meth:`switch_to_input` or :py:meth:`switch_to_output` method. If
+//| you want to set pull, value or drive mode prior to switching, then use
+//| those methods instead."""
+//|
+typedef struct {
+ mp_obj_base_t base;
+} digitalio_digitalio_direction_obj_t;
+extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_in_obj;
+extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_out_obj;
+
+STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self);
+ if (direction == DIRECTION_INPUT) {
+ return (mp_obj_t)&digitalio_direction_input_obj;
+ }
+ return (mp_obj_t)&digitalio_direction_output_obj;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_direction_obj, digitalio_digitalinout_obj_get_direction);
+
+STATIC mp_obj_t digitalio_digitalinout_obj_set_direction(mp_obj_t self_in, mp_obj_t value) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (value == MP_ROM_PTR(&digitalio_direction_input_obj)) {
+ common_hal_digitalio_digitalinout_switch_to_input(self, PULL_NONE);
+ } else if (value == MP_ROM_PTR(&digitalio_direction_output_obj)) {
+ digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(self, false, DRIVE_MODE_PUSH_PULL);
+ if (result == DIGITALINOUT_INPUT_ONLY) {
+ mp_raise_NotImplementedError(translate("Pin is input only"));
+ }
+ } else {
+ mp_raise_ValueError(translate("Invalid direction."));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(digitalio_digitalinout_set_direction_obj, digitalio_digitalinout_obj_set_direction);
+
+MP_PROPERTY_GETSET(digitalio_digitalio_direction_obj,
+ (mp_obj_t)&digitalio_digitalinout_get_direction_obj,
+ (mp_obj_t)&digitalio_digitalinout_set_direction_obj);
+
+//| value: bool
+//| """The digital logic level of the pin."""
+//|
+STATIC mp_obj_t digitalio_digitalinout_obj_get_value(mp_obj_t self_in) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ bool value = common_hal_digitalio_digitalinout_get_value(self);
+ return mp_obj_new_bool(value);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_value_obj, digitalio_digitalinout_obj_get_value);
+
+STATIC mp_obj_t digitalio_digitalinout_obj_set_value(mp_obj_t self_in, mp_obj_t value) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) {
+ mp_raise_AttributeError(translate("Cannot set value when direction is input."));
+ return mp_const_none;
+ }
+ common_hal_digitalio_digitalinout_set_value(self, mp_obj_is_true(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(digitalio_digitalinout_set_value_obj, digitalio_digitalinout_obj_set_value);
+
+MP_PROPERTY_GETSET(digitalio_digitalinout_value_obj,
+ (mp_obj_t)&digitalio_digitalinout_get_value_obj,
+ (mp_obj_t)&digitalio_digitalinout_set_value_obj);
+
+//| drive_mode: DriveMode
+//| """The pin drive mode. One of:
+//|
+//| - `digitalio.DriveMode.PUSH_PULL`
+//| - `digitalio.DriveMode.OPEN_DRAIN`"""
+//|
+STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) {
+ mp_raise_AttributeError(translate("Drive mode not used when direction is input."));
+ return mp_const_none;
+ }
+ digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self);
+ if (drive_mode == DRIVE_MODE_PUSH_PULL) {
+ return (mp_obj_t)&digitalio_drive_mode_push_pull_obj;
+ }
+ return (mp_obj_t)&digitalio_drive_mode_open_drain_obj;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_drive_mode_obj, digitalio_digitalinout_obj_get_drive_mode);
+
+STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_obj_t drive_mode) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) {
+ mp_raise_AttributeError(translate("Drive mode not used when direction is input."));
+ return mp_const_none;
+ }
+ digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL;
+ if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) {
+ c_drive_mode = DRIVE_MODE_OPEN_DRAIN;
+ }
+ common_hal_digitalio_digitalinout_set_drive_mode(self, c_drive_mode);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(digitalio_digitalinout_set_drive_mode_obj, digitalio_digitalinout_obj_set_drive_mode);
+
+MP_PROPERTY_GETSET(digitalio_digitalio_drive_mode_obj,
+ (mp_obj_t)&digitalio_digitalinout_get_drive_mode_obj,
+ (mp_obj_t)&digitalio_digitalinout_set_drive_mode_obj);
+
+//| pull: Optional[Pull]
+//| """The pin pull direction. One of:
+//|
+//| - `digitalio.Pull.UP`
+//| - `digitalio.Pull.DOWN`
+//| - `None`
+//|
+//| :raises AttributeError: if `direction` is :py:data:`~digitalio.Direction.OUTPUT`."""
+//|
+STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_OUTPUT) {
+ mp_raise_AttributeError(translate("Pull not used when direction is output."));
+ return mp_const_none;
+ }
+ digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self);
+ if (pull == PULL_UP) {
+ return MP_OBJ_FROM_PTR(&digitalio_pull_up_obj);
+ } else if (pull == PULL_DOWN) {
+ return MP_OBJ_FROM_PTR(&digitalio_pull_down_obj);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_pull_obj, digitalio_digitalinout_obj_get_pull);
+
+STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t pull_obj) {
+ digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_OUTPUT) {
+ mp_raise_AttributeError(translate("Pull not used when direction is output."));
+ return mp_const_none;
+ }
+
+ common_hal_digitalio_digitalinout_set_pull(self, validate_pull(pull_obj, MP_QSTR_pull));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(digitalio_digitalinout_set_pull_obj, digitalio_digitalinout_obj_set_pull);
+
+MP_PROPERTY_GETSET(digitalio_digitalio_pull_obj,
+ (mp_obj_t)&digitalio_digitalinout_get_pull_obj,
+ (mp_obj_t)&digitalio_digitalinout_set_pull_obj);
+
+STATIC const mp_rom_map_elem_t digitalio_digitalinout_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&digitalio_digitalinout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&digitalio_digitalinout_obj___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_switch_to_output), MP_ROM_PTR(&digitalio_digitalinout_switch_to_output_obj) },
+ { MP_ROM_QSTR(MP_QSTR_switch_to_input), MP_ROM_PTR(&digitalio_digitalinout_switch_to_input_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_direction), MP_ROM_PTR(&digitalio_digitalio_direction_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&digitalio_digitalinout_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_drive_mode), MP_ROM_PTR(&digitalio_digitalio_drive_mode_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&digitalio_digitalio_pull_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(digitalio_digitalinout_locals_dict, digitalio_digitalinout_locals_dict_table);
+
+const mp_obj_type_t digitalio_digitalinout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_DigitalInOut,
+ .make_new = digitalio_digitalinout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&digitalio_digitalinout_locals_dict,
+};
+
+// Helper for validating digitalio.DigitalInOut arguments
+digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj) {
+ if (!mp_obj_is_type(obj, &digitalio_digitalinout_type)) {
+ mp_raise_TypeError(translate("argument num/types mismatch"));
+ }
+ digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(obj);
+ check_for_deinit(pin);
+ return pin;
+}
diff --git a/circuitpython/shared-bindings/digitalio/DigitalInOut.h b/circuitpython/shared-bindings/digitalio/DigitalInOut.h
new file mode 100644
index 0000000..b6edbc6
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/DigitalInOut.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/digitalio/DigitalInOut.h"
+#include "shared-bindings/digitalio/Direction.h"
+#include "shared-bindings/digitalio/DriveMode.h"
+#include "shared-bindings/digitalio/Pull.h"
+
+extern const mp_obj_type_t digitalio_digitalinout_type;
+
+typedef enum {
+ DIGITALINOUT_OK,
+ DIGITALINOUT_PIN_BUSY,
+ DIGITALINOUT_INPUT_ONLY
+} digitalinout_result_t;
+
+typedef enum {
+ DIGITALINOUT_REG_READ,
+ DIGITALINOUT_REG_WRITE,
+ DIGITALINOUT_REG_SET,
+ DIGITALINOUT_REG_RESET,
+ DIGITALINOUT_REG_TOGGLE,
+} digitalinout_reg_op_t;
+
+digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t *self, const mcu_pin_obj_t *pin);
+void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t *self);
+bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t *self);
+void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t *self, digitalio_pull_t pull);
+digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t *self, bool value, digitalio_drive_mode_t drive_mode);
+digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t *self);
+void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t *self, bool value);
+bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t *self);
+digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t *self, digitalio_drive_mode_t drive_mode);
+digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t *self);
+void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t *self, digitalio_pull_t pull);
+digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t *self);
+void common_hal_digitalio_digitalinout_never_reset(digitalio_digitalinout_obj_t *self);
+digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj);
+
+volatile uint32_t *common_hal_digitalio_digitalinout_get_reg(digitalio_digitalinout_obj_t *self, digitalinout_reg_op_t op, uint32_t *mask);
+bool common_hal_digitalio_has_reg_op(digitalinout_reg_op_t op);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H
diff --git a/circuitpython/shared-bindings/digitalio/Direction.c b/circuitpython/shared-bindings/digitalio/Direction.c
new file mode 100644
index 0000000..0ed18f8
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/Direction.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+
+#include "py/nlr.h"
+#include "py/objtype.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+
+//| class Direction:
+//| """Defines the direction of a digital pin"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define which direction the digital values are
+//| going."""
+//| ...
+//|
+//| INPUT: Direction
+//| """Read digital data in"""
+//|
+//| OUTPUT: Direction
+//| """Write digital data out"""
+//|
+const mp_obj_type_t digitalio_direction_type;
+
+const digitalio_direction_obj_t digitalio_direction_input_obj = {
+ { &digitalio_direction_type },
+};
+
+const digitalio_direction_obj_t digitalio_direction_output_obj = {
+ { &digitalio_direction_type },
+};
+
+STATIC const mp_rom_map_elem_t digitalio_direction_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_INPUT), MP_ROM_PTR(&digitalio_direction_input_obj) },
+ { MP_ROM_QSTR(MP_QSTR_OUTPUT), MP_ROM_PTR(&digitalio_direction_output_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(digitalio_direction_locals_dict, digitalio_direction_locals_dict_table);
+
+STATIC void digitalio_direction_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr direction = MP_QSTR_INPUT;
+ if (self_in == MP_ROM_PTR(&digitalio_direction_output_obj)) {
+ direction = MP_QSTR_OUTPUT;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_Direction, direction);
+}
+
+const mp_obj_type_t digitalio_direction_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Direction,
+ .print = digitalio_direction_print,
+ .locals_dict = (mp_obj_dict_t *)&digitalio_direction_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/digitalio/Direction.h b/circuitpython/shared-bindings/digitalio/Direction.h
new file mode 100644
index 0000000..17e1eda
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/Direction.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIRECTION_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIRECTION_H
+
+#include "py/obj.h"
+
+typedef enum {
+ DIRECTION_INPUT,
+ DIRECTION_OUTPUT
+} digitalio_direction_t;
+typedef struct {
+ mp_obj_base_t base;
+} digitalio_direction_obj_t;
+
+extern const mp_obj_type_t digitalio_direction_type;
+
+extern const digitalio_direction_obj_t digitalio_direction_input_obj;
+extern const digitalio_direction_obj_t digitalio_direction_output_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIRECTION_H
diff --git a/circuitpython/shared-bindings/digitalio/DriveMode.c b/circuitpython/shared-bindings/digitalio/DriveMode.c
new file mode 100644
index 0000000..c7c3400
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/DriveMode.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/digitalio/DriveMode.h"
+
+//| class DriveMode:
+//| """Defines the drive mode of a digital pin"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the drive mode used when outputting
+//| digital values."""
+//| ...
+//|
+//| PUSH_PULL: DriveMode
+//| """Output both high and low digital values"""
+//|
+//| OPEN_DRAIN: DriveMode
+//| """Output low digital values but go into high z for digital high. This is
+//| useful for i2c and other protocols that share a digital line."""
+//|
+const mp_obj_type_t digitalio_drive_mode_type;
+
+const digitalio_drive_mode_obj_t digitalio_drive_mode_push_pull_obj = {
+ { &digitalio_drive_mode_type },
+};
+
+const digitalio_drive_mode_obj_t digitalio_drive_mode_open_drain_obj = {
+ { &digitalio_drive_mode_type },
+};
+
+STATIC const mp_rom_map_elem_t digitalio_drive_mode_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_PUSH_PULL), MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(digitalio_drive_mode_locals_dict, digitalio_drive_mode_locals_dict_table);
+
+STATIC void digitalio_drive_mode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr drive_mode = MP_QSTR_PUSH_PULL;
+ if (self_in == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) {
+ drive_mode = MP_QSTR_OPEN_DRAIN;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_DriveMode, drive_mode);
+}
+
+const mp_obj_type_t digitalio_drive_mode_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_DriveMode,
+ .print = digitalio_drive_mode_print,
+ .locals_dict = (mp_obj_dict_t *)&digitalio_drive_mode_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/digitalio/DriveMode.h b/circuitpython/shared-bindings/digitalio/DriveMode.h
new file mode 100644
index 0000000..01ecaa4
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/DriveMode.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DRIVEMODE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DRIVEMODE_H
+
+#include "py/obj.h"
+
+typedef enum {
+ DRIVE_MODE_PUSH_PULL,
+ DRIVE_MODE_OPEN_DRAIN
+} digitalio_drive_mode_t;
+
+typedef struct {
+ mp_obj_base_t base;
+} digitalio_drive_mode_obj_t;
+
+extern const mp_obj_type_t digitalio_drive_mode_type;
+
+extern const digitalio_drive_mode_obj_t digitalio_drive_mode_push_pull_obj;
+extern const digitalio_drive_mode_obj_t digitalio_drive_mode_open_drain_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DRIVEMODE_H
diff --git a/circuitpython/shared-bindings/digitalio/Pull.c b/circuitpython/shared-bindings/digitalio/Pull.c
new file mode 100644
index 0000000..4db68dd
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/Pull.c
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "shared-bindings/digitalio/Pull.h"
+
+//| class Pull:
+//| """Defines the pull of a digital input pin"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the pull value, if any, used while reading
+//| digital values in."""
+//| ...
+//|
+//| UP: Pull
+//| """When the input line isn't being driven the pull up can pull the state
+//| of the line high so it reads as true."""
+//|
+//| DOWN: Pull
+//| """When the input line isn't being driven the pull down can pull the
+//| state of the line low so it reads as false."""
+//|
+const mp_obj_type_t digitalio_pull_type;
+
+const digitalio_pull_obj_t digitalio_pull_up_obj = {
+ { &digitalio_pull_type },
+};
+
+const digitalio_pull_obj_t digitalio_pull_down_obj = {
+ { &digitalio_pull_type },
+};
+
+STATIC const mp_rom_map_elem_t digitalio_pull_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_PTR(&digitalio_pull_up_obj) },
+ { MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_PTR(&digitalio_pull_down_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(digitalio_pull_locals_dict, digitalio_pull_locals_dict_table);
+
+STATIC void digitalio_pull_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr pull = MP_QSTR_UP;
+ if (self_in == MP_ROM_PTR(&digitalio_pull_down_obj)) {
+ pull = MP_QSTR_DOWN;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_digitalio, MP_QSTR_Pull, pull);
+}
+
+const mp_obj_type_t digitalio_pull_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Pull,
+ .print = digitalio_pull_print,
+ .locals_dict = (mp_obj_dict_t *)&digitalio_pull_locals_dict,
+};
+
+digitalio_pull_t validate_pull(mp_rom_obj_t obj, qstr arg_name) {
+ if (obj == MP_ROM_PTR(&digitalio_pull_up_obj)) {
+ return PULL_UP;
+ } else if (obj == MP_ROM_PTR(&digitalio_pull_down_obj)) {
+ return PULL_DOWN;
+ }
+ if (obj == MP_ROM_NONE) {
+ return PULL_NONE;
+ }
+ mp_raise_TypeError_varg(translate("%q must be of type %q or None"), arg_name, MP_QSTR_Pull);
+}
diff --git a/circuitpython/shared-bindings/digitalio/Pull.h b/circuitpython/shared-bindings/digitalio/Pull.h
new file mode 100644
index 0000000..f4f6c42
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/Pull.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_PULL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_PULL_H
+
+#include "py/obj.h"
+
+typedef enum _digitalio_pull_t {
+ PULL_NONE,
+ PULL_UP,
+ PULL_DOWN
+} digitalio_pull_t;
+
+extern const mp_obj_type_t digitalio_pull_type;
+
+typedef struct {
+ mp_obj_base_t base;
+} digitalio_pull_obj_t;
+extern const digitalio_pull_obj_t digitalio_pull_up_obj;
+extern const digitalio_pull_obj_t digitalio_pull_down_obj;
+
+digitalio_pull_t validate_pull(mp_rom_obj_t obj, qstr arg_name);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_PULL_H
diff --git a/circuitpython/shared-bindings/digitalio/__init__.c b/circuitpython/shared-bindings/digitalio/__init__.c
new file mode 100644
index 0000000..9a9db69
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/__init__.c
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/digitalio/__init__.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/digitalio/Direction.h"
+#include "shared-bindings/digitalio/DriveMode.h"
+#include "shared-bindings/digitalio/Pull.h"
+
+#include "py/runtime.h"
+
+//| """Basic digital pin support
+//|
+//| The `digitalio` module contains classes to provide access to basic digital IO.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import digitalio
+//| import board
+//|
+//| pin = digitalio.DigitalInOut(board.LED)
+//| print(pin.value)
+//|
+//| This example will initialize the the device, read
+//| :py:data:`~digitalio.DigitalInOut.value` and then
+//| :py:meth:`~digitalio.DigitalInOut.deinit` the hardware.
+//|
+//| Here is blinky::
+//|
+//| import time
+//| import digitalio
+//| import board
+//|
+//| led = digitalio.DigitalInOut(board.LED)
+//| led.direction = digitalio.Direction.OUTPUT
+//| while True:
+//| led.value = True
+//| time.sleep(0.1)
+//| led.value = False
+//| time.sleep(0.1)
+//|
+//| For the essentials of `digitalio`, see the `CircuitPython Essentials
+//| Learn guide <https://learn.adafruit.com/circuitpython-essentials/circuitpython-digital-in-out>`_
+//|
+//| For more information on using `digitalio`, see `this additional Learn guide
+//| <https://learn.adafruit.com/circuitpython-digital-inputs-and-outputs>`_
+//| """
+
+STATIC const mp_rom_map_elem_t digitalio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_digitalio) },
+ { MP_ROM_QSTR(MP_QSTR_DigitalInOut), MP_ROM_PTR(&digitalio_digitalinout_type) },
+
+ // Enum-like Classes.
+ { MP_ROM_QSTR(MP_QSTR_Direction), MP_ROM_PTR(&digitalio_direction_type) },
+ { MP_ROM_QSTR(MP_QSTR_DriveMode), MP_ROM_PTR(&digitalio_drive_mode_type) },
+ { MP_ROM_QSTR(MP_QSTR_Pull), MP_ROM_PTR(&digitalio_pull_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(digitalio_module_globals, digitalio_module_globals_table);
+
+const mp_obj_module_t digitalio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&digitalio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_digitalio, digitalio_module, CIRCUITPY_DIGITALIO);
diff --git a/circuitpython/shared-bindings/digitalio/__init__.h b/circuitpython/shared-bindings/digitalio/__init__.h
new file mode 100644
index 0000000..8ab7f78
--- /dev/null
+++ b/circuitpython/shared-bindings/digitalio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO___INIT___H
diff --git a/circuitpython/shared-bindings/displayio/Bitmap.c b/circuitpython/shared-bindings/displayio/Bitmap.c
new file mode 100644
index 0000000..3af152f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Bitmap.c
@@ -0,0 +1,370 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Bitmap.h"
+#include "shared-module/displayio/Bitmap.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Bitmap:
+//| """Stores values of a certain size in a 2D array
+//|
+//| Bitmaps can be treated as read-only buffers. If the number of bits in a pixel is 8, 16, or 32; and the number of bytes
+//| per row is a multiple of 4, then the resulting memoryview will correspond directly with the bitmap's contents. Otherwise,
+//| the bitmap data is packed into the memoryview with unspecified padding.
+//|
+//| A Bitmap can be treated as a buffer, allowing its content to be
+//| viewed and modified using e.g., with ``ulab.numpy.frombuffer``,
+//| but the `displayio.Bitmap.dirty` method must be used to inform
+//| displayio when a bitmap was modified through the buffer interface.
+//|
+//| `bitmaptools.arrayblit` can also be useful to move data efficiently
+//| into a Bitmap.
+//| """
+//|
+//| def __init__(self, width: int, height: int, value_count: int) -> None:
+//| """Create a Bitmap object with the given fixed size. Each pixel stores a value that is used to
+//| index into a corresponding palette. This enables differently colored sprites to share the
+//| underlying Bitmap. value_count is used to minimize the memory used to store the Bitmap.
+//|
+//| :param int width: The number of values wide
+//| :param int height: The number of values high
+//| :param int value_count: The number of possible pixel values."""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mp_arg_check_num(n_args, n_kw, 3, 3, false);
+ uint32_t width = mp_obj_get_int(all_args[0]);
+ uint32_t height = mp_obj_get_int(all_args[1]);
+ uint32_t value_count = mp_obj_get_int(all_args[2]);
+ uint32_t bits = 1;
+
+ if (value_count == 0) {
+ mp_raise_ValueError(translate("value_count must be > 0"));
+ }
+ while ((value_count - 1) >> bits) {
+ if (bits < 8) {
+ bits <<= 1;
+ } else {
+ bits += 8;
+ }
+ }
+
+ displayio_bitmap_t *self = m_new_obj(displayio_bitmap_t);
+ self->base.type = &displayio_bitmap_type;
+ common_hal_displayio_bitmap_construct(self, width, height, bits);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+//| width: int
+//| """Width of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_bitmap_obj_get_width(mp_obj_t self_in) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_width(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_get_width_obj, displayio_bitmap_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_bitmap_width_obj,
+ (mp_obj_t)&displayio_bitmap_get_width_obj);
+
+//| height: int
+//| """Height of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_bitmap_obj_get_height(mp_obj_t self_in) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_height(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_get_height_obj, displayio_bitmap_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_bitmap_height_obj,
+ (mp_obj_t)&displayio_bitmap_get_height_obj);
+
+//| def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+//| """Returns the value at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| print(bitmap[0,1])"""
+//| ...
+//|
+//| def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None:
+//| """Sets the value at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| bitmap[0,1] = 3"""
+//| ...
+//|
+STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value_obj) {
+ if (value_obj == mp_const_none) {
+ // delete item
+ mp_raise_AttributeError(translate("Cannot delete values"));
+ return mp_const_none;
+ }
+
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (mp_obj_is_type(index_obj, &mp_type_slice)) {
+ // TODO(tannewt): Implement subscr after slices support start, stop and step tuples.
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ return mp_const_none;
+ }
+
+ uint16_t x = 0;
+ uint16_t y = 0;
+ if (mp_obj_is_small_int(index_obj)) {
+ mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj);
+ uint16_t width = common_hal_displayio_bitmap_get_width(self);
+ x = i % width;
+ y = i / width;
+ } else {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(index_obj, 2, &items);
+ x = mp_obj_get_int(items[0]);
+ y = mp_obj_get_int(items[1]);
+ if (x >= common_hal_displayio_bitmap_get_width(self) || y >= common_hal_displayio_bitmap_get_height(self)) {
+ mp_raise_IndexError(translate("pixel coordinates out of bounds"));
+ }
+ }
+
+ if (value_obj == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_bitmap_get_pixel(self, x, y));
+ } else {
+ mp_uint_t value = (mp_uint_t)mp_obj_get_int(value_obj);
+ if ((value >> common_hal_displayio_bitmap_get_bits_per_value(self)) != 0) {
+ mp_raise_ValueError(translate("pixel value requires too many bits"));
+ }
+ common_hal_displayio_bitmap_set_pixel(self, x, y, value);
+ }
+ return mp_const_none;
+}
+
+//| def blit(self, x: int, y: int, source_bitmap: Bitmap, *, x1: int, y1: int, x2: int, y2: int, skip_index: int) -> None:
+//| """Inserts the source_bitmap region defined by rectangular boundaries
+//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
+//|
+//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
+//| corner will be placed
+//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
+//| corner will be placed
+//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
+//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
+//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
+//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
+//| :param int skip_index: bitmap palette index in the source that will not be copied,
+//| set to None to copy all pixels"""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {ARG_x, ARG_y, ARG_source, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index};
+ static const mp_arg_t allowed_args[] = {
+ {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ {MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ {MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ {MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
+ {MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
+ {MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ int16_t x = args[ARG_x].u_int;
+ int16_t y = args[ARG_y].u_int;
+
+ displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);
+
+
+ // ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
+ if (self->bits_per_value < source->bits_per_value) {
+ mp_raise_ValueError(translate("source palette too large"));
+ }
+
+ int16_t x1 = args[ARG_x1].u_int;
+ int16_t y1 = args[ARG_y1].u_int;
+ int16_t x2, y2;
+ // if x2 or y2 is None, then set as the maximum size of the source bitmap
+ if (args[ARG_x2].u_obj == mp_const_none) {
+ x2 = source->width;
+ } else {
+ x2 = mp_obj_get_int(args[ARG_x2].u_obj);
+ }
+ // int16_t y2;
+ if (args[ARG_y2].u_obj == mp_const_none) {
+ y2 = source->height;
+ } else {
+ y2 = mp_obj_get_int(args[ARG_y2].u_obj);
+ }
+
+ // Check x,y are within self (target) bitmap boundary
+ if ((x < 0) || (y < 0) || (x > self->width) || (y > self->height)) {
+ mp_raise_ValueError(translate("out of range of target"));
+ }
+ // Check x1,y1,x2,y2 are within source bitmap boundary
+ if ((x1 < 0) || (x1 > source->width) ||
+ (y1 < 0) || (y1 > source->height) ||
+ (x2 < 0) || (x2 > source->width) ||
+ (y2 < 0) || (y2 > source->height)) {
+ mp_raise_ValueError(translate("out of range of source"));
+ }
+
+ // Ensure x1 < x2 and y1 < y2
+ if (x1 > x2) {
+ int16_t temp = x2;
+ x2 = x1;
+ x1 = temp;
+ }
+ if (y1 > y2) {
+ int16_t temp = y2;
+ y2 = y1;
+ y1 = temp;
+ }
+
+ uint32_t skip_index;
+ bool skip_index_none; // flag whether skip_value was None
+
+ if (args[ARG_skip_index].u_obj == mp_const_none) {
+ skip_index = 0;
+ skip_index_none = true;
+ } else {
+ skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
+ skip_index_none = false;
+ }
+
+ common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 1, displayio_bitmap_obj_blit);
+
+//| def fill(self, value: int) -> None:
+//| """Fills the bitmap with the supplied palette index value."""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_fill(mp_obj_t self_in, mp_obj_t value_obj) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_uint_t value = (mp_uint_t)mp_obj_get_int(value_obj);
+ if ((value >> common_hal_displayio_bitmap_get_bits_per_value(self)) != 0) {
+ mp_raise_ValueError(translate("pixel value requires too many bits"));
+ }
+ common_hal_displayio_bitmap_fill(self, value);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_bitmap_fill_obj, displayio_bitmap_obj_fill);
+
+//| def dirty(self, x1: int=0, y1: int=0, x2: int=-1, y2:int = -1) -> None:
+//| """Inform displayio of bitmap updates done via the buffer
+//| protocol.
+//|
+//| :param int x1: Minimum x-value for rectangular bounding box to be considered as modified
+//| :param int y1: Minimum y-value for rectangular bounding box to be considered as modified
+//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be considered as modified
+//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be considered as modified
+//|
+//| If x1 or y1 are not specified, they are taken as 0. If x2 or y2
+//| are not specified, or are given as -1, they are taken as the width
+//| and height of the image. Thus, calling dirty() with the
+//| default arguments treats the whole bitmap as modified.
+//|
+//| When a bitmap is modified through the buffer protocol, the
+//| display will not be properly updated unless the bitmap is
+//| notified of the "dirty rectangle" that encloses all modified
+//| pixels."""
+//| ...
+//|
+STATIC mp_obj_t displayio_bitmap_obj_dirty(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ enum { ARG_x1, ARG_y1, ARG_x2, ARG_y2 };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_x1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_y1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_x2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_y2, MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_area_t dirty_area = {
+ .x1 = args[ARG_x1].u_int,
+ .y1 = args[ARG_y1].u_int,
+ .x2 = args[ARG_x2].u_int == -1 ? self->width : args[ARG_x2].u_int,
+ .y2 = args[ARG_y2].u_int == -1 ? self->height : args[ARG_y2].u_int,
+ };
+
+ displayio_bitmap_set_dirty_area(self, &dirty_area);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_dirty_obj, 0, displayio_bitmap_obj_dirty);
+
+STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_bitmap_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_bitmap_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&displayio_bitmap_blit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dirty), MP_ROM_PTR(&displayio_bitmap_dirty_obj) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_bitmap_locals_dict, displayio_bitmap_locals_dict_table);
+
+// (the get_buffer protocol returns 0 for success, 1 for failure)
+STATIC mp_int_t bitmap_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ displayio_bitmap_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_displayio_bitmap_get_buffer(self, bufinfo, flags);
+}
+
+const mp_obj_type_t displayio_bitmap_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Bitmap,
+ .make_new = displayio_bitmap_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_bitmap_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = bitmap_subscr,
+ .buffer_p = { .get_buffer = bitmap_get_buffer },
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Bitmap.h b/circuitpython/shared-bindings/displayio/Bitmap.h
new file mode 100644
index 0000000..4580475
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Bitmap.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
+
+#include "shared-module/displayio/Bitmap.h"
+
+extern const mp_obj_type_t displayio_bitmap_type;
+
+void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t width,
+ uint32_t height, uint32_t bits_per_value);
+
+void common_hal_displayio_bitmap_load_row(displayio_bitmap_t *self, uint16_t y, uint8_t *data,
+ uint16_t len);
+uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self);
+uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self);
+uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self);
+void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value);
+void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source,
+ int16_t x1, int16_t y1, int16_t x2, int16_t y2,
+ uint32_t skip_index, bool skip_index_none);
+uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y);
+void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value);
+int common_hal_displayio_bitmap_get_buffer(displayio_bitmap_t *self, mp_buffer_info_t *bufinfo, mp_uint_t flags);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BITMAP_H
diff --git a/circuitpython/shared-bindings/displayio/ColorConverter.c b/circuitpython/shared-bindings/displayio/ColorConverter.c
new file mode 100644
index 0000000..18b8866
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/ColorConverter.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/ColorConverter.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/enum.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class ColorConverter:
+//| """Converts one color format to another."""
+//|
+//| def __init__(self, *, input_colorspace: Colorspace=Colorspace.RGB888, dither: bool = False) -> None:
+//| """Create a ColorConverter object to convert color formats.
+//|
+//| :param Colorspace colorspace: The source colorspace, one of the Colorspace constants
+//| :param bool dither: Adds random noise to dither the output image"""
+//| ...
+//|
+
+STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_dither, ARG_input_colorspace };
+
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_input_colorspace, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (void *)&displayio_colorspace_RGB888_obj} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t);
+ self->base.type = &displayio_colorconverter_type;
+
+ common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_input_colorspace].u_obj));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def convert(self, color: int) -> int:
+//| """Converts the given color to RGB565 according to the Colorspace"""
+//| ...
+//|
+STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t color_obj) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t color;
+ if (!mp_obj_get_int_maybe(color_obj, &color)) {
+ mp_raise_ValueError(translate("color should be an int"));
+ }
+ _displayio_colorspace_t colorspace;
+ colorspace.depth = 16;
+ uint32_t output_color;
+ common_hal_displayio_colorconverter_convert(self, &colorspace, color, &output_color);
+ return MP_OBJ_NEW_SMALL_INT(output_color);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert);
+
+//| dither: bool
+//| """When `True` the ColorConverter dithers the output by adding random noise when
+//| truncating to display bitdepth"""
+//|
+STATIC mp_obj_t displayio_colorconverter_obj_get_dither(mp_obj_t self_in) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_displayio_colorconverter_get_dither(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_get_dither_obj, displayio_colorconverter_obj_get_dither);
+
+STATIC mp_obj_t displayio_colorconverter_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_displayio_colorconverter_set_dither(self, mp_obj_is_true(dither));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_set_dither_obj, displayio_colorconverter_obj_set_dither);
+
+MP_PROPERTY_GETSET(displayio_colorconverter_dither_obj,
+ (mp_obj_t)&displayio_colorconverter_get_dither_obj,
+ (mp_obj_t)&displayio_colorconverter_set_dither_obj);
+
+//| def make_transparent(self, color: int) -> None:
+//| """Set the transparent color or index for the ColorConverter. This will
+//| raise an Exception if there is already a selected transparent index.
+//|
+//| :param int color: The color to be transparent"""
+//|
+STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_obj_t transparent_color_obj) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj);
+ common_hal_displayio_colorconverter_make_transparent(self, transparent_color);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent);
+
+//| def make_opaque(self, color: int) -> None:
+//| """Make the ColorConverter be opaque and have no transparent pixels.
+//|
+//| :param int color: [IGNORED] Use any value"""
+//|
+STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) {
+ displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj);
+ common_hal_displayio_colorconverter_make_opaque(self, transparent_color);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque);
+
+STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) },
+ { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_colorconverter_make_transparent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_colorconverter_make_opaque_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table);
+
+const mp_obj_type_t displayio_colorconverter_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ColorConverter,
+ .make_new = displayio_colorconverter_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_colorconverter_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/ColorConverter.h b/circuitpython/shared-bindings/displayio/ColorConverter.h
new file mode 100644
index 0000000..12fa8da
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/ColorConverter.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
+
+#include "shared-bindings/displayio/__init__.h"
+#include "shared-module/displayio/ColorConverter.h"
+
+#include "shared-module/displayio/Palette.h"
+
+extern const mp_obj_type_t displayio_colorconverter_type;
+
+void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t *self, bool dither, displayio_colorspace_t input_colorspace);
+void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t *colorspace, uint32_t input_color, uint32_t *output_color);
+uint32_t displayio_colorconverter_convert_pixel(displayio_colorspace_t colorspace, uint32_t pixel);
+
+void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t *self, bool dither);
+bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t *self);
+
+void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t *self, uint32_t transparent_color);
+void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t *self, uint32_t transparent_color);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H
diff --git a/circuitpython/shared-bindings/displayio/Colorspace.c b/circuitpython/shared-bindings/displayio/Colorspace.c
new file mode 100644
index 0000000..3692dc2
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Colorspace.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/displayio/__init__.h"
+
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB888, DISPLAYIO_COLORSPACE_RGB888);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB565, DISPLAYIO_COLORSPACE_RGB565);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB565_SWAPPED, DISPLAYIO_COLORSPACE_RGB565_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB555, DISPLAYIO_COLORSPACE_RGB555);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB555_SWAPPED, DISPLAYIO_COLORSPACE_RGB555_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR565, DISPLAYIO_COLORSPACE_BGR565);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR565_SWAPPED, DISPLAYIO_COLORSPACE_BGR565_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR555, DISPLAYIO_COLORSPACE_BGR555);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, BGR555_SWAPPED, DISPLAYIO_COLORSPACE_BGR555_SWAPPED);
+MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, L8, DISPLAYIO_COLORSPACE_L8);
+
+//| class Colorspace:
+//| """The colorspace for a `ColorConverter` to operate in"""
+//|
+//| RGB888: Colorspace
+//| """The standard 24-bit colorspace. Bits 0-7 are blue, 8-15 are green, and 16-24 are red. (0xRRGGBB)"""
+//|
+//| RGB565: Colorspace
+//| """The standard 16-bit colorspace. Bits 0-4 are blue, bits 5-10 are green, and 11-15 are red (0bRRRRRGGGGGGBBBBB)"""
+//|
+//| RGB565_SWAPPED: Colorspace
+//| """The swapped 16-bit colorspace. First, the high and low 8 bits of the number are swapped, then they are interpreted as for RGB565"""
+//|
+//| RGB555: Colorspace
+//| """The standard 15-bit colorspace. Bits 0-4 are blue, bits 5-9 are green, and 11-14 are red. The top bit is ignored. (0bxRRRRRGGGGGBBBBB)"""
+//|
+//| RGB555_SWAPPED: Colorspace
+//| """The swapped 15-bit colorspace. First, the high and low 8 bits of the number are swapped, then they are interpreted as for RGB555"""
+//|
+MAKE_ENUM_MAP(displayio_colorspace) {
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB888),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB565),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB565_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB555),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, RGB555_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR565),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR565_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR555),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, BGR555_SWAPPED),
+ MAKE_ENUM_MAP_ENTRY(displayio_colorspace, L8),
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_colorspace_locals_dict, displayio_colorspace_locals_table);
+
+MAKE_PRINTER(displayio, displayio_colorspace);
+MAKE_ENUM_TYPE(displayio, ColorSpace, displayio_colorspace);
diff --git a/circuitpython/shared-bindings/displayio/Display.c b/circuitpython/shared-bindings/displayio/Display.c
new file mode 100644
index 0000000..b19c0ba
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Display.c
@@ -0,0 +1,524 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Display.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| _DisplayBus = Union['FourWire', 'paralleldisplay.ParallelBus', 'I2CDisplay']
+//| """:py:class:`FourWire`, :py:class:`paralleldisplay.ParallelBus` or :py:class:`I2CDisplay`"""
+//|
+
+//|
+//| class Display:
+//| """Manage updating a display over a display bus
+//|
+//| This initializes a display and connects it into CircuitPython. Unlike other
+//| objects in CircuitPython, Display objects live until `displayio.release_displays()`
+//| is called. This is done so that CircuitPython can use the display itself.
+//|
+//| Most people should not use this class directly. Use a specific display driver instead that will
+//| contain the initialization sequence at minimum."""
+//|
+//| def __init__(self, display_bus: _DisplayBus, init_sequence: ReadableBuffer, *, width: int, height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, color_depth: int = 16, grayscale: bool = False, pixels_in_byte_share_row: bool = True, bytes_per_cell: int = 1, reverse_pixels_in_byte: bool = False, set_column_command: int = 0x2a, set_row_command: int = 0x2b, write_ram_command: int = 0x2c, backlight_pin: Optional[microcontroller.Pin] = None, brightness_command: Optional[int] = None, brightness: float = 1.0, auto_brightness: bool = False, single_byte_bounds: bool = False, data_as_commands: bool = False, auto_refresh: bool = True, native_frames_per_second: int = 60, backlight_on_high: bool = True, SH1107_addressing: bool = False) -> None:
+//| r"""Create a Display object on the given display bus (`FourWire`, `ParallelBus` or `I2CDisplay`).
+//|
+//| The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a
+//| command byte followed by a byte to determine the parameter count and delay. When the top bit
+//| of the second byte is 1 (0x80), a delay will occur after the command parameters are sent.
+//| The remaining 7 bits are the parameter count excluding any delay byte. The bytes following
+//| are the parameters. When the delay bit is set, a single byte after the parameters specifies
+//| the delay duration in milliseconds. The value 0xff will lead to an extra long 500 ms delay
+//| instead of 255 ms. The next byte will begin a new command definition.
+//| Here is an example:
+//|
+//| .. code-block:: python
+//|
+//| init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma
+//| b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms)
+//| b"\x29\x81\xaa\x78"# Display on then delay 0x78 (120ms)
+//| )
+//| display = displayio.Display(display_bus, init_sequence, width=320, height=240)
+//|
+//| The first command is 0xe1 with 15 (0xf) parameters following. The second is 0x11 with 0
+//| parameters and a 120ms (0x78) delay. The third command is 0x29 with one parameter 0xaa and a
+//| 120ms delay (0x78). Multiple byte literals (b"") are merged together on load. The parens
+//| are needed to allow byte literals on subsequent lines.
+//|
+//| The initialization sequence should always leave the display memory access inline with the scan
+//| of the display to minimize tearing artifacts.
+//|
+//| :param display_bus: The bus that the display is connected to
+//| :type _DisplayBus: FourWire, ParallelBus or I2CDisplay
+//| :param ~circuitpython_typing.ReadableBuffer init_sequence: Byte-packed initialization sequence.
+//| :param int width: Width in pixels
+//| :param int height: Height in pixels
+//| :param int colstart: The index if the first visible column
+//| :param int rowstart: The index if the first visible row
+//| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)
+//| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays
+//| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.)
+//| :param bool grayscale: True if the display only shows a single color.
+//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column.
+//| :param int bytes_per_cell: Number of bytes per addressable memory location when color_depth < 8. When greater than one, bytes share a row or column according to pixels_in_byte_share_row.
+//| :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.)
+//| :param bool reverse_bytes_in_word: Reverses the order of bytes within a word when color_depth == 16
+//| :param int set_column_command: Command used to set the start and end columns to update
+//| :param int set_row_command: Command used so set the start and end rows to update
+//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set.
+//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight
+//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers.
+//| :param float brightness: Initial display brightness. This value is ignored if auto_brightness is True.
+//| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism.
+//| :param bool single_byte_bounds: Display column and row commands use single bytes
+//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this.
+//| :param bool auto_refresh: Automatically refresh the screen
+//| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence.
+//| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.
+//| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set
+//| :param int set_vertical_scroll: This parameter is accepted but ignored for backwards compatibility. It will be removed in a future release.
+//| """
+//| ...
+//|
+STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart,
+ ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row,
+ ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word,
+ ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command,
+ ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command,
+ ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands,
+ ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high,
+ ARG_SH1107_addressing };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} },
+ { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_bytes_per_cell, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_reverse_pixels_in_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_reverse_bytes_in_word, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} },
+ { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} },
+ { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} },
+ { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} },
+ { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} },
+ { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} },
+ { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} },
+ { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_SH1107_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t display_bus = args[ARG_display_bus].u_obj;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ const mcu_pin_obj_t *backlight_pin = validate_obj_is_free_pin_or_none(args[ARG_backlight_pin].u_obj);
+
+ mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj);
+
+ mp_int_t rotation = args[ARG_rotation].u_int;
+ if (rotation % 90 != 0) {
+ mp_raise_ValueError(translate("Display rotation must be in 90 degree increments"));
+ }
+
+ const bool sh1107_addressing = args[ARG_SH1107_addressing].u_bool;
+ const mp_int_t color_depth = args[ARG_color_depth].u_int;
+ if (sh1107_addressing && color_depth != 1) {
+ mp_raise_ValueError_varg(translate("%q must be 1 when %q is True"), MP_QSTR_color_depth, MP_QSTR_SH1107_addressing);
+ }
+
+ primary_display_t *disp = allocate_display_or_raise();
+ displayio_display_obj_t *self = &disp->display;
+
+ self->base.type = &displayio_display_type;
+ common_hal_displayio_display_construct(
+ self,
+ display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
+ color_depth, args[ARG_grayscale].u_bool,
+ args[ARG_pixels_in_byte_share_row].u_bool,
+ args[ARG_bytes_per_cell].u_bool,
+ args[ARG_reverse_pixels_in_byte].u_bool,
+ args[ARG_reverse_bytes_in_word].u_bool,
+ args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int,
+ args[ARG_write_ram_command].u_int,
+ bufinfo.buf, bufinfo.len,
+ MP_OBJ_TO_PTR(backlight_pin),
+ args[ARG_brightness_command].u_int,
+ brightness,
+ args[ARG_auto_brightness].u_bool,
+ args[ARG_single_byte_bounds].u_bool,
+ args[ARG_data_as_commands].u_bool,
+ args[ARG_auto_refresh].u_bool,
+ args[ARG_native_frames_per_second].u_int,
+ args[ARG_backlight_on_high].u_bool,
+ sh1107_addressing
+ );
+
+ return self;
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_display_obj_t *native_display(mp_obj_t display_obj) {
+ mp_obj_t native_display = mp_obj_cast_to_native_base(display_obj, &displayio_display_type);
+ mp_obj_assert_native_inited(native_display);
+ return MP_OBJ_TO_PTR(native_display);
+}
+
+//| def show(self, group: Group) -> None:
+//| """Switches to displaying the given group of layers. When group is None, the default
+//| CircuitPython terminal will be shown.
+//|
+//| :param Group group: The group to show."""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ displayio_group_t *group = NULL;
+ if (group_in != mp_const_none) {
+ group = MP_OBJ_TO_PTR(native_group(group_in));
+ }
+
+ bool ok = common_hal_displayio_display_show(self, group);
+ if (!ok) {
+ mp_raise_ValueError(translate("Group already used"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show);
+
+//| def refresh(self, *, target_frames_per_second: Optional[int] = None, minimum_frames_per_second: int = 0) -> bool:
+//| """When auto_refresh is off, and :py:attr:`target_frames_per_second` is not `None` this waits
+//| for the target frame rate and then refreshes the display,
+//| returning `True`. If the call has taken too long since the last refresh call for the given
+//| target frame rate, then the refresh returns `False` immediately without updating the screen to
+//| hopefully help getting caught up.
+//|
+//| If the time since the last successful refresh is below the minimum frame rate, then an
+//| exception will be raised. The default :py:attr:`minimum_frames_per_second` of 0 disables this behavior.
+//|
+//| When auto_refresh is off, and :py:attr:`target_frames_per_second` is `None` this
+//| will update the display immediately.
+//|
+//| When auto_refresh is on, updates the display immediately. (The display will also update
+//| without calls to this.)
+//|
+//| :param Optional[int] target_frames_per_second: The target frame rate that :py:func:`refresh` should try to
+//| achieve. Set to `None` for immediate refresh.
+//| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second."""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_display_obj_t *self = native_display(pos_args[0]);
+ uint32_t maximum_ms_per_real_frame = 0xffffffff;
+ mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int;
+ if (minimum_frames_per_second > 0) {
+ maximum_ms_per_real_frame = 1000 / minimum_frames_per_second;
+ }
+
+ uint32_t target_ms_per_frame;
+ if (args[ARG_target_frames_per_second].u_obj == mp_const_none) {
+ target_ms_per_frame = 0xffffffff;
+ } else {
+ target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj);
+ }
+
+ return mp_obj_new_bool(common_hal_displayio_display_refresh(self, target_ms_per_frame, maximum_ms_per_real_frame));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh);
+
+//| auto_refresh: bool
+//| """True when the display is refreshed automatically."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_auto_refresh(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_display_get_auto_refresh(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_refresh_obj, displayio_display_obj_get_auto_refresh);
+
+STATIC mp_obj_t displayio_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) {
+ displayio_display_obj_t *self = native_display(self_in);
+
+ common_hal_displayio_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_refresh_obj, displayio_display_obj_set_auto_refresh);
+
+MP_PROPERTY_GETSET(displayio_display_auto_refresh_obj,
+ (mp_obj_t)&displayio_display_get_auto_refresh_obj,
+ (mp_obj_t)&displayio_display_set_auto_refresh_obj);
+
+//| brightness: float
+//| """The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When
+//| `auto_brightness` is True, the value of `brightness` will change automatically.
+//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ mp_float_t brightness = common_hal_displayio_display_get_brightness(self);
+ if (brightness < 0) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_obj_new_float(brightness);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness);
+
+STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) {
+ displayio_display_obj_t *self = native_display(self_in);
+ common_hal_displayio_display_set_auto_brightness(self, false);
+ mp_float_t brightness = mp_obj_get_float(brightness_obj);
+ if (brightness < 0 || brightness > 1.0) {
+ mp_raise_ValueError(translate("Brightness must be 0-1.0"));
+ }
+ bool ok = common_hal_displayio_display_set_brightness(self, brightness);
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_brightness_obj, displayio_display_obj_set_brightness);
+
+MP_PROPERTY_GETSET(displayio_display_brightness_obj,
+ (mp_obj_t)&displayio_display_get_brightness_obj,
+ (mp_obj_t)&displayio_display_set_brightness_obj);
+
+//| auto_brightness: bool
+//| """True when the display brightness is adjusted automatically, based on an ambient
+//| light sensor or other method. Note that some displays may have this set to True by default,
+//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False
+//| if `brightness` is set manually."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness);
+
+STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) {
+ displayio_display_obj_t *self = native_display(self_in);
+
+ common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_brightness_obj, displayio_display_obj_set_auto_brightness);
+
+MP_PROPERTY_GETSET(displayio_display_auto_brightness_obj,
+ (mp_obj_t)&displayio_display_get_auto_brightness_obj,
+ (mp_obj_t)&displayio_display_set_auto_brightness_obj);
+
+
+
+
+//| width: int
+//| """Gets the width of the board"""
+//|
+STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_display_width_obj,
+ (mp_obj_t)&displayio_display_get_width_obj);
+
+//| height: int
+//| """Gets the height of the board"""
+//|
+STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_display_height_obj,
+ (mp_obj_t)&displayio_display_get_height_obj);
+
+//| rotation: int
+//| """The rotation of the display as an int in degrees."""
+//|
+STATIC mp_obj_t displayio_display_obj_get_rotation(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_rotation(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_rotation_obj, displayio_display_obj_get_rotation);
+STATIC mp_obj_t displayio_display_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) {
+ displayio_display_obj_t *self = native_display(self_in);
+ common_hal_displayio_display_set_rotation(self, mp_obj_get_int(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_rotation_obj, displayio_display_obj_set_rotation);
+
+
+MP_PROPERTY_GETSET(displayio_display_rotation_obj,
+ (mp_obj_t)&displayio_display_get_rotation_obj,
+ (mp_obj_t)&displayio_display_set_rotation_obj);
+
+//| bus: _DisplayBus
+//| """The bus being used by the display"""
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return common_hal_displayio_display_get_bus(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus);
+
+MP_PROPERTY_GETTER(displayio_display_bus_obj,
+ (mp_obj_t)&displayio_display_get_bus_obj);
+
+//| root_group: Group
+//| """The root group on the display."""
+//|
+//|
+STATIC mp_obj_t displayio_display_obj_get_root_group(mp_obj_t self_in) {
+ displayio_display_obj_t *self = native_display(self_in);
+ return common_hal_displayio_display_get_root_group(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_root_group_obj, displayio_display_obj_get_root_group);
+
+MP_PROPERTY_GETTER(displayio_display_root_group_obj,
+ (mp_obj_t)&displayio_display_get_root_group_obj);
+
+
+//| def fill_row(self, y: int, buffer: WriteableBuffer) -> WriteableBuffer:
+//| """Extract the pixels from a single row
+//|
+//| :param int y: The top edge of the area
+//| :param ~circuitpython_typing.WriteableBuffer buffer: The buffer in which to place the pixel data"""
+//| ...
+//|
+STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_y, ARG_buffer };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = -1} },
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ displayio_display_obj_t *self = native_display(pos_args[0]);
+ mp_int_t y = args[ARG_y].u_int;
+ mp_obj_t *result = args[ARG_buffer].u_obj;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_WRITE);
+
+ if (self->core.colorspace.depth != 16) {
+ mp_raise_ValueError(translate("Display must have a 16 bit colorspace."));
+ }
+
+ displayio_area_t area = {
+ .x1 = 0,
+ .y1 = y,
+ .x2 = self->core.width,
+ .y2 = y + 1
+ };
+ uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth;
+ uint16_t buffer_size = self->core.width / pixels_per_word;
+ uint16_t pixels_per_buffer = displayio_area_size(&area);
+ if (pixels_per_buffer % pixels_per_word) {
+ buffer_size += 1;
+ }
+
+ uint32_t *result_buffer = bufinfo.buf;
+ size_t result_buffer_size = bufinfo.len;
+
+ if (result_buffer_size >= (buffer_size * 4)) {
+ volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1;
+ uint32_t mask[mask_length];
+
+ for (uint16_t k = 0; k < mask_length; k++) {
+ mask[k] = 0x00000000;
+ }
+
+ displayio_display_core_fill_area(&self->core, &area, mask, result_buffer);
+ return result;
+ } else {
+ mp_raise_ValueError(translate("Buffer is too small"));
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_fill_row_obj, 1, displayio_display_obj_fill_row);
+
+STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_display_refresh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_display_rotation_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) },
+ { MP_ROM_QSTR(MP_QSTR_root_group), MP_ROM_PTR(&displayio_display_root_group_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table);
+
+const mp_obj_type_t displayio_display_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Display,
+ .make_new = displayio_display_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_display_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/Display.h b/circuitpython/shared-bindings/displayio/Display.h
new file mode 100644
index 0000000..f193e61
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Display.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/displayio/Display.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_display_type;
+
+#define NO_BRIGHTNESS_COMMAND 0x100
+
+void common_hal_displayio_display_construct(displayio_display_obj_t *self,
+ mp_obj_t bus, uint16_t width, uint16_t height,
+ int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale,
+ bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word,
+ uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command,
+ uint8_t *init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t *backlight_pin, uint16_t brightness_command,
+ mp_float_t brightness, bool auto_brightness,
+ bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second,
+ bool backlight_on_high, bool SH1107_addressing);
+
+bool common_hal_displayio_display_show(displayio_display_obj_t *self,
+ displayio_group_t *root_group);
+
+bool common_hal_displayio_display_refresh(displayio_display_obj_t *self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame);
+
+bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t *self);
+void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t *self, bool auto_refresh);
+
+uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t *self);
+uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t *self);
+uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t *self);
+void common_hal_displayio_display_set_rotation(displayio_display_obj_t *self, int rotation);
+
+bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t *self);
+void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t *self, bool auto_brightness);
+
+bool common_hal_displayio_display_get_dither(displayio_display_obj_t *self);
+void common_hal_displayio_display_set_dither(displayio_display_obj_t *self, bool dither);
+
+mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t *self);
+bool common_hal_displayio_display_set_brightness(displayio_display_obj_t *self, mp_float_t brightness);
+
+mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t *self);
+mp_obj_t common_hal_displayio_display_get_root_group(displayio_display_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H
diff --git a/circuitpython/shared-bindings/displayio/EPaperDisplay.c b/circuitpython/shared-bindings/displayio/EPaperDisplay.c
new file mode 100644
index 0000000..94d2978
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/EPaperDisplay.c
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/EPaperDisplay.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class EPaperDisplay:
+//| """Manage updating an epaper display over a display bus
+//|
+//| This initializes an epaper display and connects it into CircuitPython. Unlike other
+//| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()`
+//| is called. This is done so that CircuitPython can use the display itself.
+//|
+//| Most people should not use this class directly. Use a specific display driver instead that will
+//| contain the startup and shutdown sequences at minimum."""
+//|
+//| def __init__(self, display_bus: _DisplayBus,
+//| start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *,
+//| width: int, height: int, ram_width: int, ram_height: int,
+//| colstart: int = 0, rowstart: int = 0, rotation: int = 0,
+//| set_column_window_command: Optional[int] = None,
+//| set_row_window_command: Optional[int] = None,
+//| set_current_column_command: Optional[int] = None,
+//| set_current_row_command: Optional[int] = None,
+//| write_black_ram_command: int, black_bits_inverted: bool = False,
+//| write_color_ram_command: Optional[int] = None,
+//| color_bits_inverted: bool = False, highlight_color: int = 0x000000,
+//| refresh_display_command: int, refresh_time: float = 40,
+//| busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True,
+//| seconds_per_frame: float = 180, always_toggle_chip_select: bool = False,
+//| grayscale: bool = False, two_byte_sequence_length: bool = False) -> None:
+//| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `paralleldisplay.ParallelBus`).
+//|
+//| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every
+//| command begins with a command byte followed by a byte to determine the parameter count and
+//| delay. When the top bit of the second byte is 1 (0x80), a delay will occur after the command
+//| parameters are sent. The remaining 7 bits are the parameter count excluding any delay
+//| byte. The bytes following are the parameters. When the delay bit is set, a single byte after
+//| the parameters specifies the delay duration in milliseconds. The value 0xff will lead to an
+//| extra long 500 ms delay instead of 255 ms. The next byte will begin a new command definition.
+//|
+//| :param display_bus: The bus that the display is connected to
+//| :type _DisplayBus: displayio.FourWire or paralleldisplay.ParallelBus
+//| :param ~circuitpython_typing.ReadableBuffer start_sequence: Byte-packed initialization sequence.
+//| :param ~circuitpython_typing.ReadableBuffer stop_sequence: Byte-packed initialization sequence.
+//| :param int width: Width in pixels
+//| :param int height: Height in pixels
+//| :param int ram_width: RAM width in pixels
+//| :param int ram_height: RAM height in pixels
+//| :param int colstart: The index if the first visible column
+//| :param int rowstart: The index if the first visible row
+//| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)
+//| :param int set_column_window_command: Command used to set the start and end columns to update
+//| :param int set_row_window_command: Command used so set the start and end rows to update
+//| :param int set_current_column_command: Command used to set the current column location
+//| :param int set_current_row_command: Command used to set the current row location
+//| :param int write_black_ram_command: Command used to write pixels values into the update region
+//| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black.
+//| :param int write_color_ram_command: Command used to write pixels values into the update region
+//| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color.
+//| :param int highlight_color: RGB888 of source color to highlight with third ePaper color.
+//| :param int refresh_display_command: Command used to start a display refresh
+//| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided.
+//| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy
+//| :param bool busy_state: State of the busy pin when the display is busy
+//| :param float seconds_per_frame: Minimum number of seconds between screen refreshes
+//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte
+//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale
+//| :param bool two_byte_sequence_length: When true, use two bytes to define sequence length"""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height,
+ ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation,
+ ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command,
+ ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted,
+ ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color,
+ ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state,
+ ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_two_byte_sequence_length };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_stop_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_ram_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_ram_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, },
+ { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_set_column_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_row_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_current_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_set_current_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} },
+ { MP_QSTR_write_black_ram_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} },
+ { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} },
+ { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
+ { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_two_byte_sequence_length, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t display_bus = args[ARG_display_bus].u_obj;
+
+ mp_buffer_info_t start_bufinfo;
+ mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_bufinfo, MP_BUFFER_READ);
+ mp_buffer_info_t stop_bufinfo;
+ mp_get_buffer_raise(args[ARG_stop_sequence].u_obj, &stop_bufinfo, MP_BUFFER_READ);
+
+
+ const mcu_pin_obj_t *busy_pin = validate_obj_is_free_pin_or_none(args[ARG_busy_pin].u_obj);
+
+ mp_int_t rotation = args[ARG_rotation].u_int;
+ if (rotation % 90 != 0) {
+ mp_raise_ValueError(translate("Display rotation must be in 90 degree increments"));
+ }
+
+ primary_display_t *disp = allocate_display_or_raise();
+ displayio_epaperdisplay_obj_t *self = &disp->epaper_display;
+ ;
+
+ mp_float_t refresh_time = mp_obj_get_float(args[ARG_refresh_time].u_obj);
+ mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj);
+
+ mp_int_t write_color_ram_command = NO_COMMAND;
+ mp_int_t highlight_color = args[ARG_highlight_color].u_int;
+ if (args[ARG_write_color_ram_command].u_obj != mp_const_none) {
+ write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj);
+ }
+
+ self->base.type = &displayio_epaperdisplay_type;
+ common_hal_displayio_epaperdisplay_construct(
+ self,
+ display_bus,
+ start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len,
+ args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int,
+ args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation,
+ args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int,
+ args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int,
+ args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command,
+ args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time,
+ busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame,
+ args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_two_byte_sequence_length].u_bool
+ );
+
+ return self;
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_epaperdisplay_obj_t *native_display(mp_obj_t display_obj) {
+ mp_obj_t native_display = mp_obj_cast_to_native_base(display_obj, &displayio_epaperdisplay_type);
+ mp_obj_assert_native_inited(native_display);
+ return MP_OBJ_TO_PTR(native_display);
+}
+
+//| def show(self, group: Group) -> None:
+//| """Switches to displaying the given group of layers. When group is None, the default
+//| CircuitPython terminal will be shown.
+//|
+//| :param Group group: The group to show."""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ displayio_group_t *group = NULL;
+ if (group_in != mp_const_none) {
+ group = MP_OBJ_TO_PTR(native_group(group_in));
+ }
+
+ bool ok = common_hal_displayio_epaperdisplay_show(self, group);
+ if (!ok) {
+ mp_raise_ValueError(translate("Group already used"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show);
+
+//| def update_refresh_mode(self, start_sequence: ReadableBuffer, seconds_per_frame: float = 180) -> None:
+//| """Updates the ``start_sequence`` and ``seconds_per_frame`` parameters to enable
+//| varying the refresh mode of the display."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_update_refresh_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_start_sequence, ARG_seconds_per_frame };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_seconds_per_frame, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} },
+ };
+ displayio_epaperdisplay_obj_t *self = native_display(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Get parameters
+ mp_buffer_info_t start_sequence;
+ mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_sequence, MP_BUFFER_READ);
+ float seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj);
+
+ // Update parameters
+ displayio_epaperdisplay_change_refresh_mode_parameters(self, &start_sequence, seconds_per_frame);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_epaperdisplay_update_refresh_mode_obj, 1, displayio_epaperdisplay_update_refresh_mode);
+
+//| def refresh(self) -> None:
+//| """Refreshes the display immediately or raises an exception if too soon. Use
+//| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur."""
+//| ...
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_refresh(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ bool ok = common_hal_displayio_epaperdisplay_refresh(self);
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Refresh too soon"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_obj, displayio_epaperdisplay_obj_refresh);
+
+//| time_to_refresh: float
+//| """Time, in fractional seconds, until the ePaper display can be refreshed."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self) / 1000.0);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_time_to_refresh_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_time_to_refresh_obj);
+
+//| busy: bool
+//| """True when the display is refreshing. This uses the ``busy_pin`` when available or the
+//| ``refresh_time`` otherwise."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_busy(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_displayio_epaperdisplay_get_busy(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_busy_obj, displayio_epaperdisplay_obj_get_busy);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_busy_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_busy_obj);
+
+//| width: int
+//| """Gets the width of the display in pixels"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_width(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_width_obj, displayio_epaperdisplay_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_width_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_width_obj);
+
+//| height: int
+//| """Gets the height of the display in pixels"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_height(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_height_obj, displayio_epaperdisplay_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_height_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_height_obj);
+
+//| rotation: int
+//| """The rotation of the display as an int in degrees."""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_rotation(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_rotation(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_rotation_obj, displayio_epaperdisplay_obj_get_rotation);
+STATIC mp_obj_t displayio_epaperdisplay_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ common_hal_displayio_epaperdisplay_set_rotation(self, mp_obj_get_int(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_set_rotation_obj, displayio_epaperdisplay_obj_set_rotation);
+
+
+MP_PROPERTY_GETSET(displayio_epaperdisplay_rotation_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_rotation_obj,
+ (mp_obj_t)&displayio_epaperdisplay_set_rotation_obj);
+
+//| bus: _DisplayBus
+//| """The bus being used by the display"""
+//|
+STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) {
+ displayio_epaperdisplay_obj_t *self = native_display(self_in);
+ return common_hal_displayio_epaperdisplay_get_bus(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus);
+
+MP_PROPERTY_GETTER(displayio_epaperdisplay_bus_obj,
+ (mp_obj_t)&displayio_epaperdisplay_get_bus_obj);
+
+
+STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) },
+ { MP_ROM_QSTR(MP_QSTR_update_refresh_mode), MP_ROM_PTR(&displayio_epaperdisplay_update_refresh_mode_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_epaperdisplay_rotation_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) },
+ { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&displayio_epaperdisplay_busy_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table);
+
+const mp_obj_type_t displayio_epaperdisplay_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_EPaperDisplay,
+ .make_new = displayio_epaperdisplay_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_epaperdisplay_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/EPaperDisplay.h b/circuitpython/shared-bindings/displayio/EPaperDisplay.h
new file mode 100644
index 0000000..ba6dffc
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/EPaperDisplay.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/displayio/EPaperDisplay.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_epaperdisplay_type;
+
+#define NO_COMMAND 0x100
+
+void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t *self,
+ mp_obj_t bus, const uint8_t *start_sequence, uint16_t start_sequence_len, const uint8_t *stop_sequence, uint16_t stop_sequence_len,
+ uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation,
+ uint16_t set_column_window_command, uint16_t set_row_window_command,
+ uint16_t set_current_column_command, uint16_t set_current_row_command,
+ uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time,
+ const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale, bool two_byte_sequence_length);
+
+bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t *self);
+
+bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t *self, displayio_group_t *root_group);
+
+// Returns time in milliseconds.
+uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t *self);
+bool common_hal_displayio_epaperdisplay_get_busy(displayio_epaperdisplay_obj_t *self);
+
+uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t *self);
+uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t *self);
+uint16_t common_hal_displayio_epaperdisplay_get_rotation(displayio_epaperdisplay_obj_t *self);
+void common_hal_displayio_epaperdisplay_set_rotation(displayio_epaperdisplay_obj_t *self, int rotation);
+
+mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H
diff --git a/circuitpython/shared-bindings/displayio/FourWire.c b/circuitpython/shared-bindings/displayio/FourWire.c
new file mode 100644
index 0000000..90aa5c6
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/FourWire.c
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/FourWire.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class FourWire:
+//| """Manage updating a display over SPI four wire protocol in the background while Python code runs.
+//| It doesn't handle display initialization."""
+//|
+//| def __init__(self, spi_bus: busio.SPI, *, command: Optional[microcontroller.Pin], chip_select: microcontroller.Pin, reset: Optional[microcontroller.Pin] = None, baudrate: int = 24000000, polarity: int = 0, phase: int = 0) -> None:
+//| """Create a FourWire object associated with the given pins.
+//|
+//| The SPI bus and pins are then in use by the display until `displayio.release_displays()` is
+//| called even after a reload. (It does this so CircuitPython can use the display after your code
+//| is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func:`displayio.release_displays` first, otherwise it will error after the first code.py run.
+//|
+//| If the ``command`` pin is not specified, a 9-bit SPI mode will be simulated by adding a
+//| data/command bit to every bit being transmitted, and splitting the resulting data back
+//| into 8-bit bytes for transmission. The extra bits that this creates at the end are ignored
+//| by the receiving device.
+//|
+//| :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines
+//| :param microcontroller.Pin command: Data or command pin. When None, 9-bit SPI is simulated.
+//| :param microcontroller.Pin chip_select: Chip select pin
+//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used
+//| :param int baudrate: Maximum baudrate in Hz for the display on the bus
+//| :param int polarity: the base state of the clock line (0 or 1)
+//| :param int phase: the edge of the clock that data is captured. First (0)
+//| or second (1). Rising or falling depends on clock polarity."""
+//| ...
+//|
+STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_spi_bus, ARG_command, ARG_chip_select, ARG_reset, ARG_baudrate, ARG_polarity, ARG_phase };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ { MP_QSTR_baudrate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 24000000} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *command = validate_obj_is_free_pin_or_none(args[ARG_command].u_obj);
+ const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ mp_obj_t spi = mp_arg_validate_type(args[ARG_spi_bus].u_obj, &busio_spi_type, MP_QSTR_spi_bus);
+
+ displayio_fourwire_obj_t *self = &allocate_display_bus_or_raise()->fourwire_bus;
+ self->base.type = &displayio_fourwire_type;
+
+ uint8_t polarity = args[ARG_polarity].u_int;
+ if (polarity != 0 && polarity != 1) {
+ mp_raise_ValueError(translate("Invalid polarity"));
+ }
+ uint8_t phase = args[ARG_phase].u_int;
+ if (phase != 0 && phase != 1) {
+ mp_raise_ValueError(translate("Invalid phase"));
+ }
+
+ common_hal_displayio_fourwire_construct(self,
+ MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int, polarity, phase);
+ return self;
+}
+
+//| def reset(self) -> None:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
+//|
+STATIC mp_obj_t displayio_fourwire_obj_reset(mp_obj_t self_in) {
+ displayio_fourwire_obj_t *self = self_in;
+
+ if (!common_hal_displayio_fourwire_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_reset_obj, displayio_fourwire_obj_reset);
+
+//| def send(self, command: int, data: ReadableBuffer, *, toggle_every_byte: bool = False) -> None:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
+//|
+STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_command, ARG_data, ARG_toggle_every_byte };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_toggle_every_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t command_int = args[ARG_command].u_int;
+ if (command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ displayio_fourwire_obj_t *self = pos_args[0];
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_displayio_fourwire_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED;
+ if (args[ARG_toggle_every_byte].u_bool) {
+ chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE;
+ }
+ common_hal_displayio_fourwire_send(self, DISPLAY_COMMAND, chip_select, &command, 1);
+ common_hal_displayio_fourwire_send(self, DISPLAY_DATA, chip_select, ((uint8_t *)bufinfo.buf), bufinfo.len);
+ common_hal_displayio_fourwire_end_transaction(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 1, displayio_fourwire_obj_send);
+
+STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_fourwire_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_fourwire_locals_dict, displayio_fourwire_locals_dict_table);
+
+const mp_obj_type_t displayio_fourwire_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_FourWire,
+ .make_new = displayio_fourwire_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_fourwire_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/FourWire.h b/circuitpython/shared-bindings/displayio/FourWire.h
new file mode 100644
index 0000000..300327f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/FourWire.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
+
+#include "shared-module/displayio/FourWire.h"
+
+#include "shared-bindings/displayio/__init__.h"
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_fourwire_type;
+
+void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t *self,
+ busio_spi_obj_t *spi, const mcu_pin_obj_t *command,
+ const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *reset, uint32_t baudrate,
+ uint8_t polarity, uint8_t phase);
+
+void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t *self);
+
+bool common_hal_displayio_fourwire_reset(mp_obj_t self);
+bool common_hal_displayio_fourwire_bus_free(mp_obj_t self);
+
+bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self);
+
+void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type,
+ display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
+
+void common_hal_displayio_fourwire_end_transaction(mp_obj_t self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H
diff --git a/circuitpython/shared-bindings/displayio/Group.c b/circuitpython/shared-bindings/displayio/Group.c
new file mode 100644
index 0000000..188331f
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Group.c
@@ -0,0 +1,355 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Group.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class Group:
+//| """Manage a group of sprites and groups and how they are inter-related."""
+//|
+//| def __init__(self, *, scale: int = 1, x: int = 0, y: int = 0) -> None:
+//| """Create a Group of a given size and scale. Scale is in one dimension. For example, scale=2
+//| leads to a layer's pixel being 2x2 pixels when in the group.
+//|
+//| :param int scale: Scale of layer pixels in one dimension.
+//| :param int x: Initial x position within the parent.
+//| :param int y: Initial y position within the parent."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_scale, ARG_x, ARG_y };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_scale, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t scale = args[ARG_scale].u_int;
+ if (scale < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_scale);
+ }
+
+ displayio_group_t *self = m_new_obj(displayio_group_t);
+ self->base.type = &displayio_group_type;
+ common_hal_displayio_group_construct(self, scale, args[ARG_x].u_int, args[ARG_y].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+displayio_group_t *native_group(mp_obj_t group_obj) {
+ mp_obj_t native_group = mp_obj_cast_to_native_base(group_obj, &displayio_group_type);
+ if (native_group == MP_OBJ_NULL) {
+ mp_raise_ValueError_varg(translate("Must be a %q subclass."), MP_QSTR_Group);
+ }
+ mp_obj_assert_native_inited(native_group);
+ return MP_OBJ_TO_PTR(native_group);
+}
+
+//| hidden: bool
+//| """True when the Group and all of it's layers are not visible. When False, the Group's layers
+//| are visible if they haven't been hidden."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_hidden(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return mp_obj_new_bool(common_hal_displayio_group_get_hidden(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_hidden_obj, displayio_group_obj_get_hidden);
+
+STATIC mp_obj_t displayio_group_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ common_hal_displayio_group_set_hidden(self, mp_obj_is_true(hidden_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_hidden_obj, displayio_group_obj_set_hidden);
+
+MP_PROPERTY_GETSET(displayio_group_hidden_obj,
+ (mp_obj_t)&displayio_group_get_hidden_obj,
+ (mp_obj_t)&displayio_group_set_hidden_obj);
+
+//| scale: int
+//| """Scales each pixel within the Group in both directions. For example, when scale=2 each pixel
+//| will be represented by 2x2 pixels."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_scale(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_scale(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_scale_obj, displayio_group_obj_get_scale);
+
+STATIC mp_obj_t displayio_group_obj_set_scale(mp_obj_t self_in, mp_obj_t scale_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t scale = mp_obj_get_int(scale_obj);
+ if (scale < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_scale);
+ }
+ common_hal_displayio_group_set_scale(self, scale);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_scale_obj, displayio_group_obj_set_scale);
+
+MP_PROPERTY_GETSET(displayio_group_scale_obj,
+ (mp_obj_t)&displayio_group_get_scale_obj,
+ (mp_obj_t)&displayio_group_set_scale_obj);
+
+//| x: int
+//| """X position of the Group in the parent."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_x(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_x_obj, displayio_group_obj_get_x);
+
+STATIC mp_obj_t displayio_group_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ common_hal_displayio_group_set_x(self, x);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_x_obj, displayio_group_obj_set_x);
+
+MP_PROPERTY_GETSET(displayio_group_x_obj,
+ (mp_obj_t)&displayio_group_get_x_obj,
+ (mp_obj_t)&displayio_group_set_x_obj);
+
+//| y: int
+//| """Y position of the Group in the parent."""
+//|
+STATIC mp_obj_t displayio_group_obj_get_y(mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_group_get_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_y_obj, displayio_group_obj_get_y);
+
+STATIC mp_obj_t displayio_group_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) {
+ displayio_group_t *self = native_group(self_in);
+
+ mp_int_t y = mp_obj_get_int(y_obj);
+ common_hal_displayio_group_set_y(self, y);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_y_obj, displayio_group_obj_set_y);
+
+MP_PROPERTY_GETSET(displayio_group_y_obj,
+ (mp_obj_t)&displayio_group_get_y_obj,
+ (mp_obj_t)&displayio_group_set_y_obj);
+
+//| def append(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Append a layer to the group. It will be drawn above other layers."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_append(mp_obj_t self_in, mp_obj_t layer) {
+ displayio_group_t *self = native_group(self_in);
+ common_hal_displayio_group_insert(self, common_hal_displayio_group_get_len(self), layer);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_append_obj, displayio_group_obj_append);
+
+//| def insert(self, index: int, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Insert a layer into the group."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_insert(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t layer) {
+ displayio_group_t *self = native_group(self_in);
+ if ((size_t)MP_OBJ_SMALL_INT_VALUE(index_obj) == common_hal_displayio_group_get_len(self)) {
+ return displayio_group_obj_append(self_in, layer);
+ }
+ size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false);
+ common_hal_displayio_group_insert(self, index, layer);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(displayio_group_insert_obj, displayio_group_obj_insert);
+
+
+//| def index(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> int:
+//| """Returns the index of the first copy of layer. Raises ValueError if not found."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_index(mp_obj_t self_in, mp_obj_t layer) {
+ displayio_group_t *self = native_group(self_in);
+ mp_int_t index = common_hal_displayio_group_index(self, layer);
+ if (index < 0) {
+ mp_raise_ValueError(translate("object not in sequence"));
+ }
+ return MP_OBJ_NEW_SMALL_INT(index);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_index_obj, displayio_group_obj_index);
+
+//| def pop(self, i: int = -1) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]:
+//| """Remove the ith item and return it."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_pop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_i };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i, MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_group_t *self = native_group(pos_args[0]);
+
+ size_t index = mp_get_index(&displayio_group_type,
+ common_hal_displayio_group_get_len(self),
+ MP_OBJ_NEW_SMALL_INT(args[ARG_i].u_int),
+ false);
+ return common_hal_displayio_group_pop(self, index);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_pop_obj, 1, displayio_group_obj_pop);
+
+
+//| def remove(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Remove the first copy of layer. Raises ValueError if it is not present."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_remove(mp_obj_t self_in, mp_obj_t layer) {
+ mp_obj_t index = displayio_group_obj_index(self_in, layer);
+ displayio_group_t *self = native_group(self_in);
+
+ common_hal_displayio_group_pop(self, MP_OBJ_SMALL_INT_VALUE(index));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_remove_obj, displayio_group_obj_remove);
+
+//| def __bool__(self) -> bool:
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Returns the number of layers in a Group"""
+//| ...
+//|
+STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ displayio_group_t *self = native_group(self_in);
+ uint16_t len = common_hal_displayio_group_get_len(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __getitem__(self, index: int) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]:
+//| """Returns the value at the given index.
+//|
+//| This allows you to::
+//|
+//| print(group[0])"""
+//| ...
+//|
+//| def __setitem__(self, index: int, value: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None:
+//| """Sets the value at the given index.
+//|
+//| This allows you to::
+//|
+//| group[0] = sprite"""
+//| ...
+//|
+//| def __delitem__(self, index: int) -> None:
+//| """Deletes the value at the given index.
+//|
+//| This allows you to::
+//|
+//| del group[0]"""
+//| ...
+//|
+STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) {
+ displayio_group_t *self = native_group(self_in);
+
+ if (mp_obj_is_type(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false);
+
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ return common_hal_displayio_group_get(self, index);
+ } else if (value == MP_OBJ_NULL) {
+ common_hal_displayio_group_pop(self, index);
+ } else {
+ common_hal_displayio_group_set(self, index, value);
+ }
+ }
+ return mp_const_none;
+}
+
+//| def sort(self, key: function, reverse: bool) -> None:
+//| """Sort the members of the group."""
+//| ...
+//|
+STATIC mp_obj_t displayio_group_obj_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ displayio_group_t *self = native_group(pos_args[0]);
+ mp_obj_t *args = m_new(mp_obj_t, n_args);
+ for (size_t i = 1; i < n_args; ++i) {
+ args[i] = pos_args[i];
+ }
+ args[0] = MP_OBJ_FROM_PTR(self->members);
+ return mp_obj_list_sort(n_args, args, kw_args);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_sort_obj, 1, displayio_group_obj_sort);
+
+STATIC const mp_rom_map_elem_t displayio_group_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_group_hidden_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&displayio_group_scale_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_group_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_group_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&displayio_group_append_obj) },
+ { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&displayio_group_insert_obj) },
+ { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&displayio_group_index_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&displayio_group_pop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&displayio_group_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&displayio_group_sort_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_group_locals_dict, displayio_group_locals_dict_table);
+
+const mp_obj_type_t displayio_group_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Group,
+ .make_new = displayio_group_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_group_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = group_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Group.h b/circuitpython/shared-bindings/displayio/Group.h
new file mode 100644
index 0000000..266fce9
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Group.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
+
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t displayio_group_type;
+
+displayio_group_t *native_group(mp_obj_t group_obj);
+
+void common_hal_displayio_group_construct(displayio_group_t *self, uint32_t scale, mp_int_t x, mp_int_t y);
+uint32_t common_hal_displayio_group_get_scale(displayio_group_t *self);
+void common_hal_displayio_group_set_scale(displayio_group_t *self, uint32_t scale);
+bool common_hal_displayio_group_get_hidden(displayio_group_t *self);
+void common_hal_displayio_group_set_hidden(displayio_group_t *self, bool hidden);
+mp_int_t common_hal_displayio_group_get_x(displayio_group_t *self);
+void common_hal_displayio_group_set_x(displayio_group_t *self, mp_int_t x);
+mp_int_t common_hal_displayio_group_get_y(displayio_group_t *self);
+void common_hal_displayio_group_set_y(displayio_group_t *self, mp_int_t y);
+void common_hal_displayio_group_append(displayio_group_t *self, mp_obj_t layer);
+void common_hal_displayio_group_insert(displayio_group_t *self, size_t index, mp_obj_t layer);
+size_t common_hal_displayio_group_get_len(displayio_group_t *self);
+mp_obj_t common_hal_displayio_group_pop(displayio_group_t *self, size_t index);
+mp_int_t common_hal_displayio_group_index(displayio_group_t *self, mp_obj_t layer);
+mp_obj_t common_hal_displayio_group_get(displayio_group_t *self, size_t index);
+void common_hal_displayio_group_set(displayio_group_t *self, size_t index, mp_obj_t layer);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GROUP_H
diff --git a/circuitpython/shared-bindings/displayio/I2CDisplay.c b/circuitpython/shared-bindings/displayio/I2CDisplay.c
new file mode 100644
index 0000000..fbfbd04
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/I2CDisplay.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/I2CDisplay.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/busio/I2C.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class I2CDisplay:
+//| """Manage updating a display over I2C in the background while Python code runs.
+//| It doesn't handle display initialization."""
+//|
+//| def __init__(self, i2c_bus: busio.I2C, *, device_address: int, reset: Optional[microcontroller.Pin] = None) -> None:
+//| """Create a I2CDisplay object associated with the given I2C bus and reset pin.
+//|
+//| The I2C bus and pins are then in use by the display until `displayio.release_displays()` is
+//| called even after a reload. (It does this so CircuitPython can use the display after your code
+//| is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func:`displayio.release_displays` first, otherwise it will error after the first code.py run.
+//|
+//| :param busio.I2C i2c_bus: The I2C bus that make up the clock and data lines
+//| :param int device_address: The I2C address of the device
+//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used"""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_i2c_bus, ARG_device_address, ARG_reset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i2c_bus, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_device_address, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c_bus].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus);
+ displayio_i2cdisplay_obj_t *self = &allocate_display_bus_or_raise()->i2cdisplay_bus;
+ self->base.type = &displayio_i2cdisplay_type;
+
+ common_hal_displayio_i2cdisplay_construct(self,
+ MP_OBJ_TO_PTR(i2c), args[ARG_device_address].u_int, reset);
+ return self;
+}
+
+//| def reset(self) -> None:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_obj_reset(mp_obj_t self_in) {
+ displayio_i2cdisplay_obj_t *self = self_in;
+
+ if (!common_hal_displayio_i2cdisplay_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_i2cdisplay_reset_obj, displayio_i2cdisplay_obj_reset);
+
+//| def send(self, command: int, data: ReadableBuffer) -> None:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
+//|
+STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) {
+ mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj);
+ if (!mp_obj_is_small_int(command_obj) || command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ uint8_t full_command[bufinfo.len + 1];
+ full_command[0] = command;
+ memcpy(full_command + 1, ((uint8_t *)bufinfo.buf), bufinfo.len);
+ common_hal_displayio_i2cdisplay_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, full_command, bufinfo.len + 1);
+ common_hal_displayio_i2cdisplay_end_transaction(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send);
+
+STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_i2cdisplay_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table);
+
+const mp_obj_type_t displayio_i2cdisplay_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2CDisplay,
+ .make_new = displayio_i2cdisplay_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_i2cdisplay_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/I2CDisplay.h b/circuitpython/shared-bindings/displayio/I2CDisplay.h
new file mode 100644
index 0000000..d40cd19
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/I2CDisplay.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
+
+#include "shared-module/displayio/I2CDisplay.h"
+
+#include "shared-bindings/displayio/__init__.h"
+#include "common-hal/microcontroller/Pin.h"
+
+extern const mp_obj_type_t displayio_i2cdisplay_type;
+
+void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t *self,
+ busio_i2c_obj_t *i2c, uint16_t device_address, const mcu_pin_obj_t *reset);
+
+void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t *self);
+
+bool common_hal_displayio_i2cdisplay_reset(mp_obj_t self);
+bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self);
+
+bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self);
+
+void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type,
+ display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
+
+void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H
diff --git a/circuitpython/shared-bindings/displayio/OnDiskBitmap.c b/circuitpython/shared-bindings/displayio/OnDiskBitmap.c
new file mode 100644
index 0000000..aa749bf
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/OnDiskBitmap.c
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+
+#include <stdint.h>
+
+#include "py/runtime.h"
+#include "py/objproperty.h"
+#include "supervisor/shared/translate.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+
+//| class OnDiskBitmap:
+//| """Loads values straight from disk. This minimizes memory use but can lead to
+//| much slower pixel load times. These load times may result in frame tearing where only part of
+//| the image is visible.
+//|
+//| It's easiest to use on a board with a built in display such as the `Hallowing M0 Express
+//| <https://www.adafruit.com/product/3900>`_.
+//|
+//| .. code-block:: Python
+//|
+//| import board
+//| import displayio
+//| import time
+//| import pulseio
+//|
+//| board.DISPLAY.auto_brightness = False
+//| board.DISPLAY.brightness = 0
+//| splash = displayio.Group()
+//| board.DISPLAY.show(splash)
+//|
+//| odb = displayio.OnDiskBitmap('/sample.bmp')
+//| face = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
+//| splash.append(face)
+//| # Wait for the image to load.
+//| board.DISPLAY.refresh(target_frames_per_second=60)
+//|
+//| # Fade up the backlight
+//| for i in range(100):
+//| board.DISPLAY.brightness = 0.01 * i
+//| time.sleep(0.05)
+//|
+//| # Wait forever
+//| while True:
+//| pass"""
+//|
+//| def __init__(self, file: Union[str,typing.BinaryIO]) -> None:
+//| """Create an OnDiskBitmap object with the given file.
+//|
+//| :param file file: The name of the bitmap file. For backwards compatibility, a file opened in binary mode may also be passed.
+//|
+//| Older versions of CircuitPython required a file opened in binary
+//| mode. CircuitPython 7.0 modified OnDiskBitmap so that it takes a
+//| filename instead, and opens the file internally. A future version
+//| of CircuitPython will remove the ability to pass in an opened file.
+//| """
+//| ...
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_obj_t arg = all_args[0];
+
+ if (mp_obj_is_str(arg)) {
+ arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb));
+ }
+ if (!mp_obj_is_type(arg, &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+
+ displayio_ondiskbitmap_t *self = m_new_obj(displayio_ondiskbitmap_t);
+ self->base.type = &displayio_ondiskbitmap_type;
+ common_hal_displayio_ondiskbitmap_construct(self, MP_OBJ_TO_PTR(arg));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| width: int
+//| """Width of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_width(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_ondiskbitmap_get_width(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_width_obj, displayio_ondiskbitmap_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_ondiskbitmap_width_obj,
+ (mp_obj_t)&displayio_ondiskbitmap_get_width_obj);
+
+//| height: int
+//| """Height of the bitmap. (read only)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_height(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_ondiskbitmap_get_height(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_height_obj, displayio_ondiskbitmap_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_ondiskbitmap_height_obj,
+ (mp_obj_t)&displayio_ondiskbitmap_get_height_obj);
+
+//| pixel_shader: Union[ColorConverter, Palette]
+//| """The image's pixel_shader. The type depends on the underlying
+//| bitmap's structure. The pixel shader can be modified (e.g., to set the
+//| transparent pixel or, for palette shaded images, to update the palette.)"""
+//|
+STATIC mp_obj_t displayio_ondiskbitmap_obj_get_pixel_shader(mp_obj_t self_in) {
+ displayio_ondiskbitmap_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_displayio_ondiskbitmap_get_pixel_shader(self);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_ondiskbitmap_get_pixel_shader_obj, displayio_ondiskbitmap_obj_get_pixel_shader);
+
+const mp_obj_property_t displayio_ondiskbitmap_pixel_shader_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&displayio_ondiskbitmap_get_pixel_shader_obj,
+ (mp_obj_t)MP_ROM_NONE,
+ (mp_obj_t)MP_ROM_NONE},
+};
+
+
+STATIC const mp_rom_map_elem_t displayio_ondiskbitmap_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_ondiskbitmap_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_ondiskbitmap_pixel_shader_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_ondiskbitmap_width_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_ondiskbitmap_locals_dict, displayio_ondiskbitmap_locals_dict_table);
+
+const mp_obj_type_t displayio_ondiskbitmap_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_OnDiskBitmap,
+ .make_new = displayio_ondiskbitmap_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_ondiskbitmap_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/OnDiskBitmap.h b/circuitpython/shared-bindings/displayio/OnDiskBitmap.h
new file mode 100644
index 0000000..6d534ec
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/OnDiskBitmap.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
+
+#include "shared-module/displayio/OnDiskBitmap.h"
+#include "extmod/vfs_fat.h"
+
+extern const mp_obj_type_t displayio_ondiskbitmap_type;
+
+void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, pyb_file_obj_t *file);
+
+uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *bitmap,
+ int16_t x, int16_t y);
+
+uint16_t common_hal_displayio_ondiskbitmap_get_height(displayio_ondiskbitmap_t *self);
+mp_obj_t common_hal_displayio_ondiskbitmap_get_pixel_shader(displayio_ondiskbitmap_t *self);
+uint16_t common_hal_displayio_ondiskbitmap_get_width(displayio_ondiskbitmap_t *self);
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_ONDISKBITMAP_H
diff --git a/circuitpython/shared-bindings/displayio/Palette.c b/circuitpython/shared-bindings/displayio/Palette.c
new file mode 100644
index 0000000..ad6d7c3
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Palette.c
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Palette.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Palette:
+//| """Map a pixel palette_index to a full color. Colors are transformed to the display's format internally to
+//| save memory."""
+//|
+//| def __init__(self, color_count: int) -> None:
+//| """Create a Palette object to store a set number of colors.
+//|
+//| :param int color_count: The number of colors in the Palette"""
+//| ...
+//|
+// TODO(tannewt): Add support for other color formats.
+// TODO(tannewt): Add support for 8-bit alpha blending.
+//|
+STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_color_count };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_palette_t *self = m_new_obj(displayio_palette_t);
+ self->base.type = &displayio_palette_type;
+ common_hal_displayio_palette_construct(self, args[ARG_color_count].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def __bool__(self) -> bool:
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Returns the number of colors in a Palette"""
+//| ...
+//|
+STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_const_true;
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_len(self));
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __getitem__(self, index: int) -> Optional[int]:
+//| r"""Return the pixel color at the given index as an integer."""
+//| ...
+//|
+//| def __setitem__(self, index: int, value: Union[int, ReadableBuffer, Tuple[int, int, int]]) -> None:
+//| r"""Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1.
+//|
+//| The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value).
+//| Value can be an int, bytes (3 bytes (RGB) or 4 bytes (RGB + pad byte)), bytearray,
+//| or a tuple or list of 3 integers.
+//|
+//| This allows you to::
+//|
+//| palette[0] = 0xFFFFFF # set using an integer
+//| palette[1] = b'\xff\xff\x00' # set using 3 bytes
+//| palette[2] = b'\xff\xff\x00\x00' # set using 4 bytes
+//| palette[3] = bytearray(b'\x00\x00\xFF') # set using a bytearay of 3 or 4 bytes
+//| palette[4] = (10, 20, 30) # set using a tuple of 3 integers"""
+//| ...
+//|
+STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
+ if (value == MP_OBJ_NULL) {
+ // delete item
+ return MP_OBJ_NULL; // op not supported
+ }
+ // Slicing not supported. Use a duplicate Palette to swap multiple colors atomically.
+ if (mp_obj_is_type(index_in, &mp_type_slice)) {
+ return MP_OBJ_NULL;
+ }
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+ size_t index = mp_get_index(&displayio_palette_type, self->color_count, index_in, false);
+ // index read
+ if (value == MP_OBJ_SENTINEL) {
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_color(self, index));
+ }
+
+ // Convert a tuple or list to a bytearray.
+ if (mp_obj_is_type(value, &mp_type_tuple) ||
+ mp_obj_is_type(value, &mp_type_list)) {
+ value = mp_type_bytes.make_new(&mp_type_bytes, 1, 0, &value);
+ }
+
+ uint32_t color;
+ mp_int_t int_value;
+ mp_buffer_info_t bufinfo;
+ if (mp_get_buffer(value, &bufinfo, MP_BUFFER_READ)) {
+ if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) {
+ mp_raise_ValueError(translate("color buffer must be a bytearray or array of type 'b' or 'B'"));
+ }
+ uint8_t *buf = bufinfo.buf;
+ if (bufinfo.len == 3 || bufinfo.len == 4) {
+ color = buf[0] << 16 | buf[1] << 8 | buf[2];
+ } else {
+ mp_raise_ValueError(translate("color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)"));
+ }
+ } else if (mp_obj_get_int_maybe(value, &int_value)) {
+ if (int_value < 0 || int_value > 0xffffff) {
+ mp_raise_TypeError(translate("color must be between 0x000000 and 0xffffff"));
+ }
+ color = int_value;
+ } else {
+ mp_raise_TypeError(translate("color buffer must be a buffer, tuple, list, or int"));
+ }
+ common_hal_displayio_palette_set_color(self, index, color);
+ return mp_const_none;
+}
+
+//| def make_transparent(self, palette_index: int) -> None:
+//| ...
+//|
+STATIC mp_obj_t displayio_palette_obj_make_transparent(mp_obj_t self_in, mp_obj_t palette_index_obj) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ common_hal_displayio_palette_make_transparent(self, palette_index);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_make_transparent_obj, displayio_palette_obj_make_transparent);
+
+//| def make_opaque(self, palette_index: int) -> None:
+//| ...
+//|
+STATIC mp_obj_t displayio_palette_obj_make_opaque(mp_obj_t self_in, mp_obj_t palette_index_obj) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ common_hal_displayio_palette_make_opaque(self, palette_index);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_make_opaque_obj, displayio_palette_obj_make_opaque);
+
+//| def is_transparent(self, palette_index: int) -> bool:
+//| """Returns `True` if the palette index is transparent. Returns `False` if opaque."""
+//| ...
+//|
+STATIC mp_obj_t displayio_palette_obj_is_transparent(mp_obj_t self_in, mp_obj_t palette_index_obj) {
+ displayio_palette_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t palette_index;
+ if (!mp_obj_get_int_maybe(palette_index_obj, &palette_index)) {
+ mp_raise_ValueError(translate("palette_index should be an int"));
+ }
+ return mp_obj_new_bool(common_hal_displayio_palette_is_transparent(self, palette_index));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_palette_is_transparent_obj, displayio_palette_obj_is_transparent);
+
+STATIC const mp_rom_map_elem_t displayio_palette_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_palette_make_transparent_obj) },
+ { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_palette_make_opaque_obj) },
+ { MP_ROM_QSTR(MP_QSTR_is_transparent), MP_ROM_PTR(&displayio_palette_is_transparent_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_palette_locals_dict, displayio_palette_locals_dict_table);
+
+const mp_obj_type_t displayio_palette_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Palette,
+ .make_new = displayio_palette_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_palette_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = palette_subscr,
+ .unary_op = group_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/Palette.h b/circuitpython/shared-bindings/displayio/Palette.h
new file mode 100644
index 0000000..d9a7980
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Palette.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
+
+#include "shared-module/displayio/Palette.h"
+
+extern const mp_obj_type_t displayio_palette_type;
+
+void common_hal_displayio_palette_construct(displayio_palette_t *self, uint16_t color_count);
+void common_hal_displayio_palette_set_color(displayio_palette_t *self, uint32_t palette_index, uint32_t color);
+uint32_t common_hal_displayio_palette_get_color(displayio_palette_t *self, uint32_t palette_index);
+uint32_t common_hal_displayio_palette_get_len(displayio_palette_t *self);
+
+void common_hal_displayio_palette_make_opaque(displayio_palette_t *self, uint32_t palette_index);
+void common_hal_displayio_palette_make_transparent(displayio_palette_t *self, uint32_t palette_index);
+bool common_hal_displayio_palette_is_transparent(displayio_palette_t *self, uint32_t palette_index);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_PALETTE_H
diff --git a/circuitpython/shared-bindings/displayio/Shape.c b/circuitpython/shared-bindings/displayio/Shape.c
new file mode 100644
index 0000000..f39e782
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Shape.c
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/Shape.h"
+
+#include <stdint.h>
+
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Shape:
+//| """Represents a shape made by defining boundaries that may be mirrored."""
+//|
+//| def __init__(self, width: int, height: int, *, mirror_x: bool = False, mirror_y: bool = False) -> None:
+//| """Create a Shape object with the given fixed size. Each pixel is one bit and is stored by the
+//| column boundaries of the shape on each row. Each row's boundary defaults to the full row.
+//|
+//| :param int width: The number of pixels wide
+//| :param int height: The number of pixels high
+//| :param bool mirror_x: When true the left boundary is mirrored to the right.
+//| :param bool mirror_y: When true the top boundary is mirrored to the bottom."""
+//| ...
+//|
+STATIC mp_obj_t displayio_shape_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_width, ARG_height, ARG_mirror_x, ARG_mirror_y };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_mirror_x, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ { MP_QSTR_mirror_y, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t width = args[ARG_width].u_int;
+ if (width < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_width);
+ }
+ mp_int_t height = args[ARG_height].u_int;
+ if (height < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_height);
+ }
+
+ displayio_shape_t *self = m_new_obj(displayio_shape_t);
+ self->base.type = &displayio_shape_type;
+ common_hal_displayio_shape_construct(self,
+ width,
+ height,
+ args[ARG_mirror_x].u_bool,
+ args[ARG_mirror_y].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+//| def set_boundary(self, y: int, start_x: int, end_x: int) -> None:
+//| """Loads pre-packed data into the given row."""
+//| ...
+//|
+STATIC mp_obj_t displayio_shape_obj_set_boundary(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ displayio_shape_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t y;
+ if (!mp_obj_get_int_maybe(args[1], &y)) {
+ mp_raise_ValueError(translate("y should be an int"));
+ }
+ mp_int_t start_x;
+ if (!mp_obj_get_int_maybe(args[2], &start_x)) {
+ mp_raise_ValueError(translate("start_x should be an int"));
+ }
+ mp_int_t end_x;
+ if (!mp_obj_get_int_maybe(args[3], &end_x)) {
+ mp_raise_ValueError(translate("end_x should be an int"));
+ }
+ common_hal_displayio_shape_set_boundary(self, y, start_x, end_x);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(displayio_shape_set_boundary_obj, 4, 4, displayio_shape_obj_set_boundary);
+
+STATIC const mp_rom_map_elem_t displayio_shape_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_set_boundary), MP_ROM_PTR(&displayio_shape_set_boundary_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_shape_locals_dict, displayio_shape_locals_dict_table);
+
+const mp_obj_type_t displayio_shape_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Shape,
+ .make_new = displayio_shape_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_shape_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/displayio/Shape.h b/circuitpython/shared-bindings/displayio/Shape.h
new file mode 100644
index 0000000..961b57c
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/Shape.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
+
+#include "shared-module/displayio/Shape.h"
+
+extern const mp_obj_type_t displayio_shape_type;
+
+void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t width,
+ uint32_t height, bool mirror_x, bool mirror_y);
+
+void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x,
+ uint16_t end_x);
+uint32_t common_hal_displayio_shape_get_pixel(void *shape, int16_t x, int16_t y);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_SHAPE_H
diff --git a/circuitpython/shared-bindings/displayio/TileGrid.c b/circuitpython/shared-bindings/displayio/TileGrid.c
new file mode 100644
index 0000000..113721b
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/TileGrid.c
@@ -0,0 +1,502 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/displayio/TileGrid.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Bitmap.h"
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+#include "shared-bindings/displayio/Palette.h"
+#include "shared-bindings/displayio/Shape.h"
+#include "supervisor/shared/translate.h"
+
+//| class TileGrid:
+//| """A grid of tiles sourced out of one bitmap
+//|
+//| Position a grid of tiles sourced from a bitmap and pixel_shader combination. Multiple grids
+//| can share bitmaps and pixel shaders.
+//|
+//| A single tile grid is also known as a Sprite."""
+//|
+//| def __init__(self, bitmap: Union[Bitmap, OnDiskBitmap, Shape], *, pixel_shader: Union[ColorConverter, Palette], width: int = 1, height: int = 1, tile_width: Optional[int] = None, tile_height: Optional[int] = None, default_tile: int = 0, x: int = 0, y: int = 0) -> None:
+//| """Create a TileGrid object. The bitmap is source for 2d pixels. The pixel_shader is used to
+//| convert the value and its location to a display native pixel color. This may be a simple color
+//| palette lookup, a gradient, a pattern or a color transformer.
+//|
+//| To save RAM usage, tile values are only allowed in the range from 0 to 255 inclusive (single byte values).
+//|
+//| tile_width and tile_height match the height of the bitmap by default.
+//|
+//| :param Bitmap,OnDiskBitmap,Shape bitmap: The bitmap storing one or more tiles.
+//| :param ColorConverter,Palette pixel_shader: The pixel shader that produces colors from values
+//| :param int width: Width of the grid in tiles.
+//| :param int height: Height of the grid in tiles.
+//| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+//| :param int tile_height: Height of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions.
+//| :param int default_tile: Default tile index to show.
+//| :param int x: Initial x position of the left edge within the parent.
+//| :param int y: Initial y position of the top edge within the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_bitmap, ARG_pixel_shader, ARG_width, ARG_height, ARG_tile_width, ARG_tile_height, ARG_default_tile, ARG_x, ARG_y };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_tile_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_tile_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_default_tile, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t bitmap = args[ARG_bitmap].u_obj;
+
+ uint16_t bitmap_width;
+ uint16_t bitmap_height;
+ mp_obj_t native = mp_obj_cast_to_native_base(bitmap, &displayio_shape_type);
+ if (native != MP_OBJ_NULL) {
+ displayio_shape_t *bmp = MP_OBJ_TO_PTR(native);
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else if (mp_obj_is_type(bitmap, &displayio_bitmap_type)) {
+ displayio_bitmap_t *bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else if (mp_obj_is_type(bitmap, &displayio_ondiskbitmap_type)) {
+ displayio_ondiskbitmap_t *bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ bitmap_width = bmp->width;
+ bitmap_height = bmp->height;
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap);
+ }
+ mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
+ if (!mp_obj_is_type(pixel_shader, &displayio_colorconverter_type) &&
+ !mp_obj_is_type(pixel_shader, &displayio_palette_type)) {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader);
+ }
+ uint16_t tile_width = args[ARG_tile_width].u_int;
+ if (tile_width == 0) {
+ tile_width = bitmap_width;
+ }
+ uint16_t tile_height = args[ARG_tile_height].u_int;
+ if (tile_height == 0) {
+ tile_height = bitmap_height;
+ }
+ if (bitmap_width % tile_width != 0) {
+ mp_raise_ValueError(translate("Tile width must exactly divide bitmap width"));
+ }
+ if (bitmap_height % tile_height != 0) {
+ mp_raise_ValueError(translate("Tile height must exactly divide bitmap height"));
+ }
+
+ int16_t x = args[ARG_x].u_int;
+ int16_t y = args[ARG_y].u_int;
+
+ displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
+ self->base.type = &displayio_tilegrid_type;
+ common_hal_displayio_tilegrid_construct(self, native,
+ bitmap_width / tile_width, bitmap_height / tile_height,
+ pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int,
+ tile_width, tile_height, x, y, args[ARG_default_tile].u_int);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static displayio_tilegrid_t *native_tilegrid(mp_obj_t tilegrid_obj) {
+ mp_obj_t native_tilegrid = mp_obj_cast_to_native_base(tilegrid_obj, &displayio_tilegrid_type);
+ mp_obj_assert_native_inited(native_tilegrid);
+ return MP_OBJ_TO_PTR(native_tilegrid);
+}
+
+//| hidden: bool
+//| """True when the TileGrid is hidden. This may be False even when a part of a hidden Group."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_hidden(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_hidden(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_hidden_obj, displayio_tilegrid_obj_get_hidden);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_hidden(self, mp_obj_is_true(hidden_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_hidden_obj, displayio_tilegrid_obj_set_hidden);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_hidden_obj,
+ (mp_obj_t)&displayio_tilegrid_get_hidden_obj,
+ (mp_obj_t)&displayio_tilegrid_set_hidden_obj);
+
+//| x: int
+//| """X position of the left edge in the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_x(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_x_obj, displayio_tilegrid_obj_get_x);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ common_hal_displayio_tilegrid_set_x(self, x);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_x_obj, displayio_tilegrid_obj_set_x);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_x_obj,
+ (mp_obj_t)&displayio_tilegrid_get_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_x_obj);
+
+//| y: int
+//| """Y position of the top edge in the parent."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_y(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_y_obj, displayio_tilegrid_obj_get_y);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ mp_int_t y = mp_obj_get_int(y_obj);
+ common_hal_displayio_tilegrid_set_y(self, y);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_y_obj, displayio_tilegrid_obj_set_y);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_y_obj,
+ (mp_obj_t)&displayio_tilegrid_get_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_y_obj);
+
+//| width: int
+//| """Width of the tilegrid in tiles."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_width(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_width_obj, displayio_tilegrid_obj_get_width);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_width_obj,
+ (mp_obj_t)&displayio_tilegrid_get_width_obj);
+
+//| height: int
+//| """Height of the tilegrid in tiles."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_height(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_height_obj, displayio_tilegrid_obj_get_height);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_height_obj,
+ (mp_obj_t)&displayio_tilegrid_get_height_obj);
+
+//| tile_width: int
+//| """Width of a single tile in pixels."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_tile_width(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_tile_width_obj, displayio_tilegrid_obj_get_tile_width);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_tile_width_obj,
+ (mp_obj_t)&displayio_tilegrid_get_tile_width_obj);
+
+//| tile_height: int
+//| """Height of a single tile in pixels."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_tile_height(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_tile_height_obj, displayio_tilegrid_obj_get_tile_height);
+
+MP_PROPERTY_GETTER(displayio_tilegrid_tile_height_obj,
+ (mp_obj_t)&displayio_tilegrid_get_tile_height_obj);
+
+//| flip_x: bool
+//| """If true, the left edge rendered will be the right edge of the right-most tile."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_flip_x(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_x_obj, displayio_tilegrid_obj_get_flip_x);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_flip_x(mp_obj_t self_in, mp_obj_t flip_x_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_flip_x(self, mp_obj_is_true(flip_x_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_x_obj, displayio_tilegrid_obj_set_flip_x);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_flip_x_obj,
+ (mp_obj_t)&displayio_tilegrid_get_flip_x_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_x_obj);
+
+//| flip_y: bool
+//| """If true, the top edge rendered will be the bottom edge of the bottom-most tile."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_flip_y(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_y_obj, displayio_tilegrid_obj_get_flip_y);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_flip_y(mp_obj_t self_in, mp_obj_t flip_y_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_flip_y(self, mp_obj_is_true(flip_y_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_y_obj, displayio_tilegrid_obj_set_flip_y);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_flip_y_obj,
+ (mp_obj_t)&displayio_tilegrid_get_flip_y_obj,
+ (mp_obj_t)&displayio_tilegrid_set_flip_y_obj);
+
+
+//| transpose_xy: bool
+//| """If true, the TileGrid's axis will be swapped. When combined with mirroring, any 90 degree
+//| rotation can be achieved along with the corresponding mirrored version."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_transpose_xy(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return mp_obj_new_bool(common_hal_displayio_tilegrid_get_transpose_xy(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_transpose_xy_obj, displayio_tilegrid_obj_get_transpose_xy);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_transpose_xy(mp_obj_t self_in, mp_obj_t transpose_xy_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ common_hal_displayio_tilegrid_set_transpose_xy(self, mp_obj_is_true(transpose_xy_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_transpose_xy_obj, displayio_tilegrid_obj_set_transpose_xy);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_transpose_xy_obj,
+ (mp_obj_t)&displayio_tilegrid_get_transpose_xy_obj,
+ (mp_obj_t)&displayio_tilegrid_set_transpose_xy_obj);
+
+//| pixel_shader: Union[ColorConverter, Palette]
+//| """The pixel shader of the tilegrid."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return common_hal_displayio_tilegrid_get_pixel_shader(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_pixel_shader_obj, displayio_tilegrid_obj_get_pixel_shader);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ if (!mp_obj_is_type(pixel_shader, &displayio_palette_type) && !mp_obj_is_type(pixel_shader, &displayio_colorconverter_type)) {
+ mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter"));
+ }
+
+ common_hal_displayio_tilegrid_set_pixel_shader(self, pixel_shader);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_pixel_shader_obj, displayio_tilegrid_obj_set_pixel_shader);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_pixel_shader_obj,
+ (mp_obj_t)&displayio_tilegrid_get_pixel_shader_obj,
+ (mp_obj_t)&displayio_tilegrid_set_pixel_shader_obj);
+
+//| bitmap: Union[Bitmap,OnDiskBitmap,Shape]
+//| """The bitmap of the tilegrid."""
+//|
+STATIC mp_obj_t displayio_tilegrid_obj_get_bitmap(mp_obj_t self_in) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+ return common_hal_displayio_tilegrid_get_bitmap(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_bitmap_obj, displayio_tilegrid_obj_get_bitmap);
+
+STATIC mp_obj_t displayio_tilegrid_obj_set_bitmap(mp_obj_t self_in, mp_obj_t bitmap) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+ uint16_t new_bitmap_width;
+ uint16_t new_bitmap_height;
+ mp_obj_t native = mp_obj_cast_to_native_base(bitmap, &displayio_shape_type);
+ if (native != MP_OBJ_NULL) {
+ displayio_shape_t *bmp = MP_OBJ_TO_PTR(native);
+ new_bitmap_width = bmp->width;
+ new_bitmap_height = bmp->height;
+ } else if (mp_obj_is_type(bitmap, &displayio_bitmap_type)) {
+ displayio_bitmap_t *bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ new_bitmap_width = bmp->width;
+ new_bitmap_height = bmp->height;
+ } else if (mp_obj_is_type(bitmap, &displayio_ondiskbitmap_type)) {
+ displayio_ondiskbitmap_t *bmp = MP_OBJ_TO_PTR(bitmap);
+ native = bitmap;
+ new_bitmap_width = bmp->width;
+ new_bitmap_height = bmp->height;
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap);
+ }
+
+ mp_obj_t old_native = mp_obj_cast_to_native_base(self->bitmap, &displayio_shape_type);
+ if (old_native != MP_OBJ_NULL) {
+ displayio_shape_t *old_bmp = MP_OBJ_TO_PTR(old_native);
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ } else if (mp_obj_is_type(self->bitmap, &displayio_bitmap_type)) {
+ displayio_bitmap_t *old_bmp = MP_OBJ_TO_PTR(self->bitmap);
+ old_native = self->bitmap;
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ } else if (mp_obj_is_type(self->bitmap, &displayio_ondiskbitmap_type)) {
+ displayio_ondiskbitmap_t *old_bmp = MP_OBJ_TO_PTR(self->bitmap);
+ old_native = self->bitmap;
+ if (old_bmp->width != new_bitmap_width || old_bmp->height != new_bitmap_height) {
+ mp_raise_ValueError(translate("New bitmap must be same size as old bitmap"));
+ }
+ }
+
+ common_hal_displayio_tilegrid_set_bitmap(self, bitmap);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_bitmap_obj, displayio_tilegrid_obj_set_bitmap);
+
+MP_PROPERTY_GETSET(displayio_tilegrid_bitmap_obj,
+ (mp_obj_t)&displayio_tilegrid_get_bitmap_obj,
+ (mp_obj_t)&displayio_tilegrid_set_bitmap_obj);
+
+//| def __getitem__(self, index: Union[Tuple[int, int], int]) -> int:
+//| """Returns the tile index at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| print(grid[0])"""
+//| ...
+//|
+//| def __setitem__(self, index: Union[Tuple[int, int], int], value: int) -> None:
+//| """Sets the tile index at the given index. The index can either be an x,y tuple or an int equal
+//| to ``y * width + x``.
+//|
+//| This allows you to::
+//|
+//| grid[0] = 10
+//|
+//| or::
+//|
+//| grid[0,0] = 10"""
+//| ...
+//|
+STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value_obj) {
+ displayio_tilegrid_t *self = native_tilegrid(self_in);
+
+
+ if (mp_obj_is_type(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ uint16_t x = 0;
+ uint16_t y = 0;
+ if (mp_obj_is_small_int(index_obj)) {
+ mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj);
+ uint16_t width = common_hal_displayio_tilegrid_get_width(self);
+ x = i % width;
+ y = i / width;
+ } else {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(index_obj, 2, &items);
+ x = mp_obj_get_int(items[0]);
+ y = mp_obj_get_int(items[1]);
+ }
+ if (x >= common_hal_displayio_tilegrid_get_width(self) ||
+ y >= common_hal_displayio_tilegrid_get_height(self)) {
+ mp_raise_IndexError(translate("Tile index out of bounds"));
+ }
+
+ if (value_obj == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile(self, x, y));
+ } else if (value_obj == mp_const_none) {
+ return MP_OBJ_NULL; // op not supported
+ } else {
+ mp_int_t value = mp_obj_get_int(value_obj);
+ if (value < 0 || value > 255) {
+ mp_raise_ValueError(translate("Tile value out of bounds"));
+ }
+ common_hal_displayio_tilegrid_set_tile(self, x, y, value);
+ }
+ }
+ return mp_const_none;
+}
+
+STATIC const mp_rom_map_elem_t displayio_tilegrid_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_tilegrid_hidden_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_tilegrid_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_tilegrid_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_tilegrid_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_tilegrid_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tile_width), MP_ROM_PTR(&displayio_tilegrid_tile_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tile_height), MP_ROM_PTR(&displayio_tilegrid_tile_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&displayio_tilegrid_flip_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&displayio_tilegrid_flip_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_transpose_xy), MP_ROM_PTR(&displayio_tilegrid_transpose_xy_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_tilegrid_pixel_shader_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&displayio_tilegrid_bitmap_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_tilegrid_locals_dict, displayio_tilegrid_locals_dict_table);
+
+const mp_obj_type_t displayio_tilegrid_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_TileGrid,
+ .make_new = displayio_tilegrid_make_new,
+ .locals_dict = (mp_obj_dict_t *)&displayio_tilegrid_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = tilegrid_subscr,
+ ),
+};
diff --git a/circuitpython/shared-bindings/displayio/TileGrid.h b/circuitpython/shared-bindings/displayio/TileGrid.h
new file mode 100644
index 0000000..2c79412
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/TileGrid.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
+
+#include "shared-module/displayio/TileGrid.h"
+
+extern const mp_obj_type_t displayio_tilegrid_type;
+
+void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
+ uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
+ mp_obj_t pixel_shader, uint16_t width, uint16_t height,
+ uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
+
+bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t *self, bool hidden);
+mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x);
+mp_int_t common_hal_displayio_tilegrid_get_y(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_y(displayio_tilegrid_t *self, mp_int_t y);
+mp_obj_t common_hal_displayio_tilegrid_get_pixel_shader(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_pixel_shader(displayio_tilegrid_t *self, mp_obj_t pixel_shader);
+
+mp_obj_t common_hal_displayio_tilegrid_get_bitmap(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_bitmap(displayio_tilegrid_t *self, mp_obj_t bitmap);
+
+
+bool common_hal_displayio_tilegrid_get_flip_x(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_flip_x(displayio_tilegrid_t *self, bool flip_x);
+bool common_hal_displayio_tilegrid_get_flip_y(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_flip_y(displayio_tilegrid_t *self, bool flip_y);
+bool common_hal_displayio_tilegrid_get_transpose_xy(displayio_tilegrid_t *self);
+void common_hal_displayio_tilegrid_set_transpose_xy(displayio_tilegrid_t *self, bool transpose_xy);
+
+uint16_t common_hal_displayio_tilegrid_get_width(displayio_tilegrid_t *self);
+uint16_t common_hal_displayio_tilegrid_get_height(displayio_tilegrid_t *self);
+
+uint16_t common_hal_displayio_tilegrid_get_tile_width(displayio_tilegrid_t *self);
+uint16_t common_hal_displayio_tilegrid_get_tile_height(displayio_tilegrid_t *self);
+
+uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
+void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index);
+
+// Private API for scrolling the TileGrid.
+void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H
diff --git a/circuitpython/shared-bindings/displayio/__init__.c b/circuitpython/shared-bindings/displayio/__init__.c
new file mode 100644
index 0000000..2e52f12
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/__init__.c
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/displayio/__init__.h"
+#include "shared-bindings/displayio/Bitmap.h"
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/Display.h"
+#include "shared-bindings/displayio/EPaperDisplay.h"
+#include "shared-bindings/displayio/FourWire.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/displayio/I2CDisplay.h"
+#include "shared-bindings/displayio/OnDiskBitmap.h"
+#include "shared-bindings/displayio/Palette.h"
+#if CIRCUITPY_PARALLELDISPLAY
+#include "shared-bindings/paralleldisplay/ParallelBus.h"
+#endif
+#include "shared-bindings/displayio/Shape.h"
+#include "shared-bindings/displayio/TileGrid.h"
+
+//| """Native helpers for driving displays
+//|
+//| The `displayio` module contains classes to manage display output
+//| including synchronizing with refresh rates and partial updating.
+//|
+//| For more a more thorough explanation and guide for using `displayio`, please
+//| refer to `this Learn guide
+//| <https://learn.adafruit.com/circuitpython-display-support-using-displayio>`_.
+//| """
+//|
+
+//| import paralleldisplay
+
+//| def release_displays() -> None:
+//| """Releases any actively used displays so their busses and pins can be used again. This will also
+//| release the builtin display on boards that have one. You will need to reinitialize it yourself
+//| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing.
+//|
+//| Use this once in your code.py if you initialize a display. Place it right before the
+//| initialization so the display is active as long as possible."""
+//| ...
+//|
+STATIC mp_obj_t displayio_release_displays(void) {
+ common_hal_displayio_release_displays();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(displayio_release_displays_obj, displayio_release_displays);
+
+
+STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_displayio) },
+ { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) },
+ { MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) },
+ { MP_ROM_QSTR(MP_QSTR_Colorspace), MP_ROM_PTR(&displayio_colorspace_type) },
+ { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) },
+ { MP_ROM_QSTR(MP_QSTR_EPaperDisplay), MP_ROM_PTR(&displayio_epaperdisplay_type) },
+ { MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) },
+ { MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) },
+ { MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) },
+ { MP_ROM_QSTR(MP_QSTR_Shape), MP_ROM_PTR(&displayio_shape_type) },
+ { MP_ROM_QSTR(MP_QSTR_TileGrid), MP_ROM_PTR(&displayio_tilegrid_type) },
+
+ { MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2CDisplay), MP_ROM_PTR(&displayio_i2cdisplay_type) },
+ #if CIRCUITPY_PARALLELDISPLAY
+ { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&paralleldisplay_parallelbus_type) },
+ #endif
+
+ { MP_ROM_QSTR(MP_QSTR_release_displays), MP_ROM_PTR(&displayio_release_displays_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(displayio_module_globals, displayio_module_globals_table);
+
+const mp_obj_module_t displayio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&displayio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_displayio, displayio_module, CIRCUITPY_DISPLAYIO);
diff --git a/circuitpython/shared-bindings/displayio/__init__.h b/circuitpython/shared-bindings/displayio/__init__.h
new file mode 100644
index 0000000..b297e4d
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/__init__.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
+
+#include "py/enum.h"
+#include "py/obj.h"
+
+typedef enum {
+ DISPLAY_COMMAND,
+ DISPLAY_DATA
+} display_byte_type_t;
+
+typedef enum {
+ CHIP_SELECT_UNTOUCHED,
+ CHIP_SELECT_TOGGLE_EVERY_BYTE
+} display_chip_select_behavior_t;
+
+typedef enum displayio_colorspace {
+ DISPLAYIO_COLORSPACE_RGB888,
+ DISPLAYIO_COLORSPACE_RGB565,
+ DISPLAYIO_COLORSPACE_RGB555,
+ DISPLAYIO_COLORSPACE_RGB565_SWAPPED,
+ DISPLAYIO_COLORSPACE_RGB555_SWAPPED,
+ DISPLAYIO_COLORSPACE_BGR565,
+ DISPLAYIO_COLORSPACE_BGR555,
+ DISPLAYIO_COLORSPACE_BGR565_SWAPPED,
+ DISPLAYIO_COLORSPACE_BGR555_SWAPPED,
+ DISPLAYIO_COLORSPACE_L8,
+} displayio_colorspace_t;
+
+typedef bool (*display_bus_bus_reset)(mp_obj_t bus);
+typedef bool (*display_bus_bus_free)(mp_obj_t bus);
+typedef bool (*display_bus_begin_transaction)(mp_obj_t bus);
+typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type,
+ display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
+typedef void (*display_bus_end_transaction)(mp_obj_t bus);
+
+void common_hal_displayio_release_displays(void);
+
+extern const mp_obj_type_t displayio_colorspace_type;
+extern const cp_enum_obj_t displayio_colorspace_RGB888_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H
diff --git a/circuitpython/shared-bindings/displayio/area.c b/circuitpython/shared-bindings/displayio/area.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/displayio/area.c
diff --git a/circuitpython/shared-bindings/dualbank/__init__.c b/circuitpython/shared-bindings/dualbank/__init__.c
new file mode 100644
index 0000000..f907c91
--- /dev/null
+++ b/circuitpython/shared-bindings/dualbank/__init__.c
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/dualbank/__init__.h"
+
+//| """DUALBANK Module
+//|
+//| The `dualbank` module adds ability to update and switch
+//| between the two app partitions.
+//|
+//| There are two identical partitions, these contain different
+//| firmware versions.
+//| Having two partitions enables rollback functionality.
+//|
+//| The two partitions are defined as boot partition and
+//| next-update partition. Calling `dualbank.flash()` writes
+//| the next-update partition.
+//|
+//| After the next-update partition is written a validation
+//| check is performed and on a successful validation this
+//| partition is set as the boot partition. On next reset,
+//| firmware will be loaded from this partition.
+//|
+//| Here is the sequence of commands to follow:
+//|
+//| .. code-block:: python
+//|
+//| import dualbank
+//|
+//| dualbank.flash(buffer, offset)
+//| dualbank.switch()
+//| """
+//| ...
+//|
+
+//| def flash(*buffer: ReadableBuffer, offset: int=0) -> None:
+//| """Writes one of two app partitions at the given offset.
+//|
+//| This can be called multiple times when flashing the firmware
+//| in small chunks.
+//| """
+//| ...
+//|
+STATIC mp_obj_t dualbank_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_offset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_offset, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_offset].u_int < 0) {
+ mp_raise_ValueError(translate("offset must be >= 0"));
+ }
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ common_hal_dualbank_flash(bufinfo.buf, bufinfo.len, args[ARG_offset].u_int);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dualbank_flash_obj, 0, dualbank_flash);
+
+//| def switch() -> None:
+//| """Switches the boot partition.
+//|
+//| On next reset, firmware will be loaded from the partition
+//| just switched over to.
+//| """
+//| ...
+//|
+STATIC mp_obj_t dualbank_switch(void) {
+ common_hal_dualbank_switch();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(dualbank_switch_obj, dualbank_switch);
+
+STATIC const mp_rom_map_elem_t dualbank_module_globals_table[] = {
+ // module name
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_dualbank) },
+ // module functions
+ { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&dualbank_flash_obj) },
+ { MP_ROM_QSTR(MP_QSTR_switch), MP_ROM_PTR(&dualbank_switch_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(dualbank_module_globals, dualbank_module_globals_table);
+
+const mp_obj_module_t dualbank_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&dualbank_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_dualbank, dualbank_module, CIRCUITPY_DUALBANK);
diff --git a/circuitpython/shared-bindings/dualbank/__init__.h b/circuitpython/shared-bindings/dualbank/__init__.h
new file mode 100644
index 0000000..7edbc6d
--- /dev/null
+++ b/circuitpython/shared-bindings/dualbank/__init__.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 microDev
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DUALBANK___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DUALBANK___INIT___H
+
+#include "py/runtime.h"
+
+extern void common_hal_dualbank_switch(void);
+extern void common_hal_dualbank_flash(const void *buf, const size_t len, const size_t offset);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DUALBANK___INIT___H
diff --git a/circuitpython/shared-bindings/floppyio/__init__.c b/circuitpython/shared-bindings/floppyio/__init__.c
new file mode 100644
index 0000000..3ef58b2
--- /dev/null
+++ b/circuitpython/shared-bindings/floppyio/__init__.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/floppyio/__init__.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "common-hal/floppyio/__init__.h"
+
+#include <stdint.h>
+
+#include "py/binary.h"
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+//| def flux_readinto(buffer: WriteableBuffer, data: digitalio.DigitalInOut, index: digitalio.DigitalInOut) -> int:
+//| """Read flux transition information into the buffer.
+//|
+//| The function returns when the buffer has filled, or when the index input
+//| indicates that one full revolution of data has been recorded. Due to
+//| technical limitations, this process may not be interruptible by
+//| KeyboardInterrupt.
+//|
+//| :param buffer: Read data into this buffer. Each element represents the time between successive zero-to-one transitions.
+//| :param data: Pin on which the flux data appears
+//| :param index: Pin on which the index pulse appears
+//| :return: The actual number of bytes of read
+//| """
+//| ...
+//|
+STATIC mp_obj_t floppyio_flux_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_data, ARG_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+ digitalio_digitalinout_obj_t *data = assert_digitalinout(args[ARG_data].u_obj);
+ digitalio_digitalinout_obj_t *index = assert_digitalinout(args[ARG_index].u_obj);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_flux_readinto(bufinfo.buf, bufinfo.len, data, index));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(floppyio_flux_readinto_obj, 0, floppyio_flux_readinto);
+
+//| def mfm_readinto(buffer: WriteableBuffer, data: digitalio.DigitalInOut, index: digitalio.DigitalInOut) -> int:
+//| """Read mfm blocks into the buffer.
+//|
+//| The track is assumed to consist of 512-byte sectors.
+//|
+//| The function returns when all sectors have been successfully read, or
+//| a number of index pulses have occurred. Due to technical limitations, this
+//| process may not be interruptible by KeyboardInterrupt.
+//|
+//| :param buffer: Read data into this buffer. Must be a multiple of 512.
+//| :param data: Pin on which the mfm data appears
+//| :param index: Pin on which the index pulse appears
+//| :return: The actual number of sectors read
+//| """
+//| ...
+//|
+STATIC mp_obj_t floppyio_mfm_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_data, ARG_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_index, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+ digitalio_digitalinout_obj_t *data = assert_digitalinout(args[ARG_data].u_obj);
+ digitalio_digitalinout_obj_t *index = assert_digitalinout(args[ARG_index].u_obj);
+
+ if (bufinfo.len % 512 != 0) {
+ mp_raise_ValueError(translate("Buffer must be a multiple of 512 bytes"));
+ }
+ size_t n_sectors = bufinfo.len / 512;
+ return MP_OBJ_NEW_SMALL_INT(common_hal_floppyio_mfm_readinto(bufinfo.buf, n_sectors, data, index));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(floppyio_mfm_readinto_obj, 0, floppyio_mfm_readinto);
+
+//| samplerate: int
+//| """The approximate sample rate in Hz used by flux_readinto."""
+//|
+
+STATIC const mp_rom_map_elem_t floppyio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_floppyio) },
+ { MP_ROM_QSTR(MP_QSTR_flux_readinto), MP_ROM_PTR(&floppyio_flux_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mfm_readinto), MP_ROM_PTR(&floppyio_mfm_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_samplerate), MP_ROM_INT(FLOPPYIO_SAMPLERATE) },
+};
+STATIC MP_DEFINE_CONST_DICT(floppyio_module_globals, floppyio_module_globals_table);
+
+const mp_obj_module_t floppyio_module = {
+ .base = {&mp_type_module },
+ .globals = (mp_obj_dict_t *)&floppyio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_floppyio, floppyio_module, CIRCUITPY_FLOPPYIO);
diff --git a/circuitpython/shared-bindings/floppyio/__init__.h b/circuitpython/shared-bindings/floppyio/__init__.h
new file mode 100644
index 0000000..322bbe7
--- /dev/null
+++ b/circuitpython/shared-bindings/floppyio/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "common-hal/digitalio/DigitalInOut.h"
+
+int common_hal_floppyio_flux_readinto(void *buf, size_t len, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index);
+int common_hal_floppyio_mfm_readinto(void *buf, size_t n_sector, digitalio_digitalinout_obj_t *data, digitalio_digitalinout_obj_t *index);
diff --git a/circuitpython/shared-bindings/fontio/BuiltinFont.c b/circuitpython/shared-bindings/fontio/BuiltinFont.c
new file mode 100644
index 0000000..9c97d9a
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/BuiltinFont.c
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/fontio/BuiltinFont.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| from typing_extensions import Protocol # for compat with python < 3.8
+//|
+//| class FontProtocol(Protocol):
+//| """A protocol shared by `BuiltinFont` and classes in ``adafruit_bitmap_font``"""
+//| def get_bounding_box(self) -> Union[Tuple[int, int], Tuple[int, int, int, int]]:
+//| """Retrieve the maximum bounding box of any glyph in the font.
+//|
+//| The four element version is ``(width, height, x_offset, y_offset)``.
+//| The two element version is ``(width, height)``, in which
+//| ``x_offset`` and ``y_offset`` are assumed to be zero."""
+//| pass
+//|
+//| def get_glyph(self, codepoint: int) -> Optional[Glyph]:
+//| """Retrieve the Glyph for a given code point
+//|
+//| If the code point is not present in the font, `None` is returned."""
+//| pass
+//|
+
+//| class BuiltinFont:
+//| """A font built into CircuitPython"""
+//|
+//| def __init__(self) -> None:
+//| """Creation not supported. Available fonts are defined when CircuitPython is built. See the
+//| `Adafruit_CircuitPython_Bitmap_Font <https://github.com/adafruit/Adafruit_CircuitPython_Bitmap_Font>`_
+//| library for dynamically loaded fonts."""
+//| ...
+//|
+
+//| bitmap: displayio.Bitmap
+//| """Bitmap containing all font glyphs starting with ASCII and followed by unicode. Use
+//| `get_glyph` in most cases. This is useful for use with `displayio.TileGrid` and
+//| `terminalio.Terminal`."""
+//|
+STATIC mp_obj_t fontio_builtinfont_obj_get_bitmap(mp_obj_t self_in) {
+ fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_fontio_builtinfont_get_bitmap(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(fontio_builtinfont_get_bitmap_obj, fontio_builtinfont_obj_get_bitmap);
+
+MP_PROPERTY_GETTER(fontio_builtinfont_bitmap_obj,
+ (mp_obj_t)&fontio_builtinfont_get_bitmap_obj);
+
+//| def get_bounding_box(self) -> Tuple[int, int]:
+//| """Returns the maximum bounds of all glyphs in the font in a tuple of two values: width, height."""
+//| ...
+//|
+STATIC mp_obj_t fontio_builtinfont_obj_get_bounding_box(mp_obj_t self_in) {
+ fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_fontio_builtinfont_get_bounding_box(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(fontio_builtinfont_get_bounding_box_obj, fontio_builtinfont_obj_get_bounding_box);
+
+
+//| def get_glyph(self, codepoint: int) -> Glyph:
+//| """Returns a `fontio.Glyph` for the given codepoint or None if no glyph is available."""
+//| ...
+//|
+STATIC mp_obj_t fontio_builtinfont_obj_get_glyph(mp_obj_t self_in, mp_obj_t codepoint_obj) {
+ fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_int_t codepoint;
+ if (!mp_obj_get_int_maybe(codepoint_obj, &codepoint)) {
+ mp_raise_ValueError_varg(translate("%q should be an int"), MP_QSTR_codepoint);
+ }
+ return common_hal_fontio_builtinfont_get_glyph(self, codepoint);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(fontio_builtinfont_get_glyph_obj, fontio_builtinfont_obj_get_glyph);
+
+STATIC const mp_rom_map_elem_t fontio_builtinfont_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&fontio_builtinfont_bitmap_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_bounding_box), MP_ROM_PTR(&fontio_builtinfont_get_bounding_box_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_glyph), MP_ROM_PTR(&fontio_builtinfont_get_glyph_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(fontio_builtinfont_locals_dict, fontio_builtinfont_locals_dict_table);
+
+const mp_obj_type_t fontio_builtinfont_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_BuiltinFont,
+ .locals_dict = (mp_obj_dict_t *)&fontio_builtinfont_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/fontio/BuiltinFont.h b/circuitpython/shared-bindings/fontio/BuiltinFont.h
new file mode 100644
index 0000000..e87445e
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/BuiltinFont.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H
+
+#include "shared-module/fontio/BuiltinFont.h"
+
+extern const mp_obj_type_t fontio_builtinfont_type;
+
+mp_obj_t common_hal_fontio_builtinfont_get_bitmap(const fontio_builtinfont_t *self);
+mp_obj_t common_hal_fontio_builtinfont_get_bounding_box(const fontio_builtinfont_t *self);
+mp_obj_t common_hal_fontio_builtinfont_get_glyph(const fontio_builtinfont_t *self, mp_uint_t codepoint);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H
diff --git a/circuitpython/shared-bindings/fontio/Glyph.c b/circuitpython/shared-bindings/fontio/Glyph.c
new file mode 100644
index 0000000..92be6da
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/Glyph.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/fontio/Glyph.h"
+
+#include <stdint.h>
+
+//| class Glyph:
+//| """Storage of glyph info"""
+//|
+//| def __init__(self,
+//| bitmap: displayio.Bitmap,
+//| tile_index: int,
+//| width: int,
+//| height: int,
+//| dx: int,
+//| dy: int,
+//| shift_x: int,
+//| shift_y: int) -> None:
+//| """Named tuple used to capture a single glyph and its attributes.
+//|
+//| :param bitmap: the bitmap including the glyph
+//| :param tile_index: the tile index within the bitmap
+//| :param width: the width of the glyph's bitmap
+//| :param height: the height of the glyph's bitmap
+//| :param dx: x adjustment to the bitmap's position
+//| :param dy: y adjustment to the bitmap's position
+//| :param shift_x: the x difference to the next glyph
+//| :param shift_y: the y difference to the next glyph"""
+//| ...
+//|
+const mp_obj_namedtuple_type_t fontio_glyph_type = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .name = MP_QSTR_Glyph,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .print = namedtuple_print,
+ .make_new = namedtuple_make_new,
+ .parent = &mp_type_tuple,
+ .attr = namedtuple_attr,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ ),
+ },
+ .n_fields = 8,
+ .fields = {
+ MP_QSTR_bitmap,
+ MP_QSTR_tile_index,
+ MP_QSTR_width,
+ MP_QSTR_height,
+ MP_QSTR_dx,
+ MP_QSTR_dy,
+ MP_QSTR_shift_x,
+ MP_QSTR_shift_y
+ },
+};
diff --git a/circuitpython/shared-bindings/fontio/Glyph.h b/circuitpython/shared-bindings/fontio/Glyph.h
new file mode 100644
index 0000000..c58d812
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/Glyph.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H
+
+#include "py/objnamedtuple.h"
+
+extern const mp_obj_namedtuple_type_t fontio_glyph_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H
diff --git a/circuitpython/shared-bindings/fontio/__init__.c b/circuitpython/shared-bindings/fontio/__init__.c
new file mode 100644
index 0000000..ea1b8a6
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/__init__.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/fontio/__init__.h"
+#include "shared-bindings/fontio/BuiltinFont.h"
+#include "shared-bindings/fontio/Glyph.h"
+
+//| """Core font related data structures
+//|
+//| .. note:: This module is intended only for low-level usage. For working with
+//| fonts in CircuitPython see the `adafruit_bitmap_font library
+//| <https://github.com/adafruit/Adafruit_CircuitPython_Bitmap_Font>`_.
+//| For information on creating custom fonts for use in CircuitPython, see
+//| `this Learn guide <https://learn.adafruit.com/custom-fonts-for-pyportal-circuitpython-display>`_
+//|
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t fontio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fontio) },
+ { MP_ROM_QSTR(MP_QSTR_BuiltinFont), MP_ROM_PTR(&fontio_builtinfont_type) },
+ { MP_ROM_QSTR(MP_QSTR_Glyph), MP_ROM_PTR(&fontio_glyph_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(fontio_module_globals, fontio_module_globals_table);
+
+const mp_obj_module_t fontio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&fontio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_fontio, fontio_module, CIRCUITPY_DISPLAYIO && CIRCUITPY_TERMINALIO);
diff --git a/circuitpython/shared-bindings/fontio/__init__.h b/circuitpython/shared-bindings/fontio/__init__.h
new file mode 100644
index 0000000..2099197
--- /dev/null
+++ b/circuitpython/shared-bindings/fontio/__init__.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO___INIT___H
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO___INIT___H
diff --git a/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.c b/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.c
new file mode 100644
index 0000000..daff217
--- /dev/null
+++ b/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.c
@@ -0,0 +1,378 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/framebufferio/FramebufferDisplay.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "shared-bindings/displayio/Group.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class FramebufferDisplay:
+//| """Manage updating a display with framebuffer in RAM
+//|
+//| This initializes a display and connects it into CircuitPython. Unlike other
+//| objects in CircuitPython, Display objects live until `displayio.release_displays()`
+//| is called. This is done so that CircuitPython can use the display itself."""
+//|
+//| def __init__(self, framebuffer: circuitpython_typing.FrameBuffer, *, rotation: int = 0, auto_refresh: bool = True) -> None:
+//| """Create a Display object with the given framebuffer (a buffer, array, ulab.array, etc)
+//|
+//| :param ~circuitpython_typing.FrameBuffer framebuffer: The framebuffer that the display is connected to
+//| :param bool auto_refresh: Automatically refresh the screen
+//| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270)"""
+//| ...
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_framebuffer, ARG_rotation, ARG_auto_refresh, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_framebuffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ };
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
+
+ mp_int_t rotation = args[ARG_rotation].u_int;
+ if (rotation % 90 != 0) {
+ mp_raise_ValueError(translate("Display rotation must be in 90 degree increments"));
+ }
+
+ primary_display_t *disp = allocate_display_or_raise();
+ framebufferio_framebufferdisplay_obj_t *self = &disp->framebuffer_display;
+ self->base.type = &framebufferio_framebufferdisplay_type;
+ common_hal_framebufferio_framebufferdisplay_construct(
+ self,
+ framebuffer,
+ rotation,
+ args[ARG_auto_refresh].u_bool
+ );
+
+ return self;
+}
+
+// Helper to ensure we have the native super class instead of a subclass.
+static framebufferio_framebufferdisplay_obj_t *native_display(mp_obj_t display_obj) {
+ mp_obj_t native_display = mp_obj_cast_to_native_base(display_obj, &framebufferio_framebufferdisplay_type);
+ mp_obj_assert_native_inited(native_display);
+ return MP_OBJ_TO_PTR(native_display);
+}
+
+//| def show(self, group: displayio.Group) -> None:
+//| """Switches to displaying the given group of layers. When group is None, the default
+//| CircuitPython terminal will be shown.
+//|
+//| :param Group group: The group to show."""
+//| ...
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_show(mp_obj_t self_in, mp_obj_t group_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ displayio_group_t *group = NULL;
+ if (group_in != mp_const_none) {
+ group = MP_OBJ_TO_PTR(native_group(group_in));
+ }
+
+ bool ok = common_hal_framebufferio_framebufferdisplay_show(self, group);
+ if (!ok) {
+ mp_raise_ValueError(translate("Group already used"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(framebufferio_framebufferdisplay_show_obj, framebufferio_framebufferdisplay_obj_show);
+
+//| def refresh(self, *, target_frames_per_second: int = 60, minimum_frames_per_second: int = 1) -> bool:
+//| """When auto refresh is off, waits for the target frame rate and then refreshes the display,
+//| returning True. If the call has taken too long since the last refresh call for the given
+//| target frame rate, then the refresh returns False immediately without updating the screen to
+//| hopefully help getting caught up.
+//|
+//| If the time since the last successful refresh is below the minimum frame rate, then an
+//| exception will be raised. Set minimum_frames_per_second to 0 to disable.
+//|
+//| When auto refresh is on, updates the display immediately. (The display will also update
+//| without calls to this.)
+//|
+//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated.
+//| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second."""
+//| ...
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} },
+ { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ framebufferio_framebufferdisplay_obj_t *self = native_display(pos_args[0]);
+ uint32_t maximum_ms_per_real_frame = 0xffffffff;
+ mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int;
+ if (minimum_frames_per_second > 0) {
+ maximum_ms_per_real_frame = 1000 / minimum_frames_per_second;
+ }
+ return mp_obj_new_bool(common_hal_framebufferio_framebufferdisplay_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(framebufferio_framebufferdisplay_refresh_obj, 1, framebufferio_framebufferdisplay_obj_refresh);
+
+//| auto_refresh: bool
+//| """True when the display is refreshed automatically."""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_auto_refresh(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_framebufferio_framebufferdisplay_get_auto_refresh(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_auto_refresh_obj, framebufferio_framebufferdisplay_obj_get_auto_refresh);
+
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+
+ common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, mp_obj_is_true(auto_refresh));
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(framebufferio_framebufferdisplay_set_auto_refresh_obj, framebufferio_framebufferdisplay_obj_set_auto_refresh);
+
+MP_PROPERTY_GETSET(framebufferio_framebufferdisplay_auto_refresh_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_auto_refresh_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_set_auto_refresh_obj);
+
+//| brightness: float
+//| """The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When
+//| `auto_brightness` is True, the value of `brightness` will change automatically.
+//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False."""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_brightness(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ mp_float_t brightness = common_hal_framebufferio_framebufferdisplay_get_brightness(self);
+ if (brightness < 0) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_obj_new_float(brightness);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_brightness_obj, framebufferio_framebufferdisplay_obj_get_brightness);
+
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ common_hal_framebufferio_framebufferdisplay_set_auto_brightness(self, false);
+ mp_float_t brightness = mp_obj_get_float(brightness_obj);
+ if (brightness < 0.0f || brightness > 1.0f) {
+ mp_raise_ValueError(translate("Brightness must be 0-1.0"));
+ }
+ bool ok = common_hal_framebufferio_framebufferdisplay_set_brightness(self, brightness);
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(framebufferio_framebufferdisplay_set_brightness_obj, framebufferio_framebufferdisplay_obj_set_brightness);
+
+MP_PROPERTY_GETSET(framebufferio_framebufferdisplay_brightness_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_brightness_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_set_brightness_obj);
+
+//| auto_brightness: bool
+//| """True when the display brightness is adjusted automatically, based on an ambient
+//| light sensor or other method. Note that some displays may have this set to True by default,
+//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False
+//| if `brightness` is set manually."""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_auto_brightness(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return mp_obj_new_bool(common_hal_framebufferio_framebufferdisplay_get_auto_brightness(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_auto_brightness_obj, framebufferio_framebufferdisplay_obj_get_auto_brightness);
+
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+
+ bool ok = common_hal_framebufferio_framebufferdisplay_set_auto_brightness(self, mp_obj_is_true(auto_brightness));
+ if (!ok) {
+ mp_raise_RuntimeError(translate("Brightness not adjustable"));
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(framebufferio_framebufferdisplay_set_auto_brightness_obj, framebufferio_framebufferdisplay_obj_set_auto_brightness);
+
+MP_PROPERTY_GETSET(framebufferio_framebufferdisplay_auto_brightness_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_auto_brightness_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_set_auto_brightness_obj);
+
+//| width: int
+//| """Gets the width of the framebuffer"""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_width(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_framebufferio_framebufferdisplay_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_width_obj, framebufferio_framebufferdisplay_obj_get_width);
+
+MP_PROPERTY_GETTER(framebufferio_framebufferdisplay_width_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_width_obj);
+
+//| height: int
+//| """Gets the height of the framebuffer"""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_height(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_framebufferio_framebufferdisplay_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_height_obj, framebufferio_framebufferdisplay_obj_get_height);
+
+MP_PROPERTY_GETTER(framebufferio_framebufferdisplay_height_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_height_obj);
+
+//| rotation: int
+//| """The rotation of the display as an int in degrees."""
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_rotation(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_framebufferio_framebufferdisplay_get_rotation(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_rotation_obj, framebufferio_framebufferdisplay_obj_get_rotation);
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ common_hal_framebufferio_framebufferdisplay_set_rotation(self, mp_obj_get_int(value));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(framebufferio_framebufferdisplay_set_rotation_obj, framebufferio_framebufferdisplay_obj_set_rotation);
+
+
+MP_PROPERTY_GETSET(framebufferio_framebufferdisplay_rotation_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_rotation_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_set_rotation_obj);
+
+//| framebuffer: circuitpython_typing.FrameBuffer
+//| """The framebuffer being used by the display"""
+//|
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_get_framebuffer(mp_obj_t self_in) {
+ framebufferio_framebufferdisplay_obj_t *self = native_display(self_in);
+ return common_hal_framebufferio_framebufferdisplay_get_framebuffer(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(framebufferio_framebufferdisplay_get_framebuffer_obj, framebufferio_framebufferdisplay_obj_get_framebuffer);
+
+MP_PROPERTY_GETTER(framebufferio_framebufferframebuffer_obj,
+ (mp_obj_t)&framebufferio_framebufferdisplay_get_framebuffer_obj);
+
+
+//| def fill_row(self, y: int, buffer: WriteableBuffer) -> WriteableBuffer:
+//| """Extract the pixels from a single row
+//|
+//| :param int y: The top edge of the area
+//| :param ~circuitpython_typing.WriteableBuffer buffer: The buffer in which to place the pixel data"""
+//| ...
+//|
+STATIC mp_obj_t framebufferio_framebufferdisplay_obj_fill_row(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_y, ARG_buffer };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = -1} },
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ framebufferio_framebufferdisplay_obj_t *self = native_display(pos_args[0]);
+ mp_int_t y = args[ARG_y].u_int;
+ mp_obj_t *result = args[ARG_buffer].u_obj;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(result, &bufinfo, MP_BUFFER_WRITE);
+
+ if (bufinfo.typecode != BYTEARRAY_TYPECODE) {
+ mp_raise_ValueError(translate("Buffer is not a bytearray."));
+ }
+ if (self->core.colorspace.depth != 16) {
+ mp_raise_ValueError(translate("Display must have a 16 bit colorspace."));
+ }
+
+ displayio_area_t area = {
+ .x1 = 0,
+ .y1 = y,
+ .x2 = self->core.width,
+ .y2 = y + 1
+ };
+ uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth;
+ uint16_t buffer_size = self->core.width / pixels_per_word;
+ uint16_t pixels_per_buffer = displayio_area_size(&area);
+ if (pixels_per_buffer % pixels_per_word) {
+ buffer_size += 1;
+ }
+
+ uint32_t *result_buffer = bufinfo.buf;
+ size_t result_buffer_size = bufinfo.len;
+
+ if (result_buffer_size >= (buffer_size * 4)) {
+ volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1;
+ uint32_t mask[mask_length];
+
+ for (uint16_t k = 0; k < mask_length; k++) {
+ mask[k] = 0x00000000;
+ }
+
+ displayio_display_core_fill_area(&self->core, &area, mask, result_buffer);
+ return result;
+ } else {
+ mp_raise_ValueError(translate("Buffer is too small"));
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(framebufferio_framebufferdisplay_fill_row_obj, 1, framebufferio_framebufferdisplay_obj_fill_row);
+
+STATIC const mp_rom_map_elem_t framebufferio_framebufferdisplay_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&framebufferio_framebufferdisplay_show_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&framebufferio_framebufferdisplay_refresh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&framebufferio_framebufferdisplay_fill_row_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&framebufferio_framebufferdisplay_auto_refresh_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&framebufferio_framebufferdisplay_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&framebufferio_framebufferdisplay_auto_brightness_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&framebufferio_framebufferdisplay_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&framebufferio_framebufferdisplay_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&framebufferio_framebufferdisplay_rotation_obj) },
+ { MP_ROM_QSTR(MP_QSTR_framebuffer), MP_ROM_PTR(&framebufferio_framebufferframebuffer_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(framebufferio_framebufferdisplay_locals_dict, framebufferio_framebufferdisplay_locals_dict_table);
+
+const mp_obj_type_t framebufferio_framebufferdisplay_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_FramebufferDisplay,
+ .make_new = framebufferio_framebufferdisplay_make_new,
+ .locals_dict = (mp_obj_dict_t *)&framebufferio_framebufferdisplay_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.h b/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.h
new file mode 100644
index 0000000..f96b47e
--- /dev/null
+++ b/circuitpython/shared-bindings/framebufferio/FramebufferDisplay.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_FRAMEBUFFERDISPLAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_FRAMEBUFFERDISPLAY_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#include "shared-module/framebufferio/FramebufferDisplay.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t framebufferio_framebufferdisplay_type;
+
+#define NO_BRIGHTNESS_COMMAND 0x100
+
+void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t *self,
+ mp_obj_t framebuffer,
+ uint16_t rotation,
+ bool auto_refresh);
+
+bool common_hal_framebufferio_framebufferdisplay_show(framebufferio_framebufferdisplay_obj_t *self,
+ displayio_group_t *root_group);
+
+bool common_hal_framebufferio_framebufferdisplay_refresh(framebufferio_framebufferdisplay_obj_t *self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame);
+
+bool common_hal_framebufferio_framebufferdisplay_get_auto_refresh(framebufferio_framebufferdisplay_obj_t *self);
+void common_hal_framebufferio_framebufferdisplay_set_auto_refresh(framebufferio_framebufferdisplay_obj_t *self, bool auto_refresh);
+
+uint16_t common_hal_framebufferio_framebufferdisplay_get_width(framebufferio_framebufferdisplay_obj_t *self);
+uint16_t common_hal_framebufferio_framebufferdisplay_get_height(framebufferio_framebufferdisplay_obj_t *self);
+uint16_t common_hal_framebufferio_framebufferdisplay_get_rotation(framebufferio_framebufferdisplay_obj_t *self);
+void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t *self, int rotation);
+
+bool common_hal_framebufferio_framebufferdisplay_get_auto_brightness(framebufferio_framebufferdisplay_obj_t *self);
+bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebufferio_framebufferdisplay_obj_t *self, bool auto_brightness);
+
+mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t *self);
+bool common_hal_framebufferio_framebufferdisplay_set_brightness(framebufferio_framebufferdisplay_obj_t *self, mp_float_t brightness);
+
+mp_obj_t common_hal_framebufferio_framebufferdisplay_framebuffer(framebufferio_framebufferdisplay_obj_t *self);
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_FRAMEBUFFERDISPLAY_H
diff --git a/circuitpython/shared-bindings/framebufferio/__init__.c b/circuitpython/shared-bindings/framebufferio/__init__.c
new file mode 100644
index 0000000..5d95ef4
--- /dev/null
+++ b/circuitpython/shared-bindings/framebufferio/__init__.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "shared-bindings/framebufferio/__init__.h"
+#include "shared-bindings/framebufferio/FramebufferDisplay.h"
+
+//| """Native framebuffer display driving
+//|
+//| The `framebufferio` module contains classes to manage display output
+//| including synchronizing with refresh rates and partial updating.
+//| It is used in conjunction with classes from `displayio` to actually
+//| place items on the display; and classes like `RGBMatrix` to actually
+//| drive the display."""
+//|
+
+#if CIRCUITPY_FRAMEBUFFERIO
+static const mp_rom_map_elem_t framebufferio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebufferio) },
+ { MP_ROM_QSTR(MP_QSTR_FramebufferDisplay), MP_ROM_PTR(&framebufferio_framebufferdisplay_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(framebufferio_module_globals, framebufferio_module_globals_table);
+
+const mp_obj_module_t framebufferio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&framebufferio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_framebufferio, framebufferio_module, CIRCUITPY_FRAMEBUFFERIO);
+#endif
diff --git a/circuitpython/shared-bindings/framebufferio/__init__.h b/circuitpython/shared-bindings/framebufferio/__init__.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/framebufferio/__init__.h
diff --git a/circuitpython/shared-bindings/frequencyio/FrequencyIn.c b/circuitpython/shared-bindings/frequencyio/FrequencyIn.c
new file mode 100644
index 0000000..2f6ebd0
--- /dev/null
+++ b/circuitpython/shared-bindings/frequencyio/FrequencyIn.c
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Michael Schroeder
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/frequencyio/FrequencyIn.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class FrequencyIn:
+//| """Read a frequency signal
+//|
+//| FrequencyIn is used to measure the frequency, in hertz, of a digital signal
+//| on an incoming pin. Accuracy has shown to be within 10%, if not better. It
+//| is recommended to utilize an average of multiple samples to smooth out readings.
+//|
+//| Frequencies below 1KHz are not currently detectable.
+//|
+//| FrequencyIn will not determine pulse width (use ``PulseIn``)."""
+//|
+//| def __init__(self, pin: microcontroller.Pin, capture_period: int = 10) -> None:
+//| """Create a FrequencyIn object associated with the given pin.
+//|
+//| :param ~microcontroller.Pin pin: Pin to read frequency from.
+//| :param int capture_period: Keyword argument to set the measurement period, in
+//| milliseconds. Default is 10ms; range is 1ms - 500ms.
+//|
+//| Read the incoming frequency from a pin::
+//|
+//| import frequencyio
+//| import board
+//|
+//| frequency = frequencyio.FrequencyIn(board.D11)
+//|
+//| # Loop while printing the detected frequency
+//| while True:
+//| print(frequency.value)
+//|
+//| # Optional clear() will reset the value
+//| # to zero. Without this, if the incoming
+//| # signal stops, the last reading will remain
+//| # as the value.
+//| frequency.clear()"""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, true);
+
+ frequencyio_frequencyin_obj_t *self = m_new_obj(frequencyio_frequencyin_obj_t);
+ self->base.type = &frequencyio_frequencyin_type;
+ enum { ARG_pin, ARG_capture_period };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_capture_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 10} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+
+ const uint16_t capture_period = args[ARG_capture_period].u_int;
+
+ common_hal_frequencyio_frequencyin_construct(self, pin, capture_period);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the FrequencyIn and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_deinit(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_frequencyio_frequencyin_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_deinit_obj, frequencyio_frequencyin_deinit);
+
+STATIC void check_for_deinit(frequencyio_frequencyin_obj_t *self) {
+ if (common_hal_frequencyio_frequencyin_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> FrequencyIn:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_frequencyio_frequencyin_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(frequencyio_frequencyin___exit___obj, 4, 4, frequencyio_frequencyin_obj___exit__);
+
+//| def pause(self) -> None:
+//| """Pause frequency capture."""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_obj_pause(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_frequencyio_frequencyin_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_pause_obj, frequencyio_frequencyin_obj_pause);
+
+//| def resume(self) -> None:
+//| """Resumes frequency capture."""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_obj_resume(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_frequencyio_frequencyin_resume(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_resume_obj, frequencyio_frequencyin_obj_resume);
+
+//| def clear(self) -> None:
+//| """Clears the last detected frequency capture value."""
+//| ...
+//|
+
+STATIC mp_obj_t frequencyio_frequencyin_obj_clear(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_frequencyio_frequencyin_clear(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_clear_obj, frequencyio_frequencyin_obj_clear);
+
+//| capture_period: int
+//| """The capture measurement period. Lower incoming frequencies will be measured
+//| more accurately with longer capture periods. Higher frequencies are more
+//| accurate with shorter capture periods.
+//|
+//| .. note:: When setting a new ``capture_period``, all previous capture information is
+//| cleared with a call to ``clear()``."""
+//|
+STATIC mp_obj_t frequencyio_frequencyin_obj_get_capture_period(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_frequencyio_frequencyin_get_capture_period(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequency_get_capture_period_obj, frequencyio_frequencyin_obj_get_capture_period);
+
+STATIC mp_obj_t frequencyio_frequencyin_obj_set_capture_period(mp_obj_t self_in, mp_obj_t capture_period) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_frequencyio_frequencyin_set_capture_period(self, mp_obj_get_int(capture_period));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(frequencyio_frequency_set_capture_period_obj, frequencyio_frequencyin_obj_set_capture_period);
+
+MP_PROPERTY_GETSET(frequencyio_frequencyin_capture_period_obj,
+ (mp_obj_t)&frequencyio_frequency_get_capture_period_obj,
+ (mp_obj_t)&frequencyio_frequency_set_capture_period_obj);
+
+//| def __get__(self, index: int) -> int:
+//| """Returns the value of the last frequency captured."""
+//| ...
+//|
+STATIC mp_obj_t frequencyio_frequencyin_obj_get_value(mp_obj_t self_in) {
+ frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ // return MP_OBJ_NEW_SMALL_INT(common_hal_frequencyio_frequencyin_get_item(self));
+ return mp_obj_new_int_from_float(common_hal_frequencyio_frequencyin_get_item(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_get_value_obj, frequencyio_frequencyin_obj_get_value);
+
+MP_PROPERTY_GETTER(frequencyio_frequencyin_value_obj,
+ (mp_obj_t)&frequencyio_frequencyin_get_value_obj);
+
+STATIC const mp_rom_map_elem_t frequencyio_frequencyin_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&frequencyio_frequencyin_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&frequencyio_frequencyin___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&frequencyio_frequencyin_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&frequencyio_frequencyin_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&frequencyio_frequencyin_resume_obj) },
+ { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&frequencyio_frequencyin_clear_obj) },
+ { MP_ROM_QSTR(MP_QSTR_capture_period), MP_ROM_PTR(&frequencyio_frequencyin_capture_period_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(frequencyio_frequencyin_locals_dict, frequencyio_frequencyin_locals_dict_table);
+
+const mp_obj_type_t frequencyio_frequencyin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_frequencyin,
+ .make_new = frequencyio_frequencyin_make_new,
+ .locals_dict = (mp_obj_dict_t *)&frequencyio_frequencyin_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/frequencyio/FrequencyIn.h b/circuitpython/shared-bindings/frequencyio/FrequencyIn.h
new file mode 100644
index 0000000..dba6c3a
--- /dev/null
+++ b/circuitpython/shared-bindings/frequencyio/FrequencyIn.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Michael Schroeder
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO_FREQUENCYIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO_FREQUENCYIN_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/frequencyio/FrequencyIn.h"
+
+extern const mp_obj_type_t frequencyio_frequencyin_type;
+
+extern void common_hal_frequencyio_frequencyin_construct(frequencyio_frequencyin_obj_t *self,
+ const mcu_pin_obj_t *pin, uint16_t capture_period);
+extern void common_hal_frequencyio_frequencyin_deinit(frequencyio_frequencyin_obj_t *self);
+extern bool common_hal_frequencyio_frequencyin_deinited(frequencyio_frequencyin_obj_t *self);
+extern void common_hal_frequencyio_frequencyin_pause(frequencyio_frequencyin_obj_t *self);
+extern void common_hal_frequencyio_frequencyin_resume(frequencyio_frequencyin_obj_t *self);
+extern void common_hal_frequencyio_frequencyin_clear(frequencyio_frequencyin_obj_t *self);
+extern uint32_t common_hal_frequencyio_frequencyin_get_item(frequencyio_frequencyin_obj_t *self);
+extern uint16_t common_hal_frequencyio_frequencyin_get_capture_period(frequencyio_frequencyin_obj_t *self);
+extern void common_hal_frequencyio_frequencyin_set_capture_period(frequencyio_frequencyin_obj_t *self, uint16_t capture_period);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO_FREQUENCYIN_H
diff --git a/circuitpython/shared-bindings/frequencyio/__init__.c b/circuitpython/shared-bindings/frequencyio/__init__.c
new file mode 100644
index 0000000..ffbb7af
--- /dev/null
+++ b/circuitpython/shared-bindings/frequencyio/__init__.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Michael Schroeder
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/frequencyio/__init__.h"
+#include "shared-bindings/frequencyio/FrequencyIn.h"
+
+//| """Support for frequency based protocols
+//|
+//| .. warning:: This module is not available in SAMD21 builds. See the
+//| :ref:`module-support-matrix` for more info.
+//|
+
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import time
+//| import frequencyio
+//| import board
+//|
+//| frequency = frequencyio.FrequencyIn(board.D11)
+//| frequency.capture_period = 15
+//| time.sleep(0.1)
+//|
+//| This example will initialize the the device, set
+//| :py:data:`~frequencyio.FrequencyIn.capture_period`, and then sleep 0.1 seconds.
+//| CircuitPython will automatically turn off FrequencyIn capture when it resets all
+//| hardware after program completion. Use ``deinit()`` or a ``with`` statement
+//| to do it yourself."""
+//|
+
+STATIC const mp_rom_map_elem_t frequencyio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_frequencyio) },
+ { MP_ROM_QSTR(MP_QSTR_FrequencyIn), MP_ROM_PTR(&frequencyio_frequencyin_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(frequencyio_module_globals, frequencyio_module_globals_table);
+
+const mp_obj_module_t frequencyio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&frequencyio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_frequencyio, frequencyio_module, CIRCUITPY_FREQUENCYIO);
diff --git a/circuitpython/shared-bindings/frequencyio/__init__.h b/circuitpython/shared-bindings/frequencyio/__init__.h
new file mode 100644
index 0000000..3915765
--- /dev/null
+++ b/circuitpython/shared-bindings/frequencyio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Michael Schroeder
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FREQUENCYIO___INIT___H
diff --git a/circuitpython/shared-bindings/gamepadshift/GamePadShift.c b/circuitpython/shared-bindings/gamepadshift/GamePadShift.c
new file mode 100644
index 0000000..1c43eea
--- /dev/null
+++ b/circuitpython/shared-bindings/gamepadshift/GamePadShift.c
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/gc.h"
+#include "py/mpstate.h"
+#include "shared-bindings/gamepadshift/GamePadShift.h"
+#include "shared-bindings/gamepadshift/__init__.h"
+#include "supervisor/shared/translate.h"
+#include "supervisor/shared/tick.h"
+
+//| class GamePadShift:
+//| """Scan buttons for presses through a shift register"""
+//|
+//| def __init__(self, clock: digitalio.DigitalInOut, data: digitalio.DigitalInOut, latch: digitalio.DigitalInOut) -> None:
+//| """Initializes button scanning routines.
+//|
+//| The ``clock``, ``data`` and ``latch`` parameters are ``DigitalInOut``
+//| objects connected to the shift register controlling the buttons.
+//|
+//| The button presses are accumulated, until the ``get_pressed`` method
+//| is called, at which point the button state is cleared, and the new
+//| button presses start to be recorded.
+//|
+//| Only one `gamepadshift.GamePadShift` may be used at a time."""
+//| ...
+//|
+STATIC mp_obj_t gamepadshift_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_args) {
+
+ enum { ARG_clock, ARG_data, ARG_latch };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ},
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_latch, MP_ARG_REQUIRED | MP_ARG_OBJ},
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args),
+ allowed_args, args);
+
+ digitalio_digitalinout_obj_t *clock_pin = assert_digitalinout(args[ARG_clock].u_obj);
+ digitalio_digitalinout_obj_t *data_pin = assert_digitalinout(args[ARG_data].u_obj);
+ digitalio_digitalinout_obj_t *latch_pin = assert_digitalinout(args[ARG_latch].u_obj);
+
+ gamepadshift_obj_t *gamepad_singleton = MP_STATE_VM(gamepad_singleton);
+ if (!gamepad_singleton ||
+ !mp_obj_is_type(MP_OBJ_FROM_PTR(gamepad_singleton),
+ &gamepadshift_type)) {
+ gamepad_singleton = m_new_ll_obj(gamepadshift_obj_t);
+ gamepad_singleton->base.type = &gamepadshift_type;
+ if (!MP_STATE_VM(gamepad_singleton)) {
+ supervisor_enable_tick();
+ }
+ MP_STATE_VM(gamepad_singleton) = gamepad_singleton;
+ }
+ common_hal_gamepadshift_gamepadshift_init(gamepad_singleton, clock_pin, data_pin, latch_pin);
+ return MP_OBJ_FROM_PTR(gamepad_singleton);
+}
+
+//| def get_pressed(self) -> int:
+//| """Get the status of buttons pressed since the last call and clear it.
+//|
+//| Returns an 8-bit number, with bits that correspond to buttons,
+//| which have been pressed (or held down) since the last call to this
+//| function set to 1, and the remaining bits set to 0. Then it clears
+//| the button state, so that new button presses (or buttons that are
+//| held down) can be recorded for the next call."""
+//| ...
+//|
+STATIC mp_obj_t gamepadshift_get_pressed(mp_obj_t self_in) {
+ gamepadshift_obj_t *gamepad_singleton = MP_STATE_VM(gamepad_singleton);
+ mp_obj_t pressed = MP_OBJ_NEW_SMALL_INT(gamepad_singleton->pressed);
+ gamepad_singleton->pressed = gamepad_singleton->last;
+ return pressed;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gamepadshift_get_pressed_obj, gamepadshift_get_pressed);
+
+//| def deinit(self) -> None:
+//| """Disable button scanning."""
+//| ...
+//|
+STATIC mp_obj_t gamepadshift_deinit(mp_obj_t self_in) {
+ common_hal_gamepadshift_gamepadshift_deinit(self_in);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gamepadshift_deinit_obj, gamepadshift_deinit);
+
+
+STATIC const mp_rom_map_elem_t gamepadshift_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR_get_pressed), MP_ROM_PTR(&gamepadshift_get_pressed_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gamepadshift_deinit_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(gamepadshift_locals_dict, gamepadshift_locals_dict_table);
+const mp_obj_type_t gamepadshift_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_GamePadShift,
+ .make_new = gamepadshift_make_new,
+ .locals_dict = (mp_obj_dict_t *)&gamepadshift_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/gamepadshift/GamePadShift.h b/circuitpython/shared-bindings/gamepadshift/GamePadShift.h
new file mode 100644
index 0000000..8856e13
--- /dev/null
+++ b/circuitpython/shared-bindings/gamepadshift/GamePadShift.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT_GAMEPADSHIFT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT_GAMEPADSHIFT_H
+
+#include "shared-module/gamepadshift/GamePadShift.h"
+
+extern const mp_obj_type_t gamepadshift_type;
+
+void common_hal_gamepadshift_gamepadshift_init(gamepadshift_obj_t *gamepadshift,
+ digitalio_digitalinout_obj_t *clock_pin,
+ digitalio_digitalinout_obj_t *data_pin,
+ digitalio_digitalinout_obj_t *latch_pin);
+
+void common_hal_gamepadshift_gamepadshift_deinit(gamepadshift_obj_t *gamepadshift);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT_GAMEPADSHIFT_H
diff --git a/circuitpython/shared-bindings/gamepadshift/__init__.c b/circuitpython/shared-bindings/gamepadshift/__init__.c
new file mode 100644
index 0000000..816fd8d
--- /dev/null
+++ b/circuitpython/shared-bindings/gamepadshift/__init__.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared-bindings/gamepadshift/GamePadShift.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/util.h"
+
+//| """Tracks button presses read through a shift register.
+//|
+//| .. note:: `gamepadshift` is deprecated in CircuitPython 7.0.0 and will be removed in 8.0.0.
+//| Use `keypad` instead.
+//| """
+//|
+STATIC const mp_rom_map_elem_t gamepadshift_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gamepadshift) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GamePadShift), MP_ROM_PTR(&gamepadshift_type)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(gamepadshift_module_globals, gamepadshift_module_globals_table);
+
+const mp_obj_module_t gamepadshift_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&gamepadshift_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_gamepadshift, gamepadshift_module, CIRCUITPY_GAMEPADSHIFT);
diff --git a/circuitpython/shared-bindings/gamepadshift/__init__.h b/circuitpython/shared-bindings/gamepadshift/__init__.h
new file mode 100644
index 0000000..4b4be75
--- /dev/null
+++ b/circuitpython/shared-bindings/gamepadshift/__init__.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Radomir Dopieralski for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H
diff --git a/circuitpython/shared-bindings/getpass/__init__.c b/circuitpython/shared-bindings/getpass/__init__.c
new file mode 100644
index 0000000..7c2de89
--- /dev/null
+++ b/circuitpython/shared-bindings/getpass/__init__.c
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/stream.h"
+#include "shared-module/getpass/__init__.h"
+
+//| """Getpass Module
+//|
+//| This module provides a way to get input from user without echoing it.
+//|
+//| """
+//| ...
+//|
+
+//| def getpass(prompt: Optional[str] = 'Password: ', stream: Optional[io.FileIO] = None) -> str:
+//|
+//| """Prompt the user without echoing.
+//|
+//| :param str prompt: The user is prompted using the string ``prompt``, which defaults to ``'Password: '``.
+//| :param io.FileIO stream: The ``prompt`` is written to the file-like object ``stream`` if provided.
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t getpass_getpass(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_prompt, ARG_stream };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_prompt, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_stream, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *prompt = (args[ARG_prompt].u_obj == mp_const_none) ? "Password: " : mp_obj_str_get_str(args[ARG_prompt].u_obj);
+
+ mp_print_t print = {.data = NULL};
+ if (args[ARG_stream].u_obj != mp_const_none) {
+ #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
+ mp_get_stream_raise(args[ARG_stream].u_obj, MP_STREAM_OP_WRITE);
+ print.data = MP_OBJ_TO_PTR(args[ARG_stream].u_obj);
+ print.print_strn = mp_stream_write_adaptor;
+ #else
+ mp_raise_NotImplementedError(translate("stream operation not supported"));
+ #endif
+ }
+
+ return shared_module_getpass_getpass(prompt, ((print.data) ? &print : NULL));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(getpass_getpass_obj, 0, getpass_getpass);
+
+STATIC const mp_rom_map_elem_t getpass_module_globals_table[] = {
+ // module name
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_getpass) },
+ // module functions
+ { MP_ROM_QSTR(MP_QSTR_getpass), MP_ROM_PTR(&getpass_getpass_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(getpass_module_globals, getpass_module_globals_table);
+
+const mp_obj_module_t getpass_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&getpass_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_getpass, getpass_module, CIRCUITPY_GETPASS);
diff --git a/circuitpython/shared-bindings/gifio/GifWriter.c b/circuitpython/shared-bindings/gifio/GifWriter.c
new file mode 100644
index 0000000..11dd43b
--- /dev/null
+++ b/circuitpython/shared-bindings/gifio/GifWriter.c
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#if MICROPY_VFS
+#include "extmod/vfs.h"
+#endif
+#include "py/runtime.h"
+#include "shared-bindings/gifio/GifWriter.h"
+#include "shared-module/gifio/GifWriter.h"
+#include "shared/runtime/context_manager_helpers.h"
+
+//| class GifWriter:
+//| def __init__(self, file: Union[typing.BinaryIO, str], width:int, height:int, colorspace: displayio.Colorspace, loop:bool=True, dither:bool=False) -> None:
+//| """Construct a GifWriter object
+//|
+//| :param file: Either a file open in bytes mode, or the name of a file to open in bytes mode.
+//| :param width: The width of the image. All frames must have the same width.
+//| :param height: The height of the image. All frames must have the same height.
+//| :param colorspace: The colorspace of the image. All frames must have the same colorspace. The supported colorspaces are ``RGB565``, ``BGR565``, ``RGB565_SWAPPED``, ``BGR565_SWAPPED``, and ``L8`` (greyscale)
+//| :param loop: If True, the GIF is marked for looping playback
+//| :param dither: If True, and the image is in color, a simple ordered dither is applied.
+//| """
+//| ...
+//|
+static mp_obj_t gifio_gifwriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_file, ARG_width, ARG_height, ARG_colorspace, ARG_loop, ARG_dither };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = NULL} },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_colorspace, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = NULL} },
+ { MP_QSTR_loop, MP_ARG_BOOL, { .u_bool = true } },
+ { MP_QSTR_dither, MP_ARG_BOOL, { .u_bool = false } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t file = args[ARG_file].u_obj;
+ bool own_file = false;
+ if (mp_obj_is_str(file)) {
+ file = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), file, MP_OBJ_NEW_QSTR(MP_QSTR_wb));
+ own_file = true;
+ }
+
+ gifio_gifwriter_t *self = m_new_obj(gifio_gifwriter_t);
+ self->base.type = &gifio_gifwriter_type;
+ shared_module_gifio_gifwriter_construct(
+ self,
+ file,
+ args[ARG_width].u_int,
+ args[ARG_height].u_int,
+ (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_colorspace].u_obj),
+ args[ARG_loop].u_bool,
+ args[ARG_dither].u_bool,
+ own_file);
+
+ return self;
+}
+
+
+//| def __enter__(self) -> GifWriter:
+//| """No-op used by Context Managers."""
+//| ...
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+static mp_obj_t gifio_gifwriter___exit__(size_t n_args, const mp_obj_t *args) {
+ gifio_gifwriter_t *self = MP_OBJ_TO_PTR(args[0]);
+ shared_module_gifio_gifwriter_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(gifio_gifwriter___exit___obj, 4, 4, gifio_gifwriter___exit__);
+
+//| def deinit(self) -> None:
+//| """Close the underlying file."""
+//| ...
+//|
+static mp_obj_t gifio_gifwriter_deinit(mp_obj_t self_in) {
+ gifio_gifwriter_t *self = MP_OBJ_TO_PTR(self_in);
+ shared_module_gifio_gifwriter_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gifio_gifwriter_deinit_obj, gifio_gifwriter_deinit);
+
+//| def add_frame(self, bitmap: ReadableBuffer, delay: float = 0.1) -> None:
+//| """Add a frame to the GIF.
+//|
+//| :param bitmap: The frame data
+//| :param delay: The frame delay in seconds. The GIF format rounds this to the nearest 1/100 second, and the largest permitted value is 655 seconds.
+//| """
+//| ...
+static mp_obj_t gifio_gifwriter_add_frame(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bitmap, ARG_delay };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = NULL} },
+ { MP_QSTR_delay, MP_ARG_OBJ, {.u_obj = NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ gifio_gifwriter_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ shared_module_gifio_gifwriter_check_for_deinit(self);
+
+
+ mp_float_t delay = mp_arg_validate_obj_float_non_negative(args[ARG_delay].u_obj, MICROPY_FLOAT_CONST(0.1), MP_QSTR_delay);
+ if (delay > MICROPY_FLOAT_CONST(655.)) {
+ mp_raise_ValueError_varg(translate("%q must be <= %d"), MP_QSTR_delay, 655);
+ }
+
+ int delay_centiseconds = (int)(delay * 100);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_bitmap].u_obj, &bufinfo, MP_BUFFER_READ);
+ shared_module_gifio_gifwriter_add_frame(self, &bufinfo, delay_centiseconds);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(gifio_gifwriter_add_frame_obj, 1, gifio_gifwriter_add_frame);
+
+STATIC const mp_rom_map_elem_t gifio_gifwriter_locals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_GifWriter) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&gifio_gifwriter___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gifio_gifwriter_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_add_frame), MP_ROM_PTR(&gifio_gifwriter_add_frame_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(gifio_gifwriter_locals, gifio_gifwriter_locals_table);
+
+const mp_obj_type_t gifio_gifwriter_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_GifWriter,
+ .make_new = gifio_gifwriter_make_new,
+ .locals_dict = (mp_obj_dict_t *)&gifio_gifwriter_locals,
+};
diff --git a/circuitpython/shared-bindings/gifio/GifWriter.h b/circuitpython/shared-bindings/gifio/GifWriter.h
new file mode 100644
index 0000000..601bd78
--- /dev/null
+++ b/circuitpython/shared-bindings/gifio/GifWriter.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+
+#pragma once
+
+typedef struct gifio_gifwriter gifio_gifwriter_t;
+typedef enum displayio_colorspace displayio_colorspace_t;
+
+extern const mp_obj_type_t gifio_gifwriter_type;
+
+void shared_module_gifio_gifwriter_construct(gifio_gifwriter_t *self, mp_obj_t *file, int width, int height, displayio_colorspace_t colorspace, bool loop, bool dither, bool own_file);
+void shared_module_gifio_gifwriter_check_for_deinit(gifio_gifwriter_t *self);
+bool shared_module_gifio_gifwriter_deinited(gifio_gifwriter_t *self);
+void shared_module_gifio_gifwriter_deinit(gifio_gifwriter_t *self);
+void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_buffer_info_t *buf, int16_t delay);
+void shared_module_gifio_gifwriter_close(gifio_gifwriter_t *self);
diff --git a/circuitpython/shared-bindings/gifio/__init__.c b/circuitpython/shared-bindings/gifio/__init__.c
new file mode 100644
index 0000000..317eebc
--- /dev/null
+++ b/circuitpython/shared-bindings/gifio/__init__.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared-bindings/gifio/GifWriter.h"
+#include "shared-bindings/util.h"
+
+//| """Access GIF-format images
+//| """
+//|
+STATIC const mp_rom_map_elem_t gifio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gifio) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_GifWriter), MP_ROM_PTR(&gifio_gifwriter_type)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(gifio_module_globals, gifio_module_globals_table);
+
+const mp_obj_module_t gifio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&gifio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_gifio, gifio_module, CIRCUITPY_GIFIO);
diff --git a/circuitpython/shared-bindings/gifio/__init__.h b/circuitpython/shared-bindings/gifio/__init__.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/gifio/__init__.h
diff --git a/circuitpython/shared-bindings/gnss/GNSS.c b/circuitpython/shared-bindings/gnss/GNSS.c
new file mode 100644
index 0000000..0bd800b
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/GNSS.c
@@ -0,0 +1,185 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#include "shared-bindings/gnss/GNSS.h"
+#include "shared-bindings/time/__init__.h"
+#include "shared-bindings/util.h"
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class GNSS:
+//| """Get updated positioning information from Global Navigation Satellite System (GNSS)
+//|
+//| Usage::
+//|
+//| import gnss
+//| import time
+//|
+//| nav = gnss.GNSS([gnss.SatelliteSystem.GPS, gnss.SatelliteSystem.GLONASS])
+//| last_print = time.monotonic()
+//| while True:
+//| nav.update()
+//| current = time.monotonic()
+//| if current - last_print >= 1.0:
+//| last_print = current
+//| if nav.fix is gnss.PositionFix.INVALID:
+//| print("Waiting for fix...")
+//| continue
+//| print("Latitude: {0:.6f} degrees".format(nav.latitude))
+//| print("Longitude: {0:.6f} degrees".format(nav.longitude))"""
+//|
+
+//| def __init__(self, system: Union[SatelliteSystem, List[SatelliteSystem]]) -> None:
+//| """Turn on the GNSS.
+//|
+//| :param system: satellite system to use"""
+//| ...
+//|
+STATIC mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ gnss_obj_t *self = m_new_obj(gnss_obj_t);
+ self->base.type = &gnss_type;
+ enum { ARG_system };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_system, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ unsigned long selection = 0;
+ if (mp_obj_is_type(args[ARG_system].u_obj, &gnss_satellitesystem_type)) {
+ selection |= gnss_satellitesystem_obj_to_type(args[ARG_system].u_obj);
+ } else if (mp_obj_is_type(args[ARG_system].u_obj, &mp_type_list)) {
+ size_t systems_size = 0;
+ mp_obj_t *systems;
+ mp_obj_list_get(args[ARG_system].u_obj, &systems_size, &systems);
+ for (size_t i = 0; i < systems_size; ++i) {
+ if (!mp_obj_is_type(systems[i], &gnss_satellitesystem_type)) {
+ mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem"));
+ }
+ selection |= gnss_satellitesystem_obj_to_type(systems[i]);
+ }
+ } else {
+ mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem"));
+ }
+
+ common_hal_gnss_construct(self, selection);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the GNSS."""
+//| ...
+//|
+STATIC mp_obj_t gnss_obj_deinit(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_gnss_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_deinit_obj, gnss_obj_deinit);
+
+STATIC void check_for_deinit(gnss_obj_t *self) {
+ if (common_hal_gnss_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def update(self) -> None:
+//| """Update GNSS positioning information."""
+//| ...
+//|
+STATIC mp_obj_t gnss_obj_update(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_gnss_update(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_update_obj, gnss_obj_update);
+
+//| latitude: float
+//| """Latitude of current position in degrees (float)."""
+//|
+STATIC mp_obj_t gnss_obj_get_latitude(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_gnss_get_latitude(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_latitude_obj, gnss_obj_get_latitude);
+
+MP_PROPERTY_GETTER(gnss_latitude_obj,
+ (mp_obj_t)&gnss_get_latitude_obj);
+
+//| longitude: float
+//| """Longitude of current position in degrees (float)."""
+//|
+STATIC mp_obj_t gnss_obj_get_longitude(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_gnss_get_longitude(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_longitude_obj, gnss_obj_get_longitude);
+
+MP_PROPERTY_GETTER(gnss_longitude_obj,
+ (mp_obj_t)&gnss_get_longitude_obj);
+
+//| altitude: float
+//| """Altitude of current position in meters (float)."""
+//|
+STATIC mp_obj_t gnss_obj_get_altitude(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_gnss_get_altitude(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_altitude_obj, gnss_obj_get_altitude);
+
+MP_PROPERTY_GETTER(gnss_altitude_obj,
+ (mp_obj_t)&gnss_get_altitude_obj);
+
+//| timestamp: time.struct_time
+//| """Time when the position data was updated."""
+//|
+STATIC mp_obj_t gnss_obj_get_timestamp(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ timeutils_struct_time_t tm;
+ common_hal_gnss_get_timestamp(self, &tm);
+ return struct_time_from_tm(&tm);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_timestamp_obj, gnss_obj_get_timestamp);
+
+MP_PROPERTY_GETTER(gnss_timestamp_obj,
+ (mp_obj_t)&gnss_get_timestamp_obj);
+
+//| fix: PositionFix
+//| """Fix mode."""
+//|
+STATIC mp_obj_t gnss_obj_get_fix(mp_obj_t self_in) {
+ gnss_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return gnss_positionfix_type_to_obj(common_hal_gnss_get_fix(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_fix_obj, gnss_obj_get_fix);
+
+MP_PROPERTY_GETTER(gnss_fix_obj,
+ (mp_obj_t)&gnss_get_fix_obj);
+
+STATIC const mp_rom_map_elem_t gnss_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gnss_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&gnss_update_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_latitude), MP_ROM_PTR(&gnss_latitude_obj) },
+ { MP_ROM_QSTR(MP_QSTR_longitude), MP_ROM_PTR(&gnss_longitude_obj) },
+ { MP_ROM_QSTR(MP_QSTR_altitude), MP_ROM_PTR(&gnss_altitude_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&gnss_timestamp_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fix), MP_ROM_PTR(&gnss_fix_obj) }
+};
+STATIC MP_DEFINE_CONST_DICT(gnss_locals_dict, gnss_locals_dict_table);
+
+const mp_obj_type_t gnss_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_GNSS,
+ .make_new = gnss_make_new,
+ .locals_dict = (mp_obj_dict_t *)&gnss_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/gnss/GNSS.h b/circuitpython/shared-bindings/gnss/GNSS.h
new file mode 100644
index 0000000..dca640b
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/GNSS.h
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H
+
+#include "common-hal/gnss/GNSS.h"
+#include "shared-bindings/gnss/SatelliteSystem.h"
+#include "shared-bindings/gnss/PositionFix.h"
+
+#include "shared/timeutils/timeutils.h"
+
+extern const mp_obj_type_t gnss_type;
+
+void common_hal_gnss_construct(gnss_obj_t *self, unsigned long selection);
+void common_hal_gnss_deinit(gnss_obj_t *self);
+bool common_hal_gnss_deinited(gnss_obj_t *self);
+void common_hal_gnss_update(gnss_obj_t *self);
+
+mp_float_t common_hal_gnss_get_latitude(gnss_obj_t *self);
+mp_float_t common_hal_gnss_get_longitude(gnss_obj_t *self);
+mp_float_t common_hal_gnss_get_altitude(gnss_obj_t *self);
+void common_hal_gnss_get_timestamp(gnss_obj_t *self, timeutils_struct_time_t *tm);
+gnss_positionfix_t common_hal_gnss_get_fix(gnss_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H
diff --git a/circuitpython/shared-bindings/gnss/PositionFix.c b/circuitpython/shared-bindings/gnss/PositionFix.c
new file mode 100644
index 0000000..e60611d
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/PositionFix.c
@@ -0,0 +1,80 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#include "shared-bindings/gnss/PositionFix.h"
+
+//| class PositionFix:
+//| """Position fix mode"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the position fix mode."""
+//|
+//| INVALID: PositionFix
+//| """No measurement."""
+//|
+//| FIX_2D: PositionFix
+//| """2D fix."""
+//|
+//| FIX_3D: PositionFix
+//| """3D fix."""
+//|
+const mp_obj_type_t gnss_positionfix_type;
+
+const gnss_positionfix_obj_t gnss_positionfix_invalid_obj = {
+ { &gnss_positionfix_type },
+};
+
+const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj = {
+ { &gnss_positionfix_type },
+};
+
+const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj = {
+ { &gnss_positionfix_type },
+};
+
+gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj) {
+ gnss_positionfix_t posfix = POSITIONFIX_INVALID;
+ if (obj == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) {
+ posfix = POSITIONFIX_2D;
+ } else if (obj == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) {
+ posfix = POSITIONFIX_3D;
+ }
+ return posfix;
+}
+
+mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t posfix) {
+ switch (posfix) {
+ case POSITIONFIX_2D:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix2d_obj);
+ case POSITIONFIX_3D:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix3d_obj);
+ case POSITIONFIX_INVALID:
+ default:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_invalid_obj);
+ }
+}
+
+STATIC const mp_rom_map_elem_t gnss_positionfix_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_INVALID), MP_ROM_PTR(&gnss_positionfix_invalid_obj)},
+ {MP_ROM_QSTR(MP_QSTR_FIX_2D), MP_ROM_PTR(&gnss_positionfix_fix2d_obj)},
+ {MP_ROM_QSTR(MP_QSTR_FIX_3D), MP_ROM_PTR(&gnss_positionfix_fix3d_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(gnss_positionfix_locals_dict, gnss_positionfix_locals_dict_table);
+
+STATIC void gnss_positionfix_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr posfix = MP_QSTR_INVALID;
+ if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) {
+ posfix = MP_QSTR_FIX_2D;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) {
+ posfix = MP_QSTR_FIX_3D;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_PositionFix, posfix);
+}
+
+const mp_obj_type_t gnss_positionfix_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PositionFix,
+ .print = gnss_positionfix_print,
+ .locals_dict = (mp_obj_t)&gnss_positionfix_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/gnss/PositionFix.h b/circuitpython/shared-bindings/gnss/PositionFix.h
new file mode 100644
index 0000000..0fd595f
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/PositionFix.h
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H
+
+#include "py/obj.h"
+
+typedef enum {
+ POSITIONFIX_INVALID,
+ POSITIONFIX_2D,
+ POSITIONFIX_3D,
+} gnss_positionfix_t;
+
+extern const mp_obj_type_t gnss_positionfix_type;
+
+gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj);
+mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t mode);
+
+typedef struct {
+ mp_obj_base_t base;
+} gnss_positionfix_obj_t;
+extern const gnss_positionfix_obj_t gnss_positionfix_invalid_obj;
+extern const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj;
+extern const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H
diff --git a/circuitpython/shared-bindings/gnss/SatelliteSystem.c b/circuitpython/shared-bindings/gnss/SatelliteSystem.c
new file mode 100644
index 0000000..edac03d
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/SatelliteSystem.c
@@ -0,0 +1,113 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#include "shared-bindings/gnss/SatelliteSystem.h"
+
+//| class SatelliteSystem:
+//| """Satellite system type"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the satellite system type."""
+//|
+//| GPS: SatelliteSystem
+//| """Global Positioning System."""
+//|
+//| GLONASS: SatelliteSystem
+//| """GLObal NAvigation Satellite System."""
+//|
+//| SBAS: SatelliteSystem
+//| """Satellite Based Augmentation System."""
+//|
+//| QZSS_L1CA: SatelliteSystem
+//| """Quasi-Zenith Satellite System L1C/A."""
+//|
+//| QZSS_L1S: SatelliteSystem
+//| """Quasi-Zenith Satellite System L1S."""
+//|
+const mp_obj_type_t gnss_satellitesystem_type;
+
+const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj = {
+ { &gnss_satellitesystem_type },
+};
+
+const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj = {
+ { &gnss_satellitesystem_type },
+};
+
+const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj = {
+ { &gnss_satellitesystem_type },
+};
+
+const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj = {
+ { &gnss_satellitesystem_type },
+};
+
+const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj = {
+ { &gnss_satellitesystem_type },
+};
+
+gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj) {
+ if (obj == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) {
+ return SATELLITESYSTEM_GPS;
+ } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) {
+ return SATELLITESYSTEM_GLONASS;
+ } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) {
+ return SATELLITESYSTEM_SBAS;
+ } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) {
+ return SATELLITESYSTEM_QZSS_L1CA;
+ } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) {
+ return SATELLITESYSTEM_QZSS_L1S;
+ }
+ return SATELLITESYSTEM_NONE;
+}
+
+mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t system) {
+ switch (system) {
+ case SATELLITESYSTEM_GPS:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_gps_obj);
+ case SATELLITESYSTEM_GLONASS:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_glonass_obj);
+ case SATELLITESYSTEM_SBAS:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_sbas_obj);
+ case SATELLITESYSTEM_QZSS_L1CA:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj);
+ case SATELLITESYSTEM_QZSS_L1S:
+ return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj);
+ case SATELLITESYSTEM_NONE:
+ default:
+ return MP_ROM_NONE;
+ }
+}
+
+STATIC const mp_rom_map_elem_t gnss_satellitesystem_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_GPS), MP_ROM_PTR(&gnss_satellitesystem_gps_obj)},
+ {MP_ROM_QSTR(MP_QSTR_GLONASS), MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)},
+ {MP_ROM_QSTR(MP_QSTR_SBAS), MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)},
+ {MP_ROM_QSTR(MP_QSTR_QZSS_L1CA), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)},
+ {MP_ROM_QSTR(MP_QSTR_QZSS_L1S), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(gnss_satellitesystem_locals_dict, gnss_satellitesystem_locals_dict_table);
+
+STATIC void gnss_satellitesystem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr system = MP_QSTR_None;
+ if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) {
+ system = MP_QSTR_GPS;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) {
+ system = MP_QSTR_GLONASS;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) {
+ system = MP_QSTR_SBAS;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) {
+ system = MP_QSTR_QZSS_L1CA;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) {
+ system = MP_QSTR_QZSS_L1S;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_SatelliteSystem, system);
+}
+
+const mp_obj_type_t gnss_satellitesystem_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SatelliteSystem,
+ .print = gnss_satellitesystem_print,
+ .locals_dict = (mp_obj_t)&gnss_satellitesystem_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/gnss/SatelliteSystem.h b/circuitpython/shared-bindings/gnss/SatelliteSystem.h
new file mode 100644
index 0000000..02cd17d
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/SatelliteSystem.h
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H
+
+#include "py/obj.h"
+
+typedef enum {
+ SATELLITESYSTEM_NONE = 0,
+ SATELLITESYSTEM_GPS = (1U << 0),
+ SATELLITESYSTEM_GLONASS = (1U << 1),
+ SATELLITESYSTEM_SBAS = (1U << 2),
+ SATELLITESYSTEM_QZSS_L1CA = (1U << 3),
+ SATELLITESYSTEM_QZSS_L1S = (1U << 4),
+} gnss_satellitesystem_t;
+
+extern const mp_obj_type_t gnss_satellitesystem_type;
+
+gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj);
+mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t mode);
+
+typedef struct {
+ mp_obj_base_t base;
+} gnss_satellitesystem_obj_t;
+extern const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj;
+extern const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj;
+extern const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj;
+extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj;
+extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H
diff --git a/circuitpython/shared-bindings/gnss/__init__.c b/circuitpython/shared-bindings/gnss/__init__.c
new file mode 100644
index 0000000..ab6cbf5
--- /dev/null
+++ b/circuitpython/shared-bindings/gnss/__init__.c
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation
+//
+// SPDX-License-Identifier: MIT
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "shared-bindings/gnss/GNSS.h"
+#include "shared-bindings/gnss/SatelliteSystem.h"
+#include "shared-bindings/gnss/PositionFix.h"
+#include "shared-bindings/util.h"
+
+//| """Global Navigation Satellite System
+//|
+//| The `gnss` module contains classes to control the GNSS and acquire positioning information."""
+//|
+STATIC const mp_rom_map_elem_t gnss_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gnss) },
+ { MP_ROM_QSTR(MP_QSTR_GNSS), MP_ROM_PTR(&gnss_type) },
+
+ // Enum-like Classes.
+ { MP_ROM_QSTR(MP_QSTR_SatelliteSystem), MP_ROM_PTR(&gnss_satellitesystem_type) },
+ { MP_ROM_QSTR(MP_QSTR_PositionFix), MP_ROM_PTR(&gnss_positionfix_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(gnss_module_globals, gnss_module_globals_table);
+
+const mp_obj_module_t gnss_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&gnss_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_gnss, gnss_module, CIRCUITPY_GNSS);
diff --git a/circuitpython/shared-bindings/help.rst b/circuitpython/shared-bindings/help.rst
new file mode 100644
index 0000000..ccc3790
--- /dev/null
+++ b/circuitpython/shared-bindings/help.rst
@@ -0,0 +1,31 @@
+.. This file is part of the MicroPython project, http://micropython.org/
+
+ The MIT License (MIT)
+
+ Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+:func:`help` -- Built-in method to provide helpful information
+==============================================================
+
+.. function:: help(object=None)
+
+ Prints a help method about the given object. When ``object`` is none,
+ prints general port information.
diff --git a/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.c b/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.c
new file mode 100644
index 0000000..b63e8a8
--- /dev/null
+++ b/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.c
@@ -0,0 +1,436 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/i2cperipheral/I2CPeripheral.h"
+#include "shared-bindings/time/__init__.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "shared/runtime/interrupt_char.h"
+
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+STATIC mp_obj_t mp_obj_new_i2cperipheral_i2c_peripheral_request(i2cperipheral_i2c_peripheral_obj_t *peripheral, uint8_t address, bool is_read, bool is_restart) {
+ i2cperipheral_i2c_peripheral_request_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_request_obj_t);
+ self->base.type = &i2cperipheral_i2c_peripheral_request_type;
+ self->peripheral = peripheral;
+ self->address = address;
+ self->is_read = is_read;
+ self->is_restart = is_restart;
+ return (mp_obj_t)self;
+}
+
+//| class I2CPeripheral:
+//| """Two wire serial protocol peripheral"""
+//|
+//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, addresses: Sequence[int], smbus: bool = False) -> None:
+//| """I2C is a two-wire protocol for communicating between devices.
+//| This implements the peripheral (sensor, secondary) side.
+//|
+//| :param ~microcontroller.Pin scl: The clock pin
+//| :param ~microcontroller.Pin sda: The data pin
+//| :param addresses: The I2C addresses to respond to (how many is hw dependent).
+//| :type addresses: list[int]
+//| :param bool smbus: Use SMBUS timings if the hardware supports it"""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ i2cperipheral_i2c_peripheral_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_obj_t);
+ self->base.type = &i2cperipheral_i2c_peripheral_type;
+ enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_addresses, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_smbus, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj);
+ const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj);
+
+ mp_obj_iter_buf_t iter_buf;
+ mp_obj_t iterable = mp_getiter(args[ARG_addresses].u_obj, &iter_buf);
+ mp_obj_t item;
+ uint8_t *addresses = NULL;
+ unsigned int i = 0;
+ while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
+ mp_int_t value;
+ if (!mp_obj_get_int_maybe(item, &value)) {
+ mp_raise_TypeError_varg(translate("can't convert %q to %q"), MP_QSTR_address, MP_QSTR_int);
+ }
+ if (value < 0x00 || value > 0x7f) {
+ mp_raise_ValueError(translate("address out of bounds"));
+ }
+ addresses = m_renew(uint8_t, addresses, i, i + 1);
+ addresses[i++] = value;
+ }
+ if (i == 0) {
+ mp_raise_ValueError(translate("addresses is empty"));
+ }
+
+ common_hal_i2cperipheral_i2c_peripheral_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool);
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Releases control of the underlying hardware so other classes can use it."""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj_deinit(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_type));
+ i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_i2cperipheral_i2c_peripheral_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_deinit_obj, i2cperipheral_i2c_peripheral_obj_deinit);
+
+//| def __enter__(self) -> I2CPeripheral:
+//| """No-op used in Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware on context exit. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_type));
+ i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ common_hal_i2cperipheral_i2c_peripheral_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_obj___exit__);
+
+//| def request(self, timeout: float = -1) -> I2CPeripheralRequest:
+//| """Wait for an I2C request.
+//|
+//| :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once
+//| :return: I2C Slave Request or None if timeout=-1 and there's no request
+//| :rtype: ~i2cperipheral.I2CPeripheralRequest"""
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_check_self(mp_obj_is_type(pos_args[0], &i2cperipheral_i2c_peripheral_type));
+ i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ if (common_hal_i2cperipheral_i2c_peripheral_deinited(self)) {
+ raise_deinited_error();
+ }
+ enum { ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ #if MICROPY_PY_BUILTINS_FLOAT
+ float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000;
+ int timeout_ms = (int)f;
+ #else
+ int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000;
+ #endif
+
+ bool forever = false;
+ uint64_t timeout_end = 0;
+ if (timeout_ms == 0) {
+ forever = true;
+ } else if (timeout_ms > 0) {
+ timeout_end = common_hal_time_monotonic_ms() + timeout_ms;
+ }
+
+ int last_error = 0;
+
+ do {
+ uint8_t address;
+ bool is_read;
+ bool is_restart;
+
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ return mp_const_none;
+ }
+
+ int status = common_hal_i2cperipheral_i2c_peripheral_is_addressed(self, &address, &is_read, &is_restart);
+ if (status < 0) {
+ // On error try one more time before bailing out
+ if (last_error) {
+ mp_raise_OSError(last_error);
+ }
+ last_error = -status;
+ mp_hal_delay_ms(10);
+ continue;
+ }
+
+ last_error = 0;
+
+ if (status == 0) {
+ mp_hal_delay_us(10);
+ continue;
+ }
+
+ return mp_obj_new_i2cperipheral_i2c_peripheral_request(self, address, is_read, is_restart);
+ } while (forever || common_hal_time_monotonic_ms() < timeout_end);
+
+ if (timeout_ms > 0) {
+ mp_raise_OSError(MP_ETIMEDOUT);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_obj, 1, i2cperipheral_i2c_peripheral_request);
+
+STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_request), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_obj) },
+
+};
+
+STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_locals_dict, i2cperipheral_i2c_peripheral_locals_dict_table);
+
+const mp_obj_type_t i2cperipheral_i2c_peripheral_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2CPeripheral,
+ .make_new = i2cperipheral_i2c_peripheral_make_new,
+ .locals_dict = (mp_obj_dict_t *)&i2cperipheral_i2c_peripheral_locals_dict,
+};
+
+//| class I2CPeripheralRequest:
+//|
+//| def __init__(self, peripheral: i2cperipheral.I2CPeripheral, address: int, is_read: bool, is_restart: bool) -> None:
+//| """Information about an I2C transfer request
+//| This cannot be instantiated directly, but is returned by :py:meth:`I2CPeripheral.request`.
+//|
+//| :param peripheral: The I2CPeripheral object receiving this request
+//| :param address: I2C address
+//| :param is_read: True if the main peripheral is requesting data
+//| :param is_restart: Repeated Start Condition"""
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 4, 4, false);
+ return mp_obj_new_i2cperipheral_i2c_peripheral_request(args[0], mp_obj_get_int(args[1]), mp_obj_is_true(args[2]), mp_obj_is_true(args[3]));
+}
+
+//| def __enter__(self) -> I2CPeripheralRequest:
+//| """No-op used in Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Close the request."""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_request_obj___exit__);
+
+//| address: int
+//| """The I2C address of the request."""
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_address(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(self->address);
+}
+MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_address_obj, i2cperipheral_i2c_peripheral_request_get_address);
+
+//| is_read: bool
+//| """The I2C main controller is reading from this peripheral."""
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_read(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(self->is_read);
+}
+MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_read_obj, i2cperipheral_i2c_peripheral_request_get_is_read);
+
+//| is_restart: bool
+//| """Is Repeated Start Condition."""
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_restart(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(self->is_restart);
+}
+MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_restart_obj, i2cperipheral_i2c_peripheral_request_get_is_restart);
+
+//| def read(self, n: int = -1, ack: bool = True) -> bytearray:
+//| """Read data.
+//| If ack=False, the caller is responsible for calling :py:meth:`I2CPeripheralRequest.ack`.
+//|
+//| :param n: Number of bytes to read (negative means all)
+//| :param ack: Whether or not to send an ACK after the n'th byte
+//| :return: Bytes read"""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_check_self(mp_obj_is_type(pos_args[0], &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ enum { ARG_n, ARG_ack };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_n, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_ack, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (self->is_read) {
+ mp_raise_OSError(MP_EACCES);
+ }
+
+ int n = args[ARG_n].u_int;
+ if (n == 0) {
+ return mp_obj_new_bytearray(0, NULL);
+ }
+ bool ack = args[ARG_ack].u_bool;
+
+ int i = 0;
+ uint8_t *buffer = NULL;
+ uint64_t timeout_end = common_hal_time_monotonic_ms() + 10 * 1000;
+ while (common_hal_time_monotonic_ms() < timeout_end) {
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ break;
+ }
+
+ uint8_t data;
+ int num = common_hal_i2cperipheral_i2c_peripheral_read_byte(self->peripheral, &data);
+ if (num == 0) {
+ break;
+ }
+
+ buffer = m_renew(uint8_t, buffer, i, i + 1);
+ buffer[i++] = data;
+ if (i == n) {
+ if (ack) {
+ common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true);
+ }
+ break;
+ }
+ common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true);
+ }
+
+ return mp_obj_new_bytearray(i, buffer);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_read_obj, 1, i2cperipheral_i2c_peripheral_request_read);
+
+//| def write(self, buffer: ReadableBuffer) -> int:
+//| """Write the data contained in buffer.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer buffer: Write out the data in this buffer
+//| :return: Number of bytes written"""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_write(mp_obj_t self_in, mp_obj_t buf_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (!self->is_read) {
+ mp_raise_OSError(MP_EACCES);
+ }
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+
+ for (size_t i = 0; i < bufinfo.len; i++) {
+ RUN_BACKGROUND_TASKS;
+ if (mp_hal_is_interrupted()) {
+ break;
+ }
+
+ int num = common_hal_i2cperipheral_i2c_peripheral_write_byte(self->peripheral, ((uint8_t *)(bufinfo.buf))[i]);
+ if (num == 0) {
+ return mp_obj_new_int(i);
+ }
+ }
+
+ return mp_obj_new_int(bufinfo.len);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(i2cperipheral_i2c_peripheral_request_write_obj, i2cperipheral_i2c_peripheral_request_write);
+
+//| def ack(self, ack: bool = True) -> None:
+//| """Acknowledge or Not Acknowledge last byte received.
+//| Use together with :py:meth:`I2CPeripheralRequest.read` ack=False.
+//|
+//| :param ack: Whether to send an ACK or NACK"""
+//| ...
+//|
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_obj_t *args) {
+ mp_check_self(mp_obj_is_type(args[0], &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]);
+
+ if (self->is_read) {
+ mp_raise_OSError(MP_EACCES);
+ }
+
+ common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, ack);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ack_obj, 1, 2, i2cperipheral_i2c_peripheral_request_ack);
+
+STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_close(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &i2cperipheral_i2c_peripheral_request_type));
+ i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_request_close_obj, i2cperipheral_i2c_peripheral_request_close);
+
+STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_request_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_is_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_is_restart), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_restart_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ack), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_ack_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_close_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_request_locals_dict, i2cperipheral_i2c_peripheral_request_locals_dict_table);
+
+const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_I2CPeripheralRequest,
+ .make_new = i2cperipheral_i2c_peripheral_request_make_new,
+ .locals_dict = (mp_obj_dict_t *)&i2cperipheral_i2c_peripheral_request_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.h b/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.h
new file mode 100644
index 0000000..d3db1b9
--- /dev/null
+++ b/circuitpython/shared-bindings/i2cperipheral/I2CPeripheral.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/i2cperipheral/I2CPeripheral.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ i2cperipheral_i2c_peripheral_obj_t *peripheral;
+ uint16_t address;
+ bool is_read;
+ bool is_restart;
+} i2cperipheral_i2c_peripheral_request_obj_t;
+
+extern const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type;
+
+extern const mp_obj_type_t i2cperipheral_i2c_peripheral_type;
+
+extern void common_hal_i2cperipheral_i2c_peripheral_construct(i2cperipheral_i2c_peripheral_obj_t *self,
+ const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda,
+ uint8_t *addresses, unsigned int num_addresses, bool smbus);
+extern void common_hal_i2cperipheral_i2c_peripheral_deinit(i2cperipheral_i2c_peripheral_obj_t *self);
+extern bool common_hal_i2cperipheral_i2c_peripheral_deinited(i2cperipheral_i2c_peripheral_obj_t *self);
+
+extern int common_hal_i2cperipheral_i2c_peripheral_is_addressed(i2cperipheral_i2c_peripheral_obj_t *self,
+ uint8_t *address, bool *is_read, bool *is_restart);
+extern int common_hal_i2cperipheral_i2c_peripheral_read_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t *data);
+extern int common_hal_i2cperipheral_i2c_peripheral_write_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t data);
+extern void common_hal_i2cperipheral_i2c_peripheral_ack(i2cperipheral_i2c_peripheral_obj_t *self, bool ack);
+extern void common_hal_i2cperipheral_i2c_peripheral_close(i2cperipheral_i2c_peripheral_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H
diff --git a/circuitpython/shared-bindings/i2cperipheral/__init__.c b/circuitpython/shared-bindings/i2cperipheral/__init__.c
new file mode 100644
index 0000000..fde7002
--- /dev/null
+++ b/circuitpython/shared-bindings/i2cperipheral/__init__.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+// #include "shared-bindings/i2cperipheral/__init__.h"
+#include "shared-bindings/i2cperipheral/I2CPeripheral.h"
+
+#include "py/runtime.h"
+
+//| """Two wire serial protocol peripheral
+//|
+//| The `i2cperipheral` module contains classes to support an I2C peripheral.
+//|
+//| Example emulating a peripheral with 2 addresses (read and write)::
+//|
+//| import board
+//| from i2cperipheral import I2CPeripheral
+//|
+//| regs = [0] * 16
+//| index = 0
+//|
+//| with I2CPeripheral(board.SCL, board.SDA, (0x40, 0x41)) as device:
+//| while True:
+//| r = device.request()
+//| if not r:
+//| # Maybe do some housekeeping
+//| continue
+//| with r: # Closes the transfer if necessary by sending a NACK or feeding dummy bytes
+//| if r.address == 0x40:
+//| if not r.is_read: # Main write which is Selected read
+//| b = r.read(1)
+//| if not b or b[0] > 15:
+//| break
+//| index = b[0]
+//| b = r.read(1)
+//| if b:
+//| regs[index] = b[0]
+//| elif r.is_restart: # Combined transfer: This is the Main read message
+//| n = r.write(bytes([regs[index]]))
+//| #else:
+//| # A read transfer is not supported in this example
+//| # If the microcontroller tries, it will get 0xff byte(s) by the ctx manager (r.close())
+//| elif r.address == 0x41:
+//| if not r.is_read:
+//| b = r.read(1)
+//| if b and b[0] == 0xde:
+//| # do something
+//| pass
+//|
+//| This example sets up an I2C device that can be accessed from Linux like this::
+//|
+//| $ i2cget -y 1 0x40 0x01
+//| 0x00
+//| $ i2cset -y 1 0x40 0x01 0xaa
+//| $ i2cget -y 1 0x40 0x01
+//| 0xaa
+//|
+//| .. warning::
+//| I2CPeripheral makes use of clock stretching in order to slow down
+//| the host.
+//| Make sure the I2C host supports this.
+//|
+//| Raspberry Pi in particular does not support this with its I2C hw block.
+//| This can be worked around by using the ``i2c-gpio`` bit banging driver.
+//| Since the RPi firmware uses the hw i2c, it's not possible to emulate a HAT eeprom."""
+//|
+
+STATIC const mp_rom_map_elem_t i2cperipheral_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cperipheral) },
+ { MP_ROM_QSTR(MP_QSTR_I2CPeripheral), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(i2cperipheral_module_globals, i2cperipheral_module_globals_table);
+
+const mp_obj_module_t i2cperipheral_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&i2cperipheral_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_i2cperipheral, i2cperipheral_module, CIRCUITPY_I2CPERIPHERAL);
diff --git a/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.c b/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.c
new file mode 100644
index 0000000..7f90f09
--- /dev/null
+++ b/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.c
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared/runtime/context_manager_helpers.h"
+
+#include "shared-bindings/imagecapture/ParallelImageCapture.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "common-hal/imagecapture/ParallelImageCapture.h"
+
+//| class ParallelImageCapture:
+//| """Capture image frames from a camera with parallel data interface"""
+//|
+//| def __init__(
+//| self,
+//| *,
+//| data_pins: List[microcontroller.Pin],
+//| clock: microcontroller.Pin,
+//| vsync: Optional[microcontroller.Pin],
+//| href: Optional[microcontroller.Pin],
+//| ) -> None:
+//| """Create a parallel image capture object
+//|
+//| :param List[microcontroller.Pin] data_pins: The data pins.
+//| :param microcontroller.Pin clock: The pixel clock input.
+//| :param microcontroller.Pin vsync: The vertical sync input, which has a negative-going pulse at the beginning of each frame.
+//| :param microcontroller.Pin href: The horizontal reference input, which is high whenever the camera is transmitting valid pixel information.
+//| """
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_data_pins, ARG_clock, ARG_vsync, ARG_href,
+ NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data_pins, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = MP_ROM_NONE } },
+ { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_vsync, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_href, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t pins[32];
+ uint8_t pin_count;
+ validate_pins(MP_QSTR_data, pins, MP_ARRAY_SIZE(pins), args[ARG_data_pins].u_obj, &pin_count);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *vsync = validate_obj_is_free_pin_or_none(args[ARG_vsync].u_obj);
+ const mcu_pin_obj_t *href = validate_obj_is_free_pin_or_none(args[ARG_href].u_obj);
+
+ imagecapture_parallelimagecapture_obj_t *self = m_new_obj(imagecapture_parallelimagecapture_obj_t);
+ self->base.type = &imagecapture_parallelimagecapture_type;
+
+ common_hal_imagecapture_parallelimagecapture_construct(self, pins, pin_count, clock, vsync, href);
+
+ return self;
+}
+
+//| def capture(self, buffer: WriteableBuffer) -> WriteableBuffer:
+//| """Capture a single frame into the given buffer.
+//|
+//| This will stop a continuous-mode capture, if one is in progress."""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_capture(mp_obj_t self_in, mp_obj_t buffer) {
+ imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
+ common_hal_imagecapture_parallelimagecapture_singleshot_capture(self, buffer);
+
+ return buffer;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(imagecapture_parallelimagecapture_capture_obj, imagecapture_parallelimagecapture_capture);
+
+//| def continuous_capture_start(self, buffer1: WriteableBuffer, buffer2: WriteableBuffer, /) -> None:
+//| """Begin capturing into the given buffers in the background.
+//|
+//| Call `continuous_capture_get_frame` to get the next available
+//| frame, and `continuous_capture_stop` to stop capturing.
+//|
+//| Until `continuous_capture_stop` (or `deinit`) is called, the
+//| `ParallelImageCapture` object keeps references to ``buffer1`` and
+//| ``buffer2``, so the objects will not be garbage collected."""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_start(mp_obj_t self_in, mp_obj_t buffer1, mp_obj_t buffer2) {
+ imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
+ common_hal_imagecapture_parallelimagecapture_continuous_capture_start(self, buffer1, buffer2);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(imagecapture_parallelimagecapture_continuous_capture_start_obj, imagecapture_parallelimagecapture_continuous_capture_start);
+
+//| def continuous_capture_get_frame(self) -> WriteableBuffer:
+//| """Return the next available frame, one of the two buffers passed to `continuous_capture_start`"""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_get_frame(mp_obj_t self_in) {
+ imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
+ return common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(imagecapture_parallelimagecapture_continuous_capture_get_frame_obj, imagecapture_parallelimagecapture_continuous_capture_get_frame);
+
+
+
+//| def continuous_capture_stop(self) -> None:
+//| """Stop continuous capture.
+//|
+//| Calling this method also causes the object to release its
+//| references to the buffers passed to `continuous_capture_start`,
+//| potentially allowing the objects to be garbage collected."""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_stop(mp_obj_t self_in) {
+ imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
+ common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(imagecapture_parallelimagecapture_continuous_capture_stop_obj, imagecapture_parallelimagecapture_continuous_capture_stop);
+
+
+
+
+//| def deinit(self) -> None:
+//| """Deinitialize this instance"""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture_deinit(mp_obj_t self_in) {
+ imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
+ common_hal_imagecapture_parallelimagecapture_deinit(self);
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(imagecapture_parallelimagecapture_deinit_obj, imagecapture_parallelimagecapture_deinit);
+
+//| def __enter__(self) -> ParallelImageCapture:
+//| """No-op used in Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware on context exit. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t imagecapture_parallelimagecapture___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_imagecapture_parallelimagecapture_deinit(args[0]);
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(imagecapture_parallelimagecapture___exit___obj, 4, 4, imagecapture_parallelimagecapture___exit__);
+
+
+STATIC const mp_rom_map_elem_t imagecapture_parallelimagecapture_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&imagecapture_parallelimagecapture_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&imagecapture_parallelimagecapture___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&imagecapture_parallelimagecapture_capture_obj) },
+ { MP_ROM_QSTR(MP_QSTR_continuous_capture_start), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_start_obj) },
+ { MP_ROM_QSTR(MP_QSTR_continuous_capture_stop), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_stop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_continuous_capture_get_frame), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_get_frame_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(imagecapture_parallelimagecapture_locals_dict, imagecapture_parallelimagecapture_locals_dict_table);
+
+const mp_obj_type_t imagecapture_parallelimagecapture_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ParallelImageCapture,
+ .make_new = imagecapture_parallelimagecapture_make_new,
+ .locals_dict = (mp_obj_dict_t *)&imagecapture_parallelimagecapture_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.h b/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.h
new file mode 100644
index 0000000..72ddc23
--- /dev/null
+++ b/circuitpython/shared-bindings/imagecapture/ParallelImageCapture.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "common-hal/microcontroller/Pin.h"
+
+typedef struct imagecapture_parallelimagecapture_obj imagecapture_parallelimagecapture_obj_t;
+extern const mp_obj_type_t imagecapture_parallelimagecapture_type;
+
+// if only the first element of data_pins is non-NULL, the pins are sequential in microcontroller pin numbering.
+void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_parallelimagecapture_obj_t *self,
+ const uint8_t data_pins[],
+ uint8_t data_count,
+ const mcu_pin_obj_t *data_clock,
+ const mcu_pin_obj_t *vertical_sync,
+ const mcu_pin_obj_t *horizontal_sync);
+void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self);
+bool common_hal_imagecapture_parallelimagecapture_deinited(imagecapture_parallelimagecapture_obj_t *self);
+void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer);
+void common_hal_imagecapture_parallelimagecapture_continuous_capture_start(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer1, mp_obj_t buffer2);
+void common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(imagecapture_parallelimagecapture_obj_t *self);
+mp_obj_t common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(imagecapture_parallelimagecapture_obj_t *self);
diff --git a/circuitpython/shared-bindings/imagecapture/__init__.c b/circuitpython/shared-bindings/imagecapture/__init__.c
new file mode 100644
index 0000000..0e5092a
--- /dev/null
+++ b/circuitpython/shared-bindings/imagecapture/__init__.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/imagecapture/ParallelImageCapture.h"
+
+//| """Support for "Parallel capture" interfaces"""
+//|
+
+STATIC const mp_rom_map_elem_t imagecapture_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_imagecapture) },
+ { MP_ROM_QSTR(MP_QSTR_ParallelImageCapture), MP_ROM_PTR(&imagecapture_parallelimagecapture_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(imagecapture_module_globals, imagecapture_module_globals_table);
+
+const mp_obj_module_t imagecapture_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&imagecapture_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_imagecapture, imagecapture_module, CIRCUITPY_IMAGECAPTURE);
diff --git a/circuitpython/shared-bindings/imagecapture/__init__.h b/circuitpython/shared-bindings/imagecapture/__init__.h
new file mode 100644
index 0000000..1e170aa
--- /dev/null
+++ b/circuitpython/shared-bindings/imagecapture/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/index.rst b/circuitpython/shared-bindings/index.rst
new file mode 100644
index 0000000..bf04ae1
--- /dev/null
+++ b/circuitpython/shared-bindings/index.rst
@@ -0,0 +1,23 @@
+Core Modules
+========================================
+
+These core modules are intended on being consistent across ports and boards.
+A module may not exist on a port/board if no underlying hardware support is
+present or if flash space is limited. For example, a microcontroller without
+analog features will not have `analogio`. See the `support_matrix` page for
+a list of modules supported on each board.
+
+.. toctree::
+ :hidden:
+
+ support_matrix
+
+Modules
+---------
+
+.. toctree::
+ :glob:
+ :maxdepth: 2
+
+ ../shared-bindings/*/index
+ help
diff --git a/circuitpython/shared-bindings/ipaddress/IPv4Address.c b/circuitpython/shared-bindings/ipaddress/IPv4Address.c
new file mode 100644
index 0000000..2320432
--- /dev/null
+++ b/circuitpython/shared-bindings/ipaddress/IPv4Address.c
@@ -0,0 +1,194 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/ipaddress/IPv4Address.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/ipaddress/__init__.h"
+
+//| class IPv4Address:
+//| """Encapsulates an IPv4 address."""
+//|
+
+//| def __init__(self, address: Union[int, str, bytes]) -> None:
+//| """Create a new IPv4Address object encapsulating the address value.
+//|
+//| The value itself can either be bytes or a string formatted address."""
+//| ...
+//|
+STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_address };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mp_obj_t address = args[ARG_address].u_obj;
+
+ uint32_t value;
+ uint8_t *buf = NULL;
+ if (mp_obj_get_int_maybe(address, (mp_int_t *)&value)) {
+ // We're done.
+ buf = (uint8_t *)&value;
+ } else if (mp_obj_is_str(address)) {
+ GET_STR_DATA_LEN(address, str_data, str_len);
+ if (!ipaddress_parse_ipv4address((const char *)str_data, str_len, &value)) {
+ mp_raise_ValueError(translate("Not a valid IP string"));
+ }
+ buf = (uint8_t *)&value;
+ } else {
+ mp_buffer_info_t buf_info;
+ if (mp_get_buffer(address, &buf_info, MP_BUFFER_READ)) {
+ if (buf_info.len != 4) {
+ mp_raise_ValueError_varg(translate("Address must be %d bytes long"), 4);
+ }
+ buf = buf_info.buf;
+ }
+ }
+
+
+ ipaddress_ipv4address_obj_t *self = m_new_obj(ipaddress_ipv4address_obj_t);
+ self->base.type = &ipaddress_ipv4address_type;
+
+ common_hal_ipaddress_ipv4address_construct(self, buf, 4);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| packed: bytes
+//| """The bytes that make up the address (read-only)."""
+//|
+STATIC mp_obj_t ipaddress_ipv4address_get_packed(mp_obj_t self_in) {
+ ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_ipaddress_ipv4address_get_packed(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ipv4address_get_packed_obj, ipaddress_ipv4address_get_packed);
+
+MP_PROPERTY_GETTER(ipaddress_ipv4address_packed_obj,
+ (mp_obj_t)&ipaddress_ipv4address_get_packed_obj);
+
+//| version: int
+//| """4 for IPv4, 6 for IPv6"""
+//|
+STATIC mp_obj_t ipaddress_ipv4address_get_version(mp_obj_t self_in) {
+ ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t buf_info;
+ mp_obj_t address_bytes = common_hal_ipaddress_ipv4address_get_packed(self);
+ mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ);
+ mp_int_t version = 6;
+ if (buf_info.len == 4) {
+ version = 4;
+ }
+
+ return MP_OBJ_NEW_SMALL_INT(version);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ipv4address_get_version_obj, ipaddress_ipv4address_get_version);
+
+MP_PROPERTY_GETTER(ipaddress_ipv4address_version_obj,
+ (mp_obj_t)&ipaddress_ipv4address_get_version_obj);
+
+//| def __eq__(self, other: object) -> bool:
+//| """Two Address objects are equal if their addresses and address types are equal."""
+//| ...
+//|
+STATIC mp_obj_t ipaddress_ipv4address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ switch (op) {
+ // Two Addresses are equal if their address bytes and address_type are equal
+ case MP_BINARY_OP_EQUAL:
+ if (mp_obj_is_type(rhs_in, &ipaddress_ipv4address_type)) {
+ ipaddress_ipv4address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in);
+ ipaddress_ipv4address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in);
+ return mp_obj_new_bool(
+ mp_obj_equal(common_hal_ipaddress_ipv4address_get_packed(lhs),
+ common_hal_ipaddress_ipv4address_get_packed(rhs)));
+
+ } else {
+ return mp_const_false;
+ }
+
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the IPv4Address data."""
+//| ...
+//|
+STATIC mp_obj_t ipaddress_ipv4address_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ switch (op) {
+ // Two Addresses are equal if their address bytes and address_type are equal
+ case MP_UNARY_OP_HASH: {
+ mp_obj_t bytes = common_hal_ipaddress_ipv4address_get_packed(MP_OBJ_TO_PTR(self_in));
+ GET_STR_HASH(bytes, h);
+ if (h == 0) {
+ GET_STR_DATA_LEN(bytes, data, len);
+ h = qstr_compute_hash(data, len);
+ }
+ return MP_OBJ_NEW_SMALL_INT(h);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC void ipaddress_ipv4address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t buf_info;
+ mp_obj_t address_bytes = common_hal_ipaddress_ipv4address_get_packed(self);
+ mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ);
+
+ const uint8_t *buf = (uint8_t *)buf_info.buf;
+ mp_printf(print, "%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
+}
+
+STATIC const mp_rom_map_elem_t ipaddress_ipv4address_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_packed), MP_ROM_PTR(&ipaddress_ipv4address_packed_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ipaddress_ipv4address_locals_dict, ipaddress_ipv4address_locals_dict_table);
+
+const mp_obj_type_t ipaddress_ipv4address_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Address,
+ .make_new = ipaddress_ipv4address_make_new,
+ .locals_dict = (mp_obj_dict_t *)&ipaddress_ipv4address_locals_dict,
+ .print = ipaddress_ipv4address_print,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = ipaddress_ipv4address_unary_op,
+ .binary_op = ipaddress_ipv4address_binary_op,
+ )
+};
diff --git a/circuitpython/shared-bindings/ipaddress/IPv4Address.h b/circuitpython/shared-bindings/ipaddress/IPv4Address.h
new file mode 100644
index 0000000..46a52a0
--- /dev/null
+++ b/circuitpython/shared-bindings/ipaddress/IPv4Address.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H
+
+#include "shared-module/ipaddress/IPv4Address.h"
+
+extern const mp_obj_type_t ipaddress_ipv4address_type;
+
+mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value);
+void common_hal_ipaddress_ipv4address_construct(ipaddress_ipv4address_obj_t *self, uint8_t *buf, size_t len);
+mp_obj_t common_hal_ipaddress_ipv4address_get_packed(ipaddress_ipv4address_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H
diff --git a/circuitpython/shared-bindings/ipaddress/__init__.c b/circuitpython/shared-bindings/ipaddress/__init__.c
new file mode 100644
index 0000000..6da5a52
--- /dev/null
+++ b/circuitpython/shared-bindings/ipaddress/__init__.c
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objexcept.h"
+#include "py/objstr.h"
+#include "py/parsenum.h"
+#include "py/runtime.h"
+#include "shared-bindings/ipaddress/__init__.h"
+#include "shared-bindings/ipaddress/IPv4Address.h"
+
+//| """
+//| The `ipaddress` module provides types for IP addresses. It is a subset of CPython's ipaddress
+//| module.
+//| """
+//|
+
+
+bool ipaddress_parse_ipv4address(const char *str_data, size_t str_len, uint32_t *ip_out) {
+ size_t period_count = 0;
+ size_t period_index[4] = {0, 0, 0, str_len};
+ for (size_t i = 0; i < str_len; i++) {
+ if (str_data[i] == '.') {
+ if (period_count < 3) {
+ period_index[period_count] = i;
+ }
+ period_count++;
+ }
+ }
+ if (period_count > 3) {
+ return false;
+ }
+
+ size_t last_period = 0;
+ if (ip_out != NULL) {
+ *ip_out = 0;
+ }
+ for (size_t i = 0; i < 4; i++) {
+ // Catch exceptions thrown by mp_parse_num_integer
+ nlr_buf_t nlr;
+ mp_obj_t octet;
+ if (nlr_push(&nlr) == 0) {
+ octet = mp_parse_num_integer((const char *)str_data + last_period, period_index[i] - last_period, 10, NULL);
+ nlr_pop();
+ } else {
+ return false;
+ }
+ last_period = period_index[i] + 1;
+ if (ip_out != NULL) {
+ mp_int_t int_octet = MP_OBJ_SMALL_INT_VALUE(octet);
+ *ip_out |= int_octet << (i * 8);
+ }
+ }
+ return true;
+}
+
+//| def ip_address(obj: Union[int, str]) -> IPv4Address:
+//| """Return a corresponding IP address object or raise ValueError if not possible."""
+//| ...
+//|
+
+STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) {
+ uint32_t value;
+ if (mp_obj_get_int_maybe(ip_in, (mp_int_t *)&value)) {
+ // We're done.
+ } else if (mp_obj_is_str(ip_in)) {
+ GET_STR_DATA_LEN(ip_in, str_data, str_len);
+ if (!ipaddress_parse_ipv4address((const char *)str_data, str_len, &value)) {
+ mp_raise_ValueError(translate("Not a valid IP string"));
+ }
+ } else {
+ mp_raise_ValueError(translate("Only int or string supported for ip"));
+ }
+
+ return common_hal_ipaddress_new_ipv4address(value);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ip_address_obj, ipaddress_ip_address);
+
+STATIC const mp_rom_map_elem_t ipaddress_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ipaddress) },
+ { MP_ROM_QSTR(MP_QSTR_ip_address), MP_ROM_PTR(&ipaddress_ip_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_IPv4Address), MP_ROM_PTR(&ipaddress_ipv4address_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ipaddress_module_globals, ipaddress_module_globals_table);
+
+
+const mp_obj_module_t ipaddress_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&ipaddress_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_ipaddress, ipaddress_module, CIRCUITPY_IPADDRESS);
diff --git a/circuitpython/shared-bindings/ipaddress/__init__.h b/circuitpython/shared-bindings/ipaddress/__init__.h
new file mode 100644
index 0000000..7c2e5c1
--- /dev/null
+++ b/circuitpython/shared-bindings/ipaddress/__init__.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H
+
+#include "shared-module/ipaddress/__init__.h"
+
+bool ipaddress_parse_ipv4address(const char *ip_str, size_t len, uint32_t *ip_out);
+
+mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H
diff --git a/circuitpython/shared-bindings/is31fl3741/FrameBuffer.c b/circuitpython/shared-bindings/is31fl3741/FrameBuffer.c
new file mode 100644
index 0000000..e1a87e8
--- /dev/null
+++ b/circuitpython/shared-bindings/is31fl3741/FrameBuffer.c
@@ -0,0 +1,301 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/objarray.h"
+
+#include "shared-bindings/is31fl3741/IS31FL3741.h"
+#include "shared-bindings/is31fl3741/FrameBuffer.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/framebufferio/__init__.h"
+#include "shared-module/framebufferio/FramebufferDisplay.h"
+#include "shared-bindings/busio/I2C.h"
+
+//| class IS31FL3741_FrameBuffer:
+//| """Creates an in-memory framebuffer for a IS31FL3741 device."""
+//|
+//| def __init__(self, is31: is31fl3741.IS31FL3741, width: int, height: int, mapping: Tuple[int, ...], *,
+//| framebuffer: Optional[WriteableBuffer] = None, scale: bool = False, gamma: bool = False) -> None:
+//| """Create a IS31FL3741_FrameBuffer object with the given attributes.
+//|
+//| The framebuffer is in "RGB888" format using 4 bytes per pixel.
+//| Bits 24-31 are ignored. The format is in RGB order.
+//|
+//| If a framebuffer is not passed in, one is allocated and initialized
+//| to all black. In any case, the framebuffer can be retrieved
+//| by passing the Is31fl3741 object to memoryview().
+//|
+//| A Is31fl3741 is often used in conjunction with a
+//| `framebufferio.FramebufferDisplay`.
+//|
+//| :param is31fl3741.IS31FL3741 is31: base IS31FL3741 instance to drive the framebuffer
+//| :param int width: width of the display
+//| :param int height: height of the display
+//| :param Tuple[int, ...] mapping: mapping of matrix locations to LEDs
+//| :param Optional[WriteableBuffer] framebuffer: Optional buffer to hold the display
+//| :param bool scale: if True display is scaled down by 3 when displayed
+//| :param bool gamma: if True apply gamma correction to all LEDs"""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_is31, ARG_width, ARG_height, ARG_mapping, ARG_framebuffer, ARG_scale, ARG_gamma };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_is31, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_mapping, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_framebuffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = mp_const_none } },
+ { MP_QSTR_scale, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
+ { MP_QSTR_gamma, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = false } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ is31fl3741_FrameBuffer_obj_t *self = &allocate_display_bus_or_raise()->is31fl3741;
+ self->base.type = &is31fl3741_FrameBuffer_type;
+
+ if (args[ARG_width].u_int <= 0) {
+ mp_raise_ValueError(translate("width must be greater than zero"));
+ }
+
+ self->scale = args[ARG_scale].u_bool;
+ if (self->scale) {
+ if (((args[ARG_height].u_int % 3) != 0) || ((args[ARG_width].u_int % 3) != 0)) {
+ mp_raise_ValueError(translate("Scale dimensions must divide by 3"));
+ }
+
+ self->scale_width = args[ARG_width].u_int / 3;
+ self->scale_height = args[ARG_height].u_int / 3;
+ } else {
+ self->scale_width = args[ARG_width].u_int;
+ self->scale_height = args[ARG_height].u_int;
+ }
+
+ self->auto_gamma = args[ARG_gamma].u_bool;
+
+ mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
+ if (framebuffer == mp_const_none) {
+ int width = args[ARG_width].u_int;
+ int height = args[ARG_height].u_int;
+ int bufsize = 4 * width * height;
+ framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
+ }
+
+ common_hal_is31fl3741_FrameBuffer_construct(self,
+ args[ARG_width].u_int,
+ args[ARG_height].u_int,
+ framebuffer,
+ args[ARG_is31].u_obj,
+ args[ARG_mapping].u_obj
+ );
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Free the resources associated with this
+//| IS31FL3741 instance. After deinitialization, no further operations
+//| may be performed."""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_deinit(mp_obj_t self_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ common_hal_is31fl3741_FrameBuffer_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_deinit_obj, is31fl3741_FrameBuffer_deinit);
+
+static void check_for_deinit(is31fl3741_FrameBuffer_obj_t *self) {
+ if (self->framebuffer == NULL) {
+ raise_deinited_error();
+ }
+}
+
+//| brightness: float
+//| """In the current implementation, 0.0 turns the display off entirely
+//| and any other value up to 1.0 turns the display on fully."""
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_get_brightness(mp_obj_t self_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+ uint8_t current = common_hal_is31fl3741_get_current(self->is31fl3741);
+
+ float brightness = (float)current / (float)0xFF;
+ return mp_obj_new_float(brightness);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_brightness_obj, is31fl3741_FrameBuffer_get_brightness);
+
+STATIC mp_obj_t is31fl3741_FrameBuffer_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+ mp_float_t brightness = mp_obj_get_float(value_in);
+ if (brightness < 0.0f || brightness > 1.0f) {
+ mp_raise_ValueError(translate("Brightness must be 0-1.0"));
+ }
+
+ uint8_t current = (uint8_t)(brightness * 0xFF);
+ common_hal_is31fl3741_set_current(self->is31fl3741, current);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_FrameBuffer_set_brightness_obj, is31fl3741_FrameBuffer_set_brightness);
+
+MP_PROPERTY_GETSET(is31fl3741_FrameBuffer_brightness_obj,
+ (mp_obj_t)&is31fl3741_FrameBuffer_get_brightness_obj,
+ (mp_obj_t)&is31fl3741_FrameBuffer_set_brightness_obj);
+
+//| def refresh(self) -> None:
+//| """Transmits the color data in the buffer to the pixels so that
+//| they are shown."""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_refresh(mp_obj_t self_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+ common_hal_is31fl3741_FrameBuffer_refresh(self, 0);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_refresh_obj, is31fl3741_FrameBuffer_refresh);
+
+//| width: int
+//| """The width of the display, in pixels"""
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_get_width(mp_obj_t self_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_width_obj, is31fl3741_FrameBuffer_get_width);
+MP_PROPERTY_GETTER(is31fl3741_FrameBuffer_width_obj,
+ (mp_obj_t)&is31fl3741_FrameBuffer_get_width_obj);
+
+//| height: int
+//| """The height of the display, in pixels"""
+//|
+STATIC mp_obj_t is31fl3741_FrameBuffer_get_height(mp_obj_t self_in) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_is31fl3741_FrameBuffer_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_FrameBuffer_get_height_obj, is31fl3741_FrameBuffer_get_height);
+MP_PROPERTY_GETTER(is31fl3741_FrameBuffer_height_obj,
+ (mp_obj_t)&is31fl3741_FrameBuffer_get_height_obj);
+
+STATIC const mp_rom_map_elem_t is31fl3741_FrameBuffer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_FrameBuffer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&is31fl3741_FrameBuffer_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&is31fl3741_FrameBuffer_refresh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&is31fl3741_FrameBuffer_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&is31fl3741_FrameBuffer_height_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(is31fl3741_FrameBuffer_locals_dict, is31fl3741_FrameBuffer_locals_dict_table);
+
+STATIC void is31fl3741_FrameBuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ check_for_deinit(self);
+
+ *bufinfo = self->bufinfo;
+}
+
+STATIC void is31fl3741_FrameBuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
+ common_hal_is31fl3741_FrameBuffer_refresh(self_in, dirty_row_bitmap);
+}
+
+STATIC void is31fl3741_FrameBuffer_deinit_proto(mp_obj_t self_in) {
+ common_hal_is31fl3741_FrameBuffer_deinit(self_in);
+}
+
+STATIC float is31fl3741_FrameBuffer_get_brightness_proto(mp_obj_t self_in) {
+ return common_hal_is31fl3741_FrameBuffer_get_paused(self_in) ? 0.0f : 1.0f;
+}
+
+STATIC bool is31fl3741_FrameBuffer_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
+ common_hal_is31fl3741_FrameBuffer_set_paused(self_in, value <= 0);
+ return true;
+}
+
+STATIC int is31fl3741_FrameBuffer_get_width_proto(mp_obj_t self_in) {
+ return common_hal_is31fl3741_FrameBuffer_get_width(self_in);
+}
+
+STATIC int is31fl3741_FrameBuffer_get_height_proto(mp_obj_t self_in) {
+ return common_hal_is31fl3741_FrameBuffer_get_height(self_in);
+}
+
+STATIC int is31fl3741_FrameBuffer_get_color_depth_proto(mp_obj_t self_in) {
+ // The way displayio works depth is used to calculate bytes
+ // We use an uint32_t for color already so setting to 24 causes
+ // more changes required
+ return 32;
+}
+
+STATIC int is31fl3741_FrameBuffer_get_bytes_per_cell_proto(mp_obj_t self_in) {
+ return 1;
+}
+
+STATIC int is31fl3741_FrameBuffer_get_native_frames_per_second_proto(mp_obj_t self_in) {
+ return 60; // This was just chosen may vary based on LEDs used?
+}
+
+STATIC const framebuffer_p_t is31fl3741_FrameBuffer_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
+ .get_bufinfo = is31fl3741_FrameBuffer_get_bufinfo,
+ .set_brightness = is31fl3741_FrameBuffer_set_brightness_proto,
+ .get_brightness = is31fl3741_FrameBuffer_get_brightness_proto,
+ .get_width = is31fl3741_FrameBuffer_get_width_proto,
+ .get_height = is31fl3741_FrameBuffer_get_height_proto,
+ .get_color_depth = is31fl3741_FrameBuffer_get_color_depth_proto,
+ .get_bytes_per_cell = is31fl3741_FrameBuffer_get_bytes_per_cell_proto,
+ .get_native_frames_per_second = is31fl3741_FrameBuffer_get_native_frames_per_second_proto,
+ .swapbuffers = is31fl3741_FrameBuffer_swapbuffers,
+ .deinit = is31fl3741_FrameBuffer_deinit_proto,
+};
+
+STATIC mp_int_t is31fl3741_FrameBuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ is31fl3741_FrameBuffer_obj_t *self = (is31fl3741_FrameBuffer_obj_t *)self_in;
+ // a readonly framebuffer would be unusual but not impossible
+ if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
+ return 1;
+ }
+ *bufinfo = self->bufinfo;
+ bufinfo->typecode = 'H';
+ return 0;
+}
+
+const mp_obj_type_t is31fl3741_FrameBuffer_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_is31fl3741,
+ .locals_dict = (mp_obj_dict_t *)&is31fl3741_FrameBuffer_locals_dict,
+ .make_new = is31fl3741_FrameBuffer_make_new,
+ MP_TYPE_EXTENDED_FIELDS(
+ .buffer_p = { .get_buffer = is31fl3741_FrameBuffer_get_buffer, },
+ .protocol = &is31fl3741_FrameBuffer_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/is31fl3741/FrameBuffer.h b/circuitpython/shared-bindings/is31fl3741/FrameBuffer.h
new file mode 100644
index 0000000..704913b
--- /dev/null
+++ b/circuitpython/shared-bindings/is31fl3741/FrameBuffer.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mark Komus
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "shared-module/is31fl3741/FrameBuffer.h"
+#include "shared-module/is31fl3741/IS31FL3741.h"
+
+extern const mp_obj_type_t is31fl3741_FrameBuffer_type;
+
+void common_hal_is31fl3741_FrameBuffer_construct(is31fl3741_FrameBuffer_obj_t *self, int width, int height, mp_obj_t framebuffer, is31fl3741_IS31FL3741_obj_t *is31, mp_obj_t mapping);
+
+void common_hal_is31fl3741_FrameBuffer_deinit(is31fl3741_FrameBuffer_obj_t *);
+
+int common_hal_is31fl3741_FrameBuffer_get_width(is31fl3741_FrameBuffer_obj_t *self);
+int common_hal_is31fl3741_FrameBuffer_get_height(is31fl3741_FrameBuffer_obj_t *self);
+
+void common_hal_is31fl3741_FrameBuffer_set_global_current(is31fl3741_FrameBuffer_obj_t *self, uint8_t current);
+uint8_t common_hal_is31fl3741_FrameBuffer_get_global_current(is31fl3741_FrameBuffer_obj_t *self);
+
+void common_hal_is31fl3741_FrameBuffer_set_paused(is31fl3741_FrameBuffer_obj_t *self, bool paused);
+bool common_hal_is31fl3741_FrameBuffer_get_paused(is31fl3741_FrameBuffer_obj_t *self);
+void common_hal_is31fl3741_FrameBuffer_refresh(is31fl3741_FrameBuffer_obj_t *self, uint8_t *dirtyrows);
+
+void common_hal_is31fl3741_FrameBuffer_reconstruct(is31fl3741_FrameBuffer_obj_t *self, mp_obj_t framebuffer);
+
+void is31fl3741_FrameBuffer_collect_ptrs(is31fl3741_FrameBuffer_obj_t *self);
diff --git a/circuitpython/shared-bindings/is31fl3741/IS31FL3741.c b/circuitpython/shared-bindings/is31fl3741/IS31FL3741.c
new file mode 100644
index 0000000..46a7f8a
--- /dev/null
+++ b/circuitpython/shared-bindings/is31fl3741/IS31FL3741.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/objarray.h"
+
+#include "shared-bindings/is31fl3741/IS31FL3741.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-bindings/busio/I2C.h"
+
+//| class IS31FL3741:
+//| """Driver for an IS31FL3741 device."""
+//|
+//| def __init__(self, i2c: busio.I2C, *, addr: int = 0x30) -> None:
+//| """Create a IS31FL3741 object with the given attributes.
+//|
+//| Designed to work low level or passed to and object such as
+//| :class:`~is31fl3741.IS31FL3741_FrameBuffer`.
+//|
+//| :param ~busio.I2C i2c: I2C bus the IS31FL3741 is on
+//| :param int addr: device address"""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_i2c, ARG_addr };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_i2c, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_addr, MP_ARG_INT | MP_ARG_KW_ONLY, { .u_int = 0x30 } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus);
+
+ is31fl3741_IS31FL3741_obj_t *self = m_new_obj(is31fl3741_IS31FL3741_obj_t);
+ self->base.type = &is31fl3741_IS31FL3741_type;
+
+ common_hal_is31fl3741_IS31FL3741_construct(self,
+ MP_OBJ_TO_PTR(i2c),
+ args[ARG_addr].u_int
+ );
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Free the resources associated with this
+//| IS31FL3741 instance. After deinitialization, no further operations
+//| may be performed."""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_deinit(mp_obj_t self_in) {
+ is31fl3741_IS31FL3741_obj_t *self = (is31fl3741_IS31FL3741_obj_t *)self_in;
+ common_hal_is31fl3741_IS31FL3741_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_deinit_obj, is31fl3741_IS31FL3741_deinit);
+
+//| def reset(self) -> None:
+//| """Resets the IS31FL3741 chip."""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_reset(mp_obj_t self_in) {
+ is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_is31fl3741_send_reset(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_reset_obj, is31fl3741_IS31FL3741_reset);
+
+//| def enable(self) -> None:
+//| """Enables the IS31FL3741 chip."""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_enable(mp_obj_t self_in) {
+ is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_is31fl3741_send_enable(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(is31fl3741_IS31FL3741_enable_obj, is31fl3741_IS31FL3741_enable);
+
+//| def set_global_current(self, current: int) -> None:
+//| """Sets the global current of the IS31FL3741 chip.
+//|
+//| :param int current: global current value 0x00 to 0xFF"""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_set_global_current(mp_obj_t self_in, mp_obj_t value) {
+ is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t current = mp_obj_get_int(value);
+ common_hal_is31fl3741_set_current(self, current);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(is31fl3741_IS31FL3741_set_global_current_obj, is31fl3741_IS31FL3741_set_global_current);
+
+//| def set_led(self, led: int, value: int, page: int) -> None:
+//| """Resets the IS31FL3741 chip.
+//|
+//| :param int led: which LED to set
+//| :param int value: value to set the LED to 0x00 to 0xFF
+//| :param int page: page to write to 0 or 2. If the LED is a >= 180
+//| the routine will automatically write to page 1 or 3 (instead
+//| of 0 or 2)"""
+//| ...
+//|
+STATIC mp_obj_t is31fl3741_IS31FL3741_set_led(size_t n_args, const mp_obj_t *args) {
+ is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t led = mp_obj_get_int(args[1]);
+ mp_int_t value = mp_obj_get_int(args[2]);
+ mp_int_t page = mp_obj_get_int(args[3]);
+ common_hal_is31fl3741_set_led(self, led, value, page);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(is31fl3741_IS31FL3741_set_led_obj, 4, 4, is31fl3741_IS31FL3741_set_led);
+
+//| def write(mapping: Tuple[int, ...], buf: ReadableBuffer) -> None:
+//| """Write buf out on the I2C bus to the IS31FL3741.
+//|
+//| :param ~Tuple[int, ...] mapping: map the pixels in the buffer to the order addressed by the driver chip
+//| :param ~_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order"""
+//| ...
+STATIC mp_obj_t is31fl3741_IS31FL3741_write(mp_obj_t self_in, mp_obj_t mapping, mp_obj_t buffer) {
+ is31fl3741_IS31FL3741_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (!mp_obj_is_tuple_compatible(mapping)) {
+ mp_raise_ValueError(translate("Mapping must be a tuple"));
+ }
+
+ mp_obj_t *map_items;
+ size_t map_len;
+ mp_obj_tuple_get(mapping, &map_len, &map_items);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ);
+
+ common_hal_is31fl3741_write(self, map_items, (uint8_t *)bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(is31fl3741_IS31FL3741_write_obj, is31fl3741_IS31FL3741_write);
+
+STATIC const mp_rom_map_elem_t is31fl3741_IS31FL3741_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&is31fl3741_IS31FL3741_deinit_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&is31fl3741_IS31FL3741_write_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&is31fl3741_IS31FL3741_reset_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&is31fl3741_IS31FL3741_enable_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_set_global_current), (mp_obj_t)&is31fl3741_IS31FL3741_set_global_current_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_set_led), (mp_obj_t)&is31fl3741_IS31FL3741_set_led_obj },
+};
+STATIC MP_DEFINE_CONST_DICT(is31fl3741_IS31FL3741_locals_dict, is31fl3741_IS31FL3741_locals_dict_table);
+
+const mp_obj_type_t is31fl3741_IS31FL3741_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_is31fl3741,
+ .locals_dict = (mp_obj_dict_t *)&is31fl3741_IS31FL3741_locals_dict,
+ .make_new = is31fl3741_IS31FL3741_make_new,
+};
diff --git a/circuitpython/shared-bindings/is31fl3741/IS31FL3741.h b/circuitpython/shared-bindings/is31fl3741/IS31FL3741.h
new file mode 100644
index 0000000..2b81b01
--- /dev/null
+++ b/circuitpython/shared-bindings/is31fl3741/IS31FL3741.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mark Komus
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "shared-module/is31fl3741/IS31FL3741.h"
+
+extern const mp_obj_type_t is31fl3741_IS31FL3741_type;
+
+void common_hal_is31fl3741_IS31FL3741_construct(is31fl3741_IS31FL3741_obj_t *self, busio_i2c_obj_t *i2c, uint8_t addr);
+
+void common_hal_is31fl3741_IS31FL3741_deinit(is31fl3741_IS31FL3741_obj_t *);
+
+void common_hal_is31fl3741_write(is31fl3741_IS31FL3741_obj_t *is31, const mp_obj_t *mapping, const uint8_t *pixels, size_t numBytes);
+
+void common_hal_is31fl3741_begin_transaction(is31fl3741_IS31FL3741_obj_t *self);
+void common_hal_is31fl3741_end_transaction(is31fl3741_IS31FL3741_obj_t *self);
+
+void common_hal_is31fl3741_send_unlock(is31fl3741_IS31FL3741_obj_t *self);
+void common_hal_is31fl3741_set_page(is31fl3741_IS31FL3741_obj_t *self, uint8_t p);
+void common_hal_is31fl3741_send_enable(is31fl3741_IS31FL3741_obj_t *self);
+void common_hal_is31fl3741_send_reset(is31fl3741_IS31FL3741_obj_t *self);
+void common_hal_is31fl3741_set_current(is31fl3741_IS31FL3741_obj_t *self, uint8_t current);
+uint8_t common_hal_is31fl3741_get_current(is31fl3741_IS31FL3741_obj_t *self);
+void common_hal_is31fl3741_set_led(is31fl3741_IS31FL3741_obj_t *self, uint16_t led, uint8_t level, uint8_t page);
+void common_hal_is31fl3741_draw_pixel(is31fl3741_IS31FL3741_obj_t *self, int16_t x, int16_t y, uint32_t color, uint16_t *mapping);
diff --git a/circuitpython/shared-bindings/is31fl3741/__init__.c b/circuitpython/shared-bindings/is31fl3741/__init__.c
new file mode 100644
index 0000000..6058897
--- /dev/null
+++ b/circuitpython/shared-bindings/is31fl3741/__init__.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/busio/I2C.h"
+#include "shared-bindings/is31fl3741/IS31FL3741.h"
+#include "shared-bindings/is31fl3741/FrameBuffer.h"
+
+STATIC const mp_rom_map_elem_t is31fl3741_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_is31fl3741) },
+ { MP_ROM_QSTR(MP_QSTR_IS31FL3741), MP_ROM_PTR(&is31fl3741_IS31FL3741_type) },
+ { MP_ROM_QSTR(MP_QSTR_IS31FL3741_FrameBuffer), MP_ROM_PTR(&is31fl3741_FrameBuffer_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(is31fl3741_module_globals, is31fl3741_module_globals_table);
+
+const mp_obj_module_t is31fl3741_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&is31fl3741_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_is31fl3741, is31fl3741_module, CIRCUITPY_IS31FL3741);
diff --git a/circuitpython/shared-bindings/keypad/Event.c b/circuitpython/shared-bindings/keypad/Event.c
new file mode 100644
index 0000000..380b6b5
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Event.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/supervisor/__init__.h"
+
+//| class Event:
+//| """A key transition event."""
+//| def __init__(self, key_number: int=0, pressed: bool=True, timestamp:Optional[int]=None) -> None:
+//| """Create a key transition event, which reports a key-pressed or key-released transition.
+//|
+//| :param int key_number: The key number.
+//| :param bool pressed: ``True`` if the key was pressed; ``False`` if it was released.
+//| :param int timestamp: The time in milliseconds that the keypress occurred in the `supervisor.ticks_ms` time system. If specified as None, the current value of `supervisor.ticks_ms` is used.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_event_obj_t *self = m_new_obj(keypad_event_obj_t);
+ self->base.type = &keypad_event_type;
+ enum { ARG_key_number, ARG_pressed, ARG_timestamp };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_pressed, MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_timestamp, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mp_uint_t key_number =
+ (mp_uint_t)mp_arg_validate_int_min(args[ARG_key_number].u_int, 0, MP_QSTR_key_number);
+
+ mp_obj_t timestamp = args[ARG_timestamp].u_obj;
+ if (timestamp == mp_const_none) {
+ timestamp = supervisor_ticks_ms();
+ }
+
+ (void)mp_obj_get_int_truncated(timestamp); // ensure that timesamp is an integer
+ common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool, timestamp);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| key_number: int
+//| """The key number."""
+//|
+STATIC mp_obj_t keypad_event_get_key_number(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_number(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_number_obj, keypad_event_get_key_number);
+
+MP_PROPERTY_GETTER(keypad_event_key_number_obj,
+ (mp_obj_t)&keypad_event_get_key_number_obj);
+
+//| pressed: bool
+//| """``True`` if the event represents a key down (pressed) transition.
+//| The opposite of `released`.
+//| """
+//|
+STATIC mp_obj_t keypad_event_get_pressed(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_event_get_pressed(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_get_pressed);
+
+MP_PROPERTY_GETTER(keypad_event_pressed_obj,
+ (mp_obj_t)&keypad_event_get_pressed_obj);
+
+//| released: bool
+//| """``True`` if the event represents a key up (released) transition.
+//| The opposite of `pressed`.
+//| """
+//|
+STATIC mp_obj_t keypad_event_get_released(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_event_get_released(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_get_released);
+
+MP_PROPERTY_GETTER(keypad_event_released_obj,
+ (mp_obj_t)&keypad_event_get_released_obj);
+
+//| timestamp: int
+//| """The timestamp."""
+//|
+STATIC mp_obj_t keypad_event_get_timestamp(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_keypad_event_get_timestamp(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_timestamp_obj, keypad_event_get_timestamp);
+
+MP_PROPERTY_GETTER(keypad_event_timestamp_obj,
+ (mp_obj_t)&keypad_event_get_timestamp_obj);
+
+
+//| def __eq__(self, other: object) -> bool:
+//| """Two `Event` objects are equal if their `key_number`
+//| and `pressed`/`released` values are equal.
+//| Note that this does not compare the event timestamps.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ switch (op) {
+ case MP_BINARY_OP_EQUAL:
+ if (mp_obj_is_type(rhs_in, &keypad_event_type)) {
+ keypad_event_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in);
+ keypad_event_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in);
+ return mp_obj_new_bool(
+ (common_hal_keypad_event_get_key_number(lhs) ==
+ common_hal_keypad_event_get_key_number(rhs)) &&
+ (common_hal_keypad_event_get_pressed(lhs) ==
+ common_hal_keypad_event_get_pressed(rhs))
+ );
+ } else {
+ return mp_const_false;
+ }
+
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the `Event`, so it can be used in dictionaries, etc..
+//|
+//| Note that as events with different timestamps compare equal, they also hash to the same value."""
+//| ...
+//|
+STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_HASH: {
+ const mp_int_t key_number = common_hal_keypad_event_get_key_number(self);
+ const bool pressed = common_hal_keypad_event_get_pressed(self);
+ return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_number);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "<Event: key_number %d %s>",
+ common_hal_keypad_event_get_key_number(self),
+ common_hal_keypad_event_get_pressed(self) ? "pressed" : "released");
+}
+
+STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_key_number), MP_ROM_PTR(&keypad_event_key_number_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&keypad_event_timestamp_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table);
+
+const mp_obj_type_t keypad_event_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Event,
+ .make_new = keypad_event_make_new,
+ .print = keypad_event_print,
+ .locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = keypad_event_unary_op,
+ .binary_op = keypad_event_binary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/keypad/Event.h b/circuitpython/shared-bindings/keypad/Event.h
new file mode 100644
index 0000000..44e6929
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Event.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
+
+#include "py/obj.h"
+#include "shared-module/keypad/Event.h"
+
+extern const mp_obj_type_t keypad_event_type;
+
+void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_number, bool pressed, mp_obj_t timestamp);
+mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self);
+bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self);
+bool common_hal_keypad_event_get_released(keypad_event_obj_t *self);
+mp_obj_t common_hal_keypad_event_get_timestamp(keypad_event_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
diff --git a/circuitpython/shared-bindings/keypad/EventQueue.c b/circuitpython/shared-bindings/keypad/EventQueue.c
new file mode 100644
index 0000000..8e45f7a
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/EventQueue.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/EventQueue.h"
+
+//| class EventQueue:
+//| """A queue of `Event` objects, filled by a `keypad` scanner such as `Keys` or `KeyMatrix`.
+//|
+//| You cannot create an instance of `EventQueue` directly. Each scanner creates an
+//| instance when it is created.
+//| """
+//| ...
+
+//| def get(self) -> Optional[Event]:
+//| """Return the next key transition event. Return ``None`` if no events are pending.
+//|
+//| Note that the queue size is limited; see ``max_events`` in the constructor of
+//| a scanner such as `Keys` or `KeyMatrix`.
+//| If a new event arrives when the queue is full, the event is discarded, and
+//| `overflowed` is set to ``True``.
+//|
+//| :return: The next queued key transition `Event`.
+//| :rtype: Optional[Event]
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_get(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_keypad_eventqueue_get(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_obj, keypad_eventqueue_get);
+
+//| def get_into(self, event: Event) -> bool:
+//| """Store the next key transition event in the supplied event, if available,
+//| and return ``True``.
+//| If there are no queued events, do not touch ``event`` and return ``False``.
+//|
+//| The advantage of this method over ``get()`` is that it does not allocate storage.
+//| Instead you can reuse an existing ``Event`` object.
+//|
+//| Note that the queue size is limited; see ``max_events`` in the constructor of
+//| a scanner such as `Keys` or `KeyMatrix`.
+//|
+//| :return: ``True`` if an event was available and stored, ``False`` if not.
+//| :rtype: bool
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_get_into(mp_obj_t self_in, mp_obj_t event_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ keypad_event_obj_t *event = MP_OBJ_TO_PTR(mp_arg_validate_type(event_in, &keypad_event_type, MP_QSTR_event));
+
+ return mp_obj_new_bool(common_hal_keypad_eventqueue_get_into(self, event));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_get_into_obj, keypad_eventqueue_get_into);
+
+//| def clear(self) -> None:
+//| """Clear any queued key transition events. Also sets `overflowed` to ``False``.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_clear(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_eventqueue_clear(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_clear_obj, keypad_eventqueue_clear);
+
+//| def __bool__(self) -> bool:
+//| """``True`` if `len()` is greater than zero.
+//| This is an easy way to check if the queue is empty.
+//| """
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Return the number of events currently in the queue. Used to implement ``len()``."""
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint16_t len = common_hal_keypad_eventqueue_get_length(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| overflowed: bool
+//| """``True`` if an event could not be added to the event queue because it was full. (read-only)
+//| Set to ``False`` by `clear()`.
+//| """
+//|
+STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_eventqueue_get_overflowed(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_overflowed_obj, keypad_eventqueue_get_overflowed);
+
+MP_PROPERTY_GETTER(keypad_eventqueue_overflowed_obj,
+ (mp_obj_t)&keypad_eventqueue_get_overflowed_obj);
+
+STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&keypad_eventqueue_get_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_into), MP_ROM_PTR(&keypad_eventqueue_get_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_overflowed), MP_ROM_PTR(&keypad_eventqueue_overflowed_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table);
+
+const mp_obj_type_t keypad_eventqueue_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_EventQueue,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = keypad_eventqueue_unary_op,
+ ),
+ .locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/EventQueue.h b/circuitpython/shared-bindings/keypad/EventQueue.h
new file mode 100644
index 0000000..fbbd9df
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/EventQueue.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
+
+#include "shared-module/keypad/Event.h"
+#include "shared-module/keypad/EventQueue.h"
+
+extern const mp_obj_type_t keypad_eventqueue_type;
+
+void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events);
+
+void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self);
+size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self);
+mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self);
+bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event);
+
+bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self);
+void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
diff --git a/circuitpython/shared-bindings/keypad/KeyMatrix.c b/circuitpython/shared-bindings/keypad/KeyMatrix.c
new file mode 100644
index 0000000..9e65471
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/KeyMatrix.c
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/KeyMatrix.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class KeyMatrix:
+//| """Manage a 2D matrix of keys with row and column pins."""
+//|
+//| def __init__(self, row_pins: Sequence[microcontroller.Pin], column_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan the key matrix attached to the given row and column pins.
+//| There should not be any external pull-ups or pull-downs on the matrix:
+//| ``KeyMatrix`` enables internal pull-ups or pull-downs on the pins as necessary.
+//|
+//| The keys are numbered sequentially from zero. A key number can be computed
+//| by ``row * len(column_pins) + column``.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows.
+//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the colums.
+//| :param bool columns_to_anodes: Default ``True``.
+//| If the matrix uses diodes, the diode anodes are typically connected to the column pins,
+//| and the cathodes should be connected to the row pins. If your diodes are reversed,
+//| set ``columns_to_anodes`` to ``False``.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t);
+ self->base.type = &keypad_keymatrix_type;
+ enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t row_pins = args[ARG_row_pins].u_obj;
+ // mp_obj_len() will be >= 0.
+ const size_t num_row_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_pins));
+
+ mp_obj_t column_pins = args[ARG_column_pins].u_obj;
+ const size_t num_column_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(column_pins));
+
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ const mcu_pin_obj_t *row_pins_array[num_row_pins];
+ const mcu_pin_obj_t *column_pins_array[num_column_pins];
+
+ validate_no_duplicate_pins_2(row_pins, column_pins, MP_QSTR_row_pins, MP_QSTR_column_pins);
+
+ for (size_t row = 0; row < num_row_pins; row++) {
+ const mcu_pin_obj_t *pin =
+ validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(row), MP_OBJ_SENTINEL));
+ row_pins_array[row] = pin;
+ }
+
+ for (size_t column = 0; column < num_column_pins; column++) {
+ const mcu_pin_obj_t *pin =
+ validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL));
+ column_pins_array[column] = pin;
+ }
+
+ common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_deinit(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_keypad_keymatrix_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_deinit_obj, keypad_keymatrix_deinit);
+
+//| def __enter__(self) -> KeyMatrix:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_keymatrix_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keymatrix___exit___obj, 4, 4, keypad_keymatrix___exit__);
+
+STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) {
+ if (common_hal_keypad_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| def key_number_to_row_column(self, key_number: int) -> Tuple[int]:
+//| """Return the row and column for the given key number.
+//| The row is ``key_number // len(column_pins)``.
+//| The column is ``key_number % len(column_pins)``.
+//|
+//| :return: ``(row, column)``
+//| :rtype: Tuple[int]
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_key_number_to_row_column(mp_obj_t self_in, mp_obj_t key_number_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(key_number_in),
+ 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self),
+ MP_QSTR_key_number);
+
+ mp_uint_t row;
+ mp_uint_t column;
+ common_hal_keypad_keymatrix_key_number_to_row_column(self, key_number, &row, &column);
+
+ mp_obj_t row_column[2];
+ row_column[0] = MP_OBJ_NEW_SMALL_INT(row);
+ row_column[1] = MP_OBJ_NEW_SMALL_INT(column);
+
+ return mp_obj_new_tuple(2, row_column);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_key_number_to_row_column_obj, keypad_keymatrix_key_number_to_row_column);
+
+//| def row_column_to_key_number(self, row: int, column: int) -> int:
+//| """Return the key number for a given row and column.
+//| The key number is ``row * len(column_pins) + column``.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t column_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self), MP_QSTR_row);
+
+ const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self), MP_QSTR_column);
+
+ return MP_OBJ_NEW_SMALL_INT(
+ (mp_int_t)common_hal_keypad_keymatrix_row_column_to_key_number(self, row, column));
+}
+MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_keymatrix_row_column_to_key_number);
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_keymatrix_key_number_to_row_column_obj) },
+ { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table);
+
+const mp_obj_type_t keypad_keymatrix_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_KeyMatrix,
+ .make_new = keypad_keymatrix_make_new,
+ .locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/KeyMatrix.h b/circuitpython/shared-bindings/keypad/KeyMatrix.h
new file mode 100644
index 0000000..bdf77dd
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/KeyMatrix.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/KeyMatrix.h"
+
+extern const mp_obj_type_t keypad_keymatrix_type;
+
+void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self);
+
+void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column);
+mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column);
+
+size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self);
+size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
diff --git a/circuitpython/shared-bindings/keypad/Keys.c b/circuitpython/shared-bindings/keypad/Keys.c
new file mode 100644
index 0000000..6ac705e
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Keys.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/Keys.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class Keys:
+//| """Manage a set of independent keys."""
+//|
+//| def __init__(self, pins: Sequence[microcontroller.Pin], *, value_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan keys attached to the given sequence of pins.
+//| Each key is independent and attached to its own pin.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys.
+//| The key numbers correspond to indices into this sequence.
+//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
+//| ``False`` if the pin reads low (is grounded) when the key is pressed.
+//| All the pins must be connected in the same way.
+//| :param bool pull: ``True`` if an internal pull-up or pull-down should be
+//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``;
+//| a pull-down will be used if it is ``True``.
+//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``.
+//| However, enabling an internal pull when an external one is already present is not a problem;
+//| it simply uses slightly more current.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t);
+ self->base.type = &keypad_keys_type;
+ enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
+ { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t pins = args[ARG_pins].u_obj;
+ validate_no_duplicate_pins(pins, MP_QSTR_row_pins);
+ // mp_obj_len() will be >= 0.
+ const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins));
+
+ const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ const mcu_pin_obj_t *pins_array[num_pins];
+
+ for (mp_uint_t i = 0; i < num_pins; i++) {
+ pins_array[i] =
+ validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
+ }
+
+ common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keys_deinit(mp_obj_t self_in) {
+ keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_keys_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_deinit_obj, keypad_keys_deinit);
+
+//| def __enter__(self) -> Keys:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keys___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_keys_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keys___exit___obj, 4, 4, keypad_keys___exit__);
+
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table);
+
+const mp_obj_type_t keypad_keys_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Keys,
+ .make_new = keypad_keys_make_new,
+ .locals_dict = (mp_obj_t)&keypad_keys_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/Keys.h b/circuitpython/shared-bindings/keypad/Keys.h
new file mode 100644
index 0000000..eb833b9
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Keys.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/Keys.h"
+
+extern const mp_obj_type_t keypad_keys_type;
+
+void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
diff --git a/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c
new file mode 100644
index 0000000..14ab874
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/ShiftRegisterKeys.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class ShiftRegisterKeys:
+//| """Manage a set of keys attached to an incoming shift register."""
+//|
+//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, key_count: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register
+//| like the 74HC165 or CD4021.
+//| Note that you may chain shift registers to load in as many values as you need.
+//|
+//| Key number 0 is the first (or more properly, the zero-th) bit read. In the
+//| 74HC165, this bit is labeled ``Q7``. Key number 1 will be the value of ``Q6``, etc.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param microcontroller.Pin clock: The shift register clock pin.
+//| The shift register should clock on a low-to-high transition.
+//| :param microcontroller.Pin data: the incoming shift register data pin
+//| :param microcontroller.Pin latch:
+//| Pin used to latch parallel data going into the shift register.
+//| :param bool value_to_latch: Pin state to latch data being read.
+//| ``True`` if the data is latched when ``latch`` goes high
+//| ``False`` if the data is latched when ``latch`` goes low.
+//| The default is ``True``, which is how the 74HC165 operates. The CD4021 latch is the opposite.
+//| Once the data is latched, it will be shifted out by toggling the clock pin.
+//| :param int key_count: number of data lines to clock in
+//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
+//| ``False`` if the pin reads low (is grounded) when the key is pressed.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t);
+ self->base.type = &keypad_shiftregisterkeys_type;
+ enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_value_to_latch, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_key_count, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj);
+ const mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj);
+ const bool value_to_latch = args[ARG_value_to_latch].u_bool;
+
+ const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count);
+ const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ common_hal_keypad_shiftregisterkeys_construct(
+ self, clock, data, latch, value_to_latch, key_count, value_when_pressed, interval, max_events);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_shiftregisterkeys_deinit(mp_obj_t self_in) {
+ keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_shiftregisterkeys_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_deinit_obj, keypad_shiftregisterkeys_deinit);
+
+//| def __enter__(self) -> Keys:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_shiftregisterkeys___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_shiftregisterkeys_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_shiftregisterkeys___exit___obj, 4, 4, keypad_shiftregisterkeys___exit__);
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_shiftregisterkeys_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table);
+
+const mp_obj_type_t keypad_shiftregisterkeys_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ShiftRegisterKeys,
+ .make_new = keypad_shiftregisterkeys_make_new,
+ .locals_dict = (mp_obj_t)&keypad_shiftregisterkeys_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h
new file mode 100644
index 0000000..bc91c78
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/ShiftRegisterKeys.h"
+
+extern const mp_obj_type_t keypad_shiftregisterkeys_type;
+
+void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
diff --git a/circuitpython/shared-bindings/keypad/__init__.c b/circuitpython/shared-bindings/keypad/__init__.c
new file mode 100644
index 0000000..97db750
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/__init__.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2011 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/EventQueue.h"
+#include "shared-bindings/keypad/KeyMatrix.h"
+#include "shared-bindings/keypad/Keys.h"
+#include "shared-bindings/keypad/ShiftRegisterKeys.h"
+#include "shared-bindings/util.h"
+
+STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) {
+ if (common_hal_keypad_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+STATIC mp_obj_t keypad_generic_reset(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_keypad_generic_reset(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_reset_obj, keypad_generic_reset);
+
+STATIC mp_obj_t keypad_generic_get_key_count(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_generic_get_key_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_get_key_count_obj, keypad_generic_get_key_count);
+
+const mp_obj_property_t keypad_generic_key_count_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&keypad_generic_get_key_count_obj,
+ MP_ROM_NONE,
+ MP_ROM_NONE},
+};
+
+STATIC mp_obj_t keypad_generic_get_events(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return common_hal_keypad_generic_get_events(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_get_events_obj, keypad_generic_get_events);
+
+const mp_obj_property_t keypad_generic_events_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&keypad_generic_get_events_obj,
+ MP_ROM_NONE,
+ MP_ROM_NONE},
+};
+
+
+//| """Support for scanning keys and key matrices
+//|
+//| The `keypad` module provides native support to scan sets of keys or buttons,
+//| connected independently to individual pins,
+//| connected to a shift register,
+//| or connected in a row-and-column matrix.
+//| """
+//|
+
+STATIC mp_rom_map_elem_t keypad_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) },
+ { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) },
+ { MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) },
+ { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) },
+ { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) },
+ { MP_ROM_QSTR(MP_QSTR_ShiftRegisterKeys), MP_OBJ_FROM_PTR(&keypad_shiftregisterkeys_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_module_globals, keypad_module_globals_table);
+
+const mp_obj_module_t keypad_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&keypad_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_keypad, keypad_module, CIRCUITPY_KEYPAD);
diff --git a/circuitpython/shared-bindings/keypad/__init__.h b/circuitpython/shared-bindings/keypad/__init__.h
new file mode 100644
index 0000000..eb3b16a
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/__init__.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_BINDINGS_KEYPAD_H
+#define SHARED_BINDINGS_KEYPAD_H
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "shared-module/keypad/__init__.h"
+
+bool common_hal_keypad_deinited(void *self);
+void common_hal_keypad_generic_reset(void *self);
+size_t common_hal_keypad_generic_get_key_count(void *self);
+mp_obj_t common_hal_keypad_generic_get_events(void *self);
+
+MP_DECLARE_CONST_FUN_OBJ_1(keypad_generic_reset_obj);
+
+extern const mp_obj_property_t keypad_generic_events_obj;
+extern const mp_obj_property_t keypad_generic_key_count_obj;
+
+#endif // SHARED_BINDINGS_KEYPAD_H
diff --git a/circuitpython/shared-bindings/math/__init__.c b/circuitpython/shared-bindings/math/__init__.c
new file mode 100644
index 0000000..54dbf00
--- /dev/null
+++ b/circuitpython/shared-bindings/math/__init__.c
@@ -0,0 +1,479 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2017 Michael McWethy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/builtin.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+#if MICROPY_PY_BUILTINS_FLOAT
+
+#include <math.h>
+
+// M_PI is not part of the math.h standard and may not be defined
+// And by defining our own we can ensure it uses the correct const format.
+#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
+
+
+//| """mathematical functions
+//|
+//| The `math` module provides some basic mathematical functions for
+//| working with floating-point numbers.
+//|
+//| |see_cpython_module| :mod:`cpython:math`.
+//| """
+//|
+
+STATIC NORETURN void math_error(void) {
+ mp_raise_ValueError(translate("math domain error"));
+}
+
+#define MATH_FUN_1(py_name, c_name) \
+ STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
+
+#define MATH_FUN_2(py_name, c_name) \
+ STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_float(y_obj))); } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);
+
+#define MATH_FUN_1_TO_BOOL(py_name, c_name) \
+ STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
+
+#define MATH_FUN_1_TO_INT(py_name, c_name) \
+ STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
+
+#define MATH_FUN_1_ERRCOND(py_name, c_name, error_condition) \
+ STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { \
+ mp_float_t x = mp_obj_get_float(x_obj); \
+ if (error_condition) { \
+ math_error(); \
+ } \
+ return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(x)); \
+ } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
+
+#ifdef MP_NEED_LOG2
+// 1.442695040888963407354163704 is 1/_M_LN2
+#define log2(x) (log(x) * 1.442695040888963407354163704)
+#endif
+
+//| e: float
+//| """base of the natural logarithm"""
+//|
+//| pi: float
+//| """the ratio of a circle's circumference to its diameter"""
+//|
+
+//| def acos(x: float) -> float:
+//| """Return the inverse cosine of ``x``."""
+//| ...
+//|
+//| def asin(x: float) -> float:
+//| """Return the inverse sine of ``x``."""
+//| ...
+//|
+//| def atan(x: float) -> float:
+//| """Return the inverse tangent of ``x``."""
+//| ...
+//|
+//| def atan2(y: float, x: float) -> float:
+//| """Return the principal value of the inverse tangent of ``y/x``."""
+//| ...
+//|
+//| def ceil(x: float) -> int:
+//| """Return an integer, being ``x`` rounded towards positive infinity."""
+//| ...
+//|
+//| def copysign(x: float, y: float) -> float:
+//| """Return ``x`` with the sign of ``y``."""
+//| ...
+//|
+//| def cos(x: float) -> float:
+//| """Return the cosine of ``x``."""
+//| ...
+//|
+//| def degrees(x: float) -> float:
+//| """Return radians ``x`` converted to degrees."""
+//| ...
+//|
+//| def exp(x: float) -> float:
+//| """Return the exponential of ``x``."""
+//| ...
+//|
+//| def fabs(x: float) -> float:
+//| """Return the absolute value of ``x``."""
+//| ...
+//|
+//| def floor(x: float) -> int:
+//| """Return an integer, being ``x`` rounded towards negative infinity."""
+//| ...
+//|
+//| def fmod(x: float, y: float) -> int:
+//| """Return the remainder of ``x/y``."""
+//| ...
+//|
+//| def frexp(x: float) -> Tuple[int, int]:
+//| """Decomposes a floating-point number into its mantissa and exponent.
+//| The returned value is the tuple ``(m, e)`` such that ``x == m * 2**e``
+//| exactly. If ``x == 0`` then the function returns ``(0.0, 0)``, otherwise
+//| the relation ``0.5 <= abs(m) < 1`` holds."""
+//| ...
+//|
+//| def isfinite(x: float) -> bool:
+//| """Return ``True`` if ``x`` is finite."""
+//| ...
+//|
+//| def isinf(x: float) -> bool:
+//| """Return ``True`` if ``x`` is infinite."""
+//| ...
+//|
+//| def isnan(x: float) -> bool:
+//| """Return ``True`` if ``x`` is not-a-number"""
+//| ...
+//|
+//| def ldexp(x: float, exp: float) -> float:
+//| """Return ``x * (2**exp)``."""
+//| ...
+//|
+//| def log(x: float, base: float = e) -> float:
+//| """Return the logarithm of x to the given base. If base is not specified,
+//| returns the natural logarithm (base e) of x"""
+//| ...
+//|
+//| def modf(x: float) -> Tuple[float, float]:
+//| """Return a tuple of two floats, being the fractional and integral parts of
+//| ``x``. Both return values have the same sign as ``x``."""
+//| ...
+//|
+//| def pow(x: float, y: float) -> float:
+//| """Returns ``x`` to the power of ``y``."""
+//|
+//| def radians(x: float) -> float:
+//| """Return degrees ``x`` converted to radians."""
+//|
+//| def sin(x: float) -> float:
+//| """Return the sine of ``x``."""
+//| ...
+//|
+//| def sqrt(x: float) -> float:
+//| """Returns the square root of ``x``."""
+//| ...
+//|
+//| def tan(x: float) -> float:
+//| """Return the tangent of ``x``."""
+//| ...
+//|
+//| def trunc(x: float) -> int:
+//| """Return an integer, being ``x`` rounded towards 0."""
+//| ...
+//|
+MATH_FUN_1_ERRCOND(sqrt, sqrt, (x < (mp_float_t)0.0))
+
+MATH_FUN_2(pow, pow)
+
+MATH_FUN_1(exp, exp)
+#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
+//| def expm1(x: float) -> float:
+//| """Return ``exp(x) - 1``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(expm1, expm1)
+
+//| def log2(x: float) -> float:
+//| """Return the base-2 logarithm of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0))
+
+//| def log10(x: float) -> float:
+//| """Return the base-10 logarithm of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0))
+
+//| def cosh(x: float) -> float:
+//| """Return the hyperbolic cosine of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(cosh, cosh)
+
+//| def sinh(x: float) -> float:
+//| """Return the hyperbolic sine of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(sinh, sinh)
+
+//| def tanh(x: float) -> float:
+//| """Return the hyperbolic tangent of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(tanh, tanh)
+
+//| def acosh(x: float) -> float:
+//| """Return the inverse hyperbolic cosine of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(acosh, acosh)
+
+//| def asinh(x: float) -> float:
+//| """Return the inverse hyperbolic sine of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(asinh, asinh)
+
+//| def atanh(x: float) -> float:
+//| """Return the inverse hyperbolic tangent of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(atanh, atanh)
+#endif
+
+MATH_FUN_1(cos, cos)
+
+MATH_FUN_1(sin, sin)
+
+MATH_FUN_1(tan, tan)
+
+MATH_FUN_1(acos, acos)
+
+MATH_FUN_1(asin, asin)
+
+MATH_FUN_1(atan, atan)
+
+MATH_FUN_2(atan2, atan2)
+
+MATH_FUN_1_TO_INT(ceil, ceil)
+
+MATH_FUN_2(copysign, copysign)
+
+MATH_FUN_1(fabs, fabs)
+
+MATH_FUN_1_TO_INT(floor, floor) // TODO: delegate to x.__floor__() if x is not a float
+
+MATH_FUN_2(fmod, fmod)
+
+MATH_FUN_1_TO_BOOL(isfinite, isfinite)
+
+MATH_FUN_1_TO_BOOL(isinf, isinf)
+
+MATH_FUN_1_TO_BOOL(isnan, isnan)
+
+MATH_FUN_1_TO_INT(trunc, trunc)
+
+MATH_FUN_2(ldexp, ldexp)
+#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
+
+//| def erf(x: float) -> float:
+//| """Return the error function of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(erf, erf)
+
+//| def erfc(x: float) -> float:
+//| """Return the complementary error function of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(erfc, erfc)
+
+//| def gamma(x: float) -> float:
+//| """Return the gamma function of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(gamma, tgamma)
+
+//| def lgamma(x: float) -> float:
+//| """Return the natural logarithm of the gamma function of ``x``.
+//|
+//| May not be available on some boards.
+//| """
+//| ...
+//|
+MATH_FUN_1(lgamma, lgamma)
+#endif
+// TODO: factorial, fsum
+
+// Function that takes a variable number of arguments
+
+// log(x[, base])
+STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) {
+ mp_float_t x = mp_obj_get_float(args[0]);
+ if (x <= (mp_float_t)0.0) {
+ math_error();
+ }
+ mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x);
+ if (n_args == 1) {
+ return mp_obj_new_float(l);
+ } else {
+ mp_float_t base = mp_obj_get_float(args[1]);
+ if (base <= (mp_float_t)0.0) {
+ math_error();
+// Turn off warning when comparing exactly with integral value 1.0
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wfloat-equal"
+ } else if (base == (mp_float_t)1.0) {
+ #pragma GCC diagnostic pop
+ mp_raise_msg(&mp_type_ZeroDivisionError, translate("division by zero"));
+ }
+ return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base));
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log);
+
+// Functions that return a tuple
+
+
+STATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
+ int int_exponent = 0;
+ mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
+ mp_obj_t tuple[2];
+ tuple[0] = mp_obj_new_float(significand);
+ tuple[1] = mp_obj_new_int(int_exponent);
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
+
+STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {
+ mp_float_t int_part = 0.0;
+ mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
+ mp_obj_t tuple[2];
+ tuple[0] = mp_obj_new_float(fractional_part);
+ tuple[1] = mp_obj_new_float(int_part);
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
+
+// Angular conversions
+
+
+STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) {
+ return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0)));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
+
+
+STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
+ return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees);
+
+STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) },
+ { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },
+ { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },
+ { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) },
+ { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) },
+ #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
+ { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) },
+ #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
+ { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) },
+ { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) },
+ { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) },
+ { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) },
+ { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) },
+ { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) },
+ { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) },
+ { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) },
+ { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) },
+ #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
+ { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) },
+ { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) },
+ { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) },
+ { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table);
+
+const mp_obj_module_t math_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_math_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_math, math_module, CIRCUITPY_MATH);
+
+#endif // MICROPY_PY_BUILTINS_FLOAT
diff --git a/circuitpython/shared-bindings/mdns/RemoteService.c b/circuitpython/shared-bindings/mdns/RemoteService.c
new file mode 100644
index 0000000..846207b
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/RemoteService.c
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/RemoteService.h"
+
+//| class RemoteService:
+//| """Encapsulates information about a remote service that was found during a search. This
+//| object may only be created by a `mdns.Server`. It has no user-visible constructor."""
+//|
+
+//| def __init__(self) -> None:
+//| """Cannot be instantiated directly. Use `mdns.Server.find`."""
+//| ...
+//|
+
+//| hostname: str
+//| """The hostname of the device (read-only),."""
+//|
+STATIC mp_obj_t mdns_remoteservice_get_hostname(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *hostname = common_hal_mdns_remoteservice_get_hostname(self);
+ return mp_obj_new_str(hostname, strlen(hostname));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_hostname_obj, mdns_remoteservice_get_hostname);
+
+MP_PROPERTY_GETTER(mdns_remoteservice_hostname_obj,
+ (mp_obj_t)&mdns_remoteservice_get_hostname_obj);
+
+//| instance_name: str
+//| """The human readable instance name for the service. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_instance_name(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *instance_name = common_hal_mdns_remoteservice_get_instance_name(self);
+ return mp_obj_new_str(instance_name, strlen(instance_name));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_instance_name_obj, remoteservice_get_instance_name);
+
+MP_PROPERTY_GETTER(mdns_remoteservice_instance_name_obj,
+ (mp_obj_t)&mdns_remoteservice_get_instance_name_obj);
+
+//| service_type: str
+//| """The service type string such as ``_http``. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_service_type(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *service_type = common_hal_mdns_remoteservice_get_service_type(self);
+ return mp_obj_new_str(service_type, strlen(service_type));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_service_type_obj, remoteservice_get_service_type);
+
+MP_PROPERTY_GETTER(mdns_remoteservice_service_type_obj,
+ (mp_obj_t)&mdns_remoteservice_get_service_type_obj);
+
+//| protocol: str
+//| """The protocol string such as ``_tcp``. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_protocol(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *protocol = common_hal_mdns_remoteservice_get_protocol(self);
+ return mp_obj_new_str(protocol, strlen(protocol));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_protocol_obj, remoteservice_get_protocol);
+
+MP_PROPERTY_GETTER(mdns_remoteservice_protocol_obj,
+ (mp_obj_t)&mdns_remoteservice_get_protocol_obj);
+
+//| port: int
+//| """Port number used for the service. (read-only)"""
+//|
+STATIC mp_obj_t remoteservice_get_port(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_mdns_remoteservice_get_port(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_port_obj, remoteservice_get_port);
+
+MP_PROPERTY_GETTER(mdns_remoteservice_port_obj,
+ (mp_obj_t)&mdns_remoteservice_get_port_obj);
+
+//| def __del__(self) -> None:
+//| """Deletes the RemoteService object."""
+//| ...
+//|
+STATIC mp_obj_t mdns_remoteservice_obj_deinit(mp_obj_t self_in) {
+ mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_mdns_remoteservice_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_deinit_obj, mdns_remoteservice_obj_deinit);
+
+STATIC const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mdns_remoteservice_hostname_obj) },
+ { MP_ROM_QSTR(MP_QSTR_instance_name), MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) },
+ { MP_ROM_QSTR(MP_QSTR_service_type), MP_ROM_PTR(&mdns_remoteservice_service_type_obj) },
+ { MP_ROM_QSTR(MP_QSTR_protocol), MP_ROM_PTR(&mdns_remoteservice_protocol_obj) },
+ { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&mdns_remoteservice_port_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mdns_remoteservice_deinit_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_remoteservice_locals_dict, mdns_remoteservice_locals_dict_table);
+
+const mp_obj_type_t mdns_remoteservice_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RemoteService,
+ .locals_dict = (mp_obj_dict_t *)&mdns_remoteservice_locals_dict
+};
diff --git a/circuitpython/shared-bindings/mdns/RemoteService.h b/circuitpython/shared-bindings/mdns/RemoteService.h
new file mode 100644
index 0000000..f751b68
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/RemoteService.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+#include "common-hal/mdns/RemoteService.h"
+
+extern const mp_obj_type_t mdns_remoteservice_type;
+
+const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self);
+const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self);
+mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self);
+void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self);
diff --git a/circuitpython/shared-bindings/mdns/Server.c b/circuitpython/shared-bindings/mdns/Server.c
new file mode 100644
index 0000000..b5e6c11
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/Server.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/__init__.h"
+#include "shared-bindings/mdns/Server.h"
+#include "shared-bindings/util.h"
+
+//| class Server:
+//| """The MDNS Server responds to queries for this device's information and allows for querying
+//| other devices."""
+//|
+
+//| def __init__(self, network_interface: wifi.Radio) -> None:
+//| """
+//| Constructs or returns the mdns.Server for the given network_interface. (CircuitPython
+//| may already be using it.) Only native interfaces are currently supported.
+//| """
+//| ...
+//|
+STATIC mp_obj_t mdns_server_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_network_interface };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_network_interface, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mdns_server_obj_t *self = m_new_obj(mdns_server_obj_t);
+ self->base.type = &mdns_server_type;
+ common_hal_mdns_server_construct(self, args[ARG_network_interface].u_obj);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stops the server"""
+//| ...
+//|
+STATIC mp_obj_t mdns_server_obj_deinit(mp_obj_t self_in) {
+ mdns_server_obj_t *self = (mdns_server_obj_t *)self_in;
+ common_hal_mdns_server_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_deinit_obj, mdns_server_obj_deinit);
+
+STATIC void check_for_deinit(mdns_server_obj_t *self) {
+ if (common_hal_mdns_server_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//|
+//| hostname: str
+//| """Hostname resolvable as ``<hostname>.local`` in addition to ``circuitpython.local``. Make
+//| sure this is unique across all devices on the network. It defaults to ``cpy-######``
+//| where ``######`` is the hex digits of the last three bytes of the mac address."""
+//|
+STATIC mp_obj_t mdns_server_get_hostname(mp_obj_t self) {
+ check_for_deinit(self);
+ const char *hostname = common_hal_mdns_server_get_hostname(self);
+ return mp_obj_new_str(hostname, strlen(hostname));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_get_hostname_obj, mdns_server_get_hostname);
+
+static mp_obj_t mdns_server_set_hostname(mp_obj_t self, mp_obj_t hostname) {
+ check_for_deinit(self);
+ common_hal_mdns_server_set_hostname(self, mp_obj_str_get_str(hostname));
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mdns_server_set_hostname_obj, mdns_server_set_hostname);
+
+MP_PROPERTY_GETSET(mdns_server_hostname_obj,
+ (mp_obj_t)&mdns_server_get_hostname_obj,
+ (mp_obj_t)&mdns_server_set_hostname_obj);
+
+//| instance_name: str
+//| """Human readable name to describe the device."""
+//|
+STATIC mp_obj_t mdns_server_get_instance_name(mp_obj_t self) {
+ check_for_deinit(self);
+ const char *instance_name = common_hal_mdns_server_get_instance_name(self);
+ return mp_obj_new_str(instance_name, strlen(instance_name));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mdns_server_get_instance_name_obj, mdns_server_get_instance_name);
+
+STATIC mp_obj_t mdns_server_set_instance_name(mp_obj_t self, mp_obj_t new_instance_name) {
+ check_for_deinit(self);
+ common_hal_mdns_server_set_instance_name(self, mp_obj_str_get_str(new_instance_name));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mdns_server_set_instance_name_obj, mdns_server_set_instance_name);
+
+MP_PROPERTY_GETSET(mdns_server_instance_name_obj,
+ (mp_obj_t)&mdns_server_get_instance_name_obj,
+ (mp_obj_t)&mdns_server_set_instance_name_obj);
+
+
+//| def find(self, service_type: str, protocol: str, *, timeout: float = 1) -> Tuple[RemoteService]:
+//| """Find all locally available remote services with the given service type and protocol.
+//|
+//| This doesn't allow for direct hostname lookup. To do that, use
+//| `socketpool.SocketPool.getaddrinfo()`.
+//|
+//| :param str service_type: The service type such as "_http"
+//| :param str protocol: The service protocol such as "_tcp"
+//| :param float/int timeout: Time to wait for responses"""
+//| ...
+//|
+STATIC mp_obj_t mdns_server_find(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mdns_server_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+
+ enum { ARG_service_type, ARG_protocol, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_service_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ const char *service_type = mp_obj_str_get_str(args[ARG_service_type].u_obj);
+ const char *protocol = mp_obj_str_get_str(args[ARG_protocol].u_obj);
+
+ return common_hal_mdns_server_find(self, service_type, protocol, timeout);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, mdns_server_find);
+
+//| def advertise_service(self, *, service_type: str, protocol: str, port: int) -> None:
+//| """Respond to queries for the given service with the given port.
+//|
+//| :param str service_type: The service type such as "_http"
+//| :param str protocol: The service protocol such as "_tcp"
+//| :param int port: The port used by the service"""
+//| ...
+//|
+STATIC mp_obj_t mdns_server_advertise_service(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mdns_server_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+
+ enum { ARG_service_type, ARG_protocol, ARG_port };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_service_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *service_type = mp_obj_str_get_str(args[ARG_service_type].u_obj);
+ const char *protocol = mp_obj_str_get_str(args[ARG_protocol].u_obj);
+
+ common_hal_mdns_server_advertise_service(self, service_type, protocol, args[ARG_port].u_int);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_advertise_service_obj, 1, mdns_server_advertise_service);
+
+STATIC const mp_rom_map_elem_t mdns_server_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mdns_server_hostname_obj) },
+ { MP_ROM_QSTR(MP_QSTR_instance_name), MP_ROM_PTR(&mdns_server_instance_name_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&mdns_server_find_obj) },
+ { MP_ROM_QSTR(MP_QSTR_advertise_service), MP_ROM_PTR(&mdns_server_advertise_service_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mdns_server_deinit_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_server_locals_dict, mdns_server_locals_dict_table);
+
+const mp_obj_type_t mdns_server_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Server,
+ .make_new = mdns_server_make_new,
+ .locals_dict = (mp_obj_t)&mdns_server_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/mdns/Server.h b/circuitpython/shared-bindings/mdns/Server.h
new file mode 100644
index 0000000..a178e9b
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/Server.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "common-hal/mdns/Server.h"
+
+extern const mp_obj_type_t mdns_server_type;
+
+void common_hal_mdns_server_construct(mdns_server_obj_t *self, mp_obj_t network_interface);
+void common_hal_mdns_server_deinit(mdns_server_obj_t *self);
+bool common_hal_mdns_server_deinited(mdns_server_obj_t *self);
+const char *common_hal_mdns_server_get_hostname(mdns_server_obj_t *self);
+void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *hostname);
+const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self);
+void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name);
+mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_float_t timeout);
+void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port);
diff --git a/circuitpython/shared-bindings/mdns/__init__.c b/circuitpython/shared-bindings/mdns/__init__.c
new file mode 100644
index 0000000..9752a3b
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/__init__.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+
+#include "py/objexcept.h"
+#include "py/runtime.h"
+#include "shared-bindings/mdns/__init__.h"
+#include "shared-bindings/mdns/Server.h"
+#include "shared-bindings/mdns/RemoteService.h"
+
+//| """Multicast Domain Name Service
+//|
+//| The `mdns` module provides basic support for multicast domain name services.
+//| Basic use provides hostname resolution under the .local TLD. This module
+//| also supports DNS Service Discovery that allows for discovering other hosts
+//| that provide a desired service."""
+//|
+
+STATIC const mp_rom_map_elem_t mdns_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mdns) },
+ { MP_ROM_QSTR(MP_QSTR_Server), MP_ROM_PTR(&mdns_server_type) },
+ { MP_ROM_QSTR(MP_QSTR_RemoteService), MP_ROM_PTR(&mdns_remoteservice_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mdns_module_globals, mdns_module_globals_table);
+
+const mp_obj_module_t mdns_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mdns_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_mdns, mdns_module, CIRCUITPY_MDNS);
diff --git a/circuitpython/shared-bindings/mdns/__init__.h b/circuitpython/shared-bindings/mdns/__init__.h
new file mode 100644
index 0000000..d672285
--- /dev/null
+++ b/circuitpython/shared-bindings/mdns/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.c b/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.c
new file mode 100644
index 0000000..b546452
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.c
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/memorymonitor/AllocationAlarm.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class AllocationAlarm:
+//|
+//| def __init__(self, *, minimum_block_count: int = 1) -> None:
+//| """Throw an exception when an allocation of ``minimum_block_count`` or more blocks
+//| occurs while active.
+//|
+//| Track allocations::
+//|
+//| import memorymonitor
+//|
+//| aa = memorymonitor.AllocationAlarm(minimum_block_count=2)
+//| x = 2
+//| # Should not allocate any blocks.
+//| with aa:
+//| x = 5
+//|
+//| # Should throw an exception when allocating storage for the 20 bytes.
+//| with aa:
+//| x = bytearray(20)
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) {
+ enum { ARG_minimum_block_count };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_minimum_block_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mp_int_t minimum_block_count = args[ARG_minimum_block_count].u_int;
+ if (minimum_block_count < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_minimum_block_count);
+ }
+
+ memorymonitor_allocationalarm_obj_t *self = m_new_obj(memorymonitor_allocationalarm_obj_t);
+ self->base.type = &memorymonitor_allocationalarm_type;
+
+ common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def ignore(self, count: int) -> AllocationAlarm:
+//| """Sets the number of applicable allocations to ignore before raising the exception.
+//| Automatically set back to zero at context exit.
+//|
+//| Use it within a ``with`` block::
+//|
+//| # Will not alarm because the bytearray allocation will be ignored.
+//| with aa.ignore(2):
+//| x = bytearray(20)
+//| """
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationalarm_obj_ignore(mp_obj_t self_in, mp_obj_t count_obj) {
+ mp_int_t count = mp_obj_get_int(count_obj);
+ if (count < 0) {
+ mp_raise_ValueError_varg(translate("%q must be >= 0"), MP_QSTR_count);
+ }
+ common_hal_memorymonitor_allocationalarm_set_ignore(self_in, count);
+ return self_in;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(memorymonitor_allocationalarm_ignore_obj, memorymonitor_allocationalarm_obj_ignore);
+
+//| def __enter__(self) -> AllocationAlarm:
+//| """Enables the alarm."""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationalarm_obj___enter__(mp_obj_t self_in) {
+ common_hal_memorymonitor_allocationalarm_resume(self_in);
+ return self_in;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationalarm___enter___obj, memorymonitor_allocationalarm_obj___enter__);
+
+//| def __exit__(self) -> None:
+//| """Automatically disables the allocation alarm when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationalarm_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_memorymonitor_allocationalarm_set_ignore(args[0], 0);
+ common_hal_memorymonitor_allocationalarm_pause(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationalarm___exit___obj, 4, 4, memorymonitor_allocationalarm_obj___exit__);
+
+STATIC const mp_rom_map_elem_t memorymonitor_allocationalarm_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_ignore), MP_ROM_PTR(&memorymonitor_allocationalarm_ignore_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationalarm___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationalarm___exit___obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationalarm_locals_dict, memorymonitor_allocationalarm_locals_dict_table);
+
+const mp_obj_type_t memorymonitor_allocationalarm_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_AllocationAlarm,
+ .make_new = memorymonitor_allocationalarm_make_new,
+ .locals_dict = (mp_obj_dict_t *)&memorymonitor_allocationalarm_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.h b/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.h
new file mode 100644
index 0000000..0a62971
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/AllocationAlarm.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H
+
+#include "shared-module/memorymonitor/AllocationAlarm.h"
+
+extern const mp_obj_type_t memorymonitor_allocationalarm_type;
+
+void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t *self, size_t minimum_block_count);
+void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t *self);
+void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t *self);
+void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t *self, mp_int_t count);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H
diff --git a/circuitpython/shared-bindings/memorymonitor/AllocationSize.c b/circuitpython/shared-bindings/memorymonitor/AllocationSize.c
new file mode 100644
index 0000000..1c39fdc
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/AllocationSize.c
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/memorymonitor/AllocationSize.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class AllocationSize:
+//|
+//| def __init__(self) -> None:
+//| """Tracks the number of allocations in power of two buckets.
+//|
+//| It will have 16 16-bit buckets to track allocation counts. It is total allocations
+//| meaning frees are ignored. Reallocated memory is counted twice, at allocation and when
+//| reallocated with the larger size.
+//|
+//| The buckets are measured in terms of blocks which is the finest granularity of the heap.
+//| This means bucket 0 will count all allocations less than or equal to the number of bytes
+//| per block, typically 16. Bucket 2 will be less than or equal to 4 blocks. See
+//| `bytes_per_block` to convert blocks to bytes.
+//|
+//| Multiple AllocationSizes can be used to track different code boundaries.
+//|
+//| Track allocations::
+//|
+//| import memorymonitor
+//|
+//| mm = memorymonitor.AllocationSize()
+//| with mm:
+//| print("hello world" * 3)
+//|
+//| for bucket, count in enumerate(mm):
+//| print("<", 2 ** bucket, count)
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) {
+ memorymonitor_allocationsize_obj_t *self = m_new_obj(memorymonitor_allocationsize_obj_t);
+ self->base.type = &memorymonitor_allocationsize_type;
+
+ common_hal_memorymonitor_allocationsize_construct(self);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def __enter__(self) -> AllocationSize:
+//| """Clears counts and resumes tracking."""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_obj___enter__(mp_obj_t self_in) {
+ common_hal_memorymonitor_allocationsize_clear(self_in);
+ common_hal_memorymonitor_allocationsize_resume(self_in);
+ return self_in;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize___enter___obj, memorymonitor_allocationsize_obj___enter__);
+
+//| def __exit__(self) -> None:
+//| """Automatically pauses allocation tracking when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_memorymonitor_allocationsize_pause(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationsize___exit___obj, 4, 4, memorymonitor_allocationsize_obj___exit__);
+
+//| bytes_per_block: int
+//| """Number of bytes per block"""
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_obj_get_bytes_per_block(mp_obj_t self_in) {
+ memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_bytes_per_block(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize_get_bytes_per_block_obj, memorymonitor_allocationsize_obj_get_bytes_per_block);
+
+MP_PROPERTY_GETTER(memorymonitor_allocationsize_bytes_per_block_obj,
+ (mp_obj_t)&memorymonitor_allocationsize_get_bytes_per_block_obj);
+
+//| def __len__(self) -> int:
+//| """Returns the number of allocation buckets.
+//|
+//| This allows you to::
+//|
+//| mm = memorymonitor.AllocationSize()
+//| print(len(mm))"""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint16_t len = common_hal_memorymonitor_allocationsize_get_len(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __getitem__(self, index: int) -> Optional[int]:
+//| """Returns the allocation count for the given bucket.
+//|
+//| This allows you to::
+//|
+//| mm = memorymonitor.AllocationSize()
+//| print(mm[0])"""
+//| ...
+//|
+STATIC mp_obj_t memorymonitor_allocationsize_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) {
+ if (value == mp_const_none) {
+ // delete item
+ mp_raise_AttributeError(translate("Cannot delete values"));
+ } else {
+ memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (mp_obj_is_type(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ size_t index = mp_get_index(&memorymonitor_allocationsize_type, common_hal_memorymonitor_allocationsize_get_len(self), index_obj, false);
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_item(self, index));
+ } else {
+ mp_raise_AttributeError(translate("Read-only"));
+ }
+ }
+ }
+ return mp_const_none;
+}
+
+STATIC const mp_rom_map_elem_t memorymonitor_allocationsize_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationsize___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationsize___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_bytes_per_block), MP_ROM_PTR(&memorymonitor_allocationsize_bytes_per_block_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationsize_locals_dict, memorymonitor_allocationsize_locals_dict_table);
+
+const mp_obj_type_t memorymonitor_allocationsize_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_AllocationSize,
+ .make_new = memorymonitor_allocationsize_make_new,
+ .subscr = memorymonitor_allocationsize_subscr,
+ .unary_op = memorymonitor_allocationsize_unary_op,
+ .getiter = mp_obj_new_generic_iterator,
+ .locals_dict = (mp_obj_dict_t *)&memorymonitor_allocationsize_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/memorymonitor/AllocationSize.h b/circuitpython/shared-bindings/memorymonitor/AllocationSize.h
new file mode 100644
index 0000000..c677c1a
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/AllocationSize.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H
+
+#include "shared-module/memorymonitor/AllocationSize.h"
+
+extern const mp_obj_type_t memorymonitor_allocationsize_type;
+
+extern void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t *self);
+extern void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t *self);
+extern void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t *self);
+extern void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t *self);
+extern size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t *self);
+extern uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t *self);
+extern uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t *self, int16_t index);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H
diff --git a/circuitpython/shared-bindings/memorymonitor/__init__.c b/circuitpython/shared-bindings/memorymonitor/__init__.c
new file mode 100644
index 0000000..64a3a6a
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/__init__.c
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/memorymonitor/__init__.h"
+#include "shared-bindings/memorymonitor/AllocationAlarm.h"
+#include "shared-bindings/memorymonitor/AllocationSize.h"
+
+//| """Memory monitoring helpers"""
+//|
+
+//| class AllocationError(Exception):
+//| """Catchall exception for allocation related errors."""
+//| ...
+MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception)
+
+NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+STATIC const mp_rom_map_elem_t memorymonitor_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_memorymonitor) },
+ { MP_ROM_QSTR(MP_QSTR_AllocationAlarm), MP_ROM_PTR(&memorymonitor_allocationalarm_type) },
+ { MP_ROM_QSTR(MP_QSTR_AllocationSize), MP_ROM_PTR(&memorymonitor_allocationsize_type) },
+
+ // Errors
+ { MP_ROM_QSTR(MP_QSTR_AllocationError), MP_ROM_PTR(&mp_type_memorymonitor_AllocationError) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(memorymonitor_module_globals, memorymonitor_module_globals_table);
+
+void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
+ bool is_subclass = kind & PRINT_EXC_SUBCLASS;
+ if (!is_subclass && (k == PRINT_EXC)) {
+ mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(memorymonitor_module_globals_table[0].value)));
+ mp_print_str(print, ".");
+ }
+ mp_obj_exception_print(print, o_in, kind);
+}
+
+const mp_obj_module_t memorymonitor_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&memorymonitor_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_memorymonitor, memorymonitor_module, CIRCUITPY_MEMORYMONITOR);
diff --git a/circuitpython/shared-bindings/memorymonitor/__init__.h b/circuitpython/shared-bindings/memorymonitor/__init__.h
new file mode 100644
index 0000000..5d9dfdd
--- /dev/null
+++ b/circuitpython/shared-bindings/memorymonitor/__init__.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H
+
+#include "py/obj.h"
+
+
+void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
+
+#define MP_DEFINE_MEMORYMONITOR_EXCEPTION(exc_name, base_name) \
+ const mp_obj_type_t mp_type_memorymonitor_##exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_##exc_name, \
+ .print = memorymonitor_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .attr = mp_obj_exception_attr, \
+ .parent = &mp_type_##base_name, \
+ };
+
+extern const mp_obj_type_t mp_type_memorymonitor_AllocationError;
+
+NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t *msg, ...);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H
diff --git a/circuitpython/shared-bindings/microcontroller/Pin.c b/circuitpython/shared-bindings/microcontroller/Pin.c
new file mode 100644
index 0000000..e6809d6
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/Pin.c
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/board/__init__.h"
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class Pin:
+//| """Identifies an IO pin on the microcontroller."""
+//|
+//| def __init__(self) -> None:
+//| """Identifies an IO pin on the microcontroller. They are fixed by the
+//| hardware so they cannot be constructed on demand. Instead, use
+//| :mod:`board` or :mod:`microcontroller.pin` to reference the desired pin."""
+//| ...
+//|
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the Pin."""
+//| ...
+//|
+// Provided by mp_generic_unary_op().
+
+static void get_pin_name(const mcu_pin_obj_t *self, qstr *package, qstr *module, qstr *name) {
+ const mp_map_t *board_map = &board_module_globals.map;
+ for (uint8_t i = 0; i < board_map->alloc; i++) {
+ if (board_map->table[i].value == MP_OBJ_FROM_PTR(self)) {
+ *package = 0;
+ *module = MP_QSTR_board;
+ *name = MP_OBJ_QSTR_VALUE(board_map->table[i].key);
+ return;
+ }
+ }
+ const mp_map_t *mcu_map = &mcu_pin_globals.map;
+ for (uint8_t i = 0; i < mcu_map->alloc; i++) {
+ if (mcu_map->table[i].value == MP_OBJ_FROM_PTR(self)) {
+ *package = MP_QSTR_microcontroller;
+ *module = MP_QSTR_pin;
+ *name = MP_OBJ_QSTR_VALUE(mcu_map->table[i].key);
+ return;
+ }
+ }
+}
+
+STATIC void mcu_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ mcu_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ qstr package = MP_QSTR_Pin;
+ qstr module;
+ qstr name = MP_QSTR_Pin;
+
+ get_pin_name(self, &package, &module, &name);
+ if (package) {
+ mp_printf(print, "%q.%q.%q", package, module, name);
+ } else {
+ mp_printf(print, "%q.%q", module, name);
+ }
+}
+
+const mp_obj_type_t mcu_pin_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Pin,
+ .print = mcu_pin_print,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_generic_unary_op,
+ )
+};
+
+const mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj) {
+ if (!mp_obj_is_type(obj, &mcu_pin_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), mcu_pin_type.name);
+ }
+ return MP_OBJ_TO_PTR(obj);
+}
+
+// Validate that the obj is a pin or None. Return an mcu_pin_obj_t* or NULL, correspondingly.
+const mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj) {
+ if (obj == mp_const_none) {
+ return NULL;
+ }
+ return validate_obj_is_pin(obj);
+}
+
+const mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj) {
+ const mcu_pin_obj_t *pin = validate_obj_is_pin(obj);
+ assert_pin_free(pin);
+ return pin;
+}
+
+// Validate every element in the list is a unique pin
+void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name) {
+ const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq));
+
+ for (size_t pin_cnt = 0; pin_cnt < num_pins; pin_cnt++) {
+ mp_obj_t pin1_obj = mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(pin_cnt), MP_OBJ_SENTINEL);
+ const mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj);
+
+ for (size_t pin_cnt_2 = pin_cnt + 1; pin_cnt_2 < num_pins; pin_cnt_2++) {
+ mp_obj_t pin2_obj = mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(pin_cnt_2), MP_OBJ_SENTINEL);
+ const mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj);
+ if (pin1 == pin2) {
+ mp_raise_TypeError_varg(translate("%q contains duplicate pins"), arg_name);
+ }
+ }
+ }
+}
+
+void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, qstr arg_name2) {
+ const size_t num_pins_1 = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq1));
+ const size_t num_pins_2 = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq2));
+
+ validate_no_duplicate_pins(seq1, arg_name1);
+ validate_no_duplicate_pins(seq2, arg_name2);
+
+ for (size_t pin_cnt_1 = 0; pin_cnt_1 < num_pins_1; pin_cnt_1++) {
+ mp_obj_t pin1_obj = mp_obj_subscr(seq1, MP_OBJ_NEW_SMALL_INT(pin_cnt_1), MP_OBJ_SENTINEL);
+ const mcu_pin_obj_t *pin1 = validate_obj_is_pin(pin1_obj);
+
+ for (size_t pin_cnt_2 = 0; pin_cnt_2 < num_pins_2; pin_cnt_2++) {
+ mp_obj_t pin2_obj = mp_obj_subscr(seq2, MP_OBJ_NEW_SMALL_INT(pin_cnt_2), MP_OBJ_SENTINEL);
+ const mcu_pin_obj_t *pin2 = validate_obj_is_pin(pin2_obj);
+ if (pin1 == pin2) {
+ mp_raise_TypeError_varg(translate("%q and %q contain duplicate pins"), arg_name1, arg_name2);
+ }
+ }
+ }
+}
+
+// Validate every element in the list to be a free pin.
+void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) {
+ mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq));
+ if (len > max_pins) {
+ mp_raise_ValueError_varg(translate("At most %d %q may be specified (not %d)"), max_pins, what, len);
+ }
+ *count_out = len;
+ for (mp_int_t i = 0; i < len; i++) {
+ pins_out[i] = validate_obj_is_free_pin(mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
+ }
+}
+
+// Validate that the obj is a free pin or None. Return an mcu_pin_obj_t* or NULL, correspondingly.
+const mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj) {
+ if (obj == mp_const_none) {
+ return NULL;
+ }
+ const mcu_pin_obj_t *pin = validate_obj_is_pin(obj);
+ assert_pin_free(pin);
+ return pin;
+}
+
+void assert_pin_free(const mcu_pin_obj_t *pin) {
+ if (pin != NULL && pin != MP_OBJ_TO_PTR(mp_const_none) && !common_hal_mcu_pin_is_free(pin)) {
+ qstr package;
+ qstr module;
+ qstr name = MP_QSTR_Pin;
+
+ get_pin_name(pin, &package, &module, &name);
+ mp_raise_ValueError_varg(translate("%q in use"), name);
+ }
+}
+
+void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out) {
+ const mcu_pin_obj_t *pins[max_pins];
+ validate_list_is_free_pins(what, pins, max_pins, seq, count_out);
+ for (mp_int_t i = 0; i < *count_out; i++) {
+ pin_nos[i] = common_hal_mcu_pin_number(pins[i]);
+ }
+}
diff --git a/circuitpython/shared-bindings/microcontroller/Pin.h b/circuitpython/shared-bindings/microcontroller/Pin.h
new file mode 100644
index 0000000..a7378ea
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/Pin.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PIN_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "py/obj.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t mcu_pin_type;
+
+const mcu_pin_obj_t *validate_obj_is_pin(mp_obj_t obj);
+const mcu_pin_obj_t *validate_obj_is_pin_or_none(mp_obj_t obj);
+const mcu_pin_obj_t *validate_obj_is_free_pin(mp_obj_t obj);
+const mcu_pin_obj_t *validate_obj_is_free_pin_or_none(mp_obj_t obj);
+void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name);
+void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, qstr arg_name2);
+void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out);
+void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out);
+
+void assert_pin_free(const mcu_pin_obj_t *pin);
+
+bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin);
+void common_hal_never_reset_pin(const mcu_pin_obj_t *pin);
+void common_hal_reset_pin(const mcu_pin_obj_t *pin);
+uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin);
+void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin);
+void common_hal_mcu_pin_claim_number(uint8_t pin_no);
+void common_hal_mcu_pin_reset_number(uint8_t pin_no);
+
+#define COMMON_HAL_MCU_NO_PIN ((uint8_t)0xff)
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PIN_H
diff --git a/circuitpython/shared-bindings/microcontroller/Processor.c b/circuitpython/shared-bindings/microcontroller/Processor.c
new file mode 100644
index 0000000..ff1b52e
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/Processor.c
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/microcontroller/Processor.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/mperrno.h"
+#include "py/objtype.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+
+//| class Processor:
+//| """Microcontroller CPU information and control
+//|
+//| Usage::
+//|
+//| import microcontroller
+//| print(microcontroller.cpu.frequency)
+//| print(microcontroller.cpu.temperature)
+//|
+//| Note that on chips with more than one cpu (such as the RP2040)
+//| microcontroller.cpu will return the value for CPU 0.
+//| To get values from other CPUs use microcontroller.cpus indexed by
+//| the number of the desired cpu. i.e.
+//|
+//| print(microcontroller.cpus[0].temperature)
+//| print(microcontroller.cpus[1].frequency)"""
+//|
+
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `microcontroller.Processor`.
+//| Use `microcontroller.cpu` to access the sole instance available."""
+//| ...
+//|
+
+//| frequency: int
+//| """The CPU operating frequency in Hertz. (read-only)"""
+//|
+
+STATIC mp_obj_t mcu_processor_set_frequency(mp_obj_t self, mp_obj_t freq) {
+ #if CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY
+ uint32_t value_of_freq = (uint32_t)mp_arg_validate_int_min(mp_obj_get_int(freq), 0, MP_QSTR_frequency);
+ common_hal_mcu_processor_set_frequency(self, value_of_freq);
+ #else
+ mp_raise_msg(&mp_type_NotImplementedError,translate("frequency is read-only for this board"));
+ #endif
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_2(mcu_processor_set_frequency_obj, mcu_processor_set_frequency);
+
+
+STATIC mp_obj_t mcu_processor_get_frequency(mp_obj_t self) {
+ return mp_obj_new_int_from_uint(common_hal_mcu_processor_get_frequency());
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_frequency_obj, mcu_processor_get_frequency);
+
+MP_PROPERTY_GETSET(mcu_processor_frequency_obj,
+ (mp_obj_t)&mcu_processor_get_frequency_obj,
+ (mp_obj_t)&mcu_processor_set_frequency_obj);
+
+//| reset_reason: microcontroller.ResetReason
+//| """The reason the microcontroller started up from reset state."""
+//|
+STATIC mp_obj_t mcu_processor_get_reset_reason(mp_obj_t self) {
+ return cp_enum_find(&mcu_reset_reason_type, common_hal_mcu_processor_get_reset_reason());
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_reset_reason_obj, mcu_processor_get_reset_reason);
+
+MP_PROPERTY_GETTER(mcu_processor_reset_reason_obj,
+ (mp_obj_t)&mcu_processor_get_reset_reason_obj);
+
+//| temperature: Optional[float]
+//| """The on-chip temperature, in Celsius, as a float. (read-only)
+//|
+//| Is `None` if the temperature is not available."""
+//|
+STATIC mp_obj_t mcu_processor_get_temperature(mp_obj_t self) {
+ float temperature = common_hal_mcu_processor_get_temperature();
+ return isnan(temperature) ? mp_const_none : mp_obj_new_float(temperature);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_temperature_obj, mcu_processor_get_temperature);
+
+MP_PROPERTY_GETTER(mcu_processor_temperature_obj,
+ (mp_obj_t)&mcu_processor_get_temperature_obj);
+
+//| uid: bytearray
+//| """The unique id (aka serial number) of the chip as a `bytearray`. (read-only)"""
+//|
+STATIC mp_obj_t mcu_processor_get_uid(mp_obj_t self) {
+ uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH];
+ common_hal_mcu_processor_get_uid(raw_id);
+ return mp_obj_new_bytearray(sizeof(raw_id), raw_id);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_uid_obj, mcu_processor_get_uid);
+
+MP_PROPERTY_GETTER(mcu_processor_uid_obj,
+ (mp_obj_t)&mcu_processor_get_uid_obj);
+
+//| voltage: Optional[float]
+//| """The input voltage to the microcontroller, as a float. (read-only)
+//|
+//| Is `None` if the voltage is not available."""
+//|
+STATIC mp_obj_t mcu_processor_get_voltage(mp_obj_t self) {
+ float voltage = common_hal_mcu_processor_get_voltage();
+ return isnan(voltage) ? mp_const_none : mp_obj_new_float(voltage);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_voltage_obj, mcu_processor_get_voltage);
+
+MP_PROPERTY_GETTER(mcu_processor_voltage_obj,
+ (mp_obj_t)&mcu_processor_get_voltage_obj);
+
+STATIC const mp_rom_map_elem_t mcu_processor_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&mcu_processor_frequency_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset_reason), MP_ROM_PTR(&mcu_processor_reset_reason_obj) },
+ { MP_ROM_QSTR(MP_QSTR_temperature), MP_ROM_PTR(&mcu_processor_temperature_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uid), MP_ROM_PTR(&mcu_processor_uid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_voltage), MP_ROM_PTR(&mcu_processor_voltage_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mcu_processor_locals_dict, mcu_processor_locals_dict_table);
+
+const mp_obj_type_t mcu_processor_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Processor,
+ .locals_dict = (mp_obj_dict_t *)&mcu_processor_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/microcontroller/Processor.h b/circuitpython/shared-bindings/microcontroller/Processor.h
new file mode 100644
index 0000000..9a2f22b
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/Processor.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PROCESSOR_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PROCESSOR_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Processor.h"
+#include "shared-bindings/microcontroller/ResetReason.h"
+
+extern const mp_obj_type_t mcu_processor_type;
+
+uint32_t common_hal_mcu_processor_get_frequency(void);
+mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void);
+float common_hal_mcu_processor_get_temperature(void);
+void common_hal_mcu_processor_get_uid(uint8_t raw_id[]);
+float common_hal_mcu_processor_get_voltage(void);
+uint32_t common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t frequency);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PROCESSOR_H
diff --git a/circuitpython/shared-bindings/microcontroller/ResetReason.c b/circuitpython/shared-bindings/microcontroller/ResetReason.c
new file mode 100644
index 0000000..905c19f
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/ResetReason.c
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/enum.h"
+
+#include "shared-bindings/microcontroller/ResetReason.h"
+
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, RESET_REASON_POWER_ON);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, RESET_REASON_BROWNOUT);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, RESET_REASON_SOFTWARE);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, RESET_REASON_DEEP_SLEEP_ALARM);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, RESET_REASON_RESET_PIN);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, RESET_REASON_WATCHDOG);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, RESET_REASON_UNKNOWN);
+MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_RESCUE_DEBUG);
+
+//| class ResetReason:
+//| """The reason the microntroller was last reset"""
+//|
+//| POWER_ON: object
+//| """The microntroller was started from power off."""
+//|
+//| BROWNOUT: object
+//| """The microntroller was reset due to too low a voltage."""
+//|
+//| SOFTWARE: object
+//| """The microntroller was reset from software."""
+//|
+//| DEEP_SLEEP_ALARM: object
+//| """The microntroller was reset for deep sleep and restarted by an alarm."""
+//|
+//| RESET_PIN: object
+//| """The microntroller was reset by a signal on its reset pin. The pin might be connected to a reset button."""
+//|
+//| WATCHDOG: object
+//| """The microcontroller was reset by its watchdog timer."""
+//|
+//| UNKNOWN: object
+//| """The microntroller restarted for an unknown reason."""
+//|
+//| RESCUE_DEBUG: object
+//| """The microntroller was reset by the rescue debug port."""
+//|
+MAKE_ENUM_MAP(mcu_reset_reason) {
+ MAKE_ENUM_MAP_ENTRY(reset_reason, POWER_ON),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, BROWNOUT),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, SOFTWARE),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, DEEP_SLEEP_ALARM),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, RESET_PIN),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, WATCHDOG),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, UNKNOWN),
+ MAKE_ENUM_MAP_ENTRY(reset_reason, RESCUE_DEBUG),
+};
+STATIC MP_DEFINE_CONST_DICT(mcu_reset_reason_locals_dict, mcu_reset_reason_locals_table);
+
+MAKE_PRINTER(microcontroller, mcu_reset_reason);
+
+MAKE_ENUM_TYPE(microcontroller, ResetReason, mcu_reset_reason);
diff --git a/circuitpython/shared-bindings/microcontroller/ResetReason.h b/circuitpython/shared-bindings/microcontroller/ResetReason.h
new file mode 100644
index 0000000..7abc54c
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/ResetReason.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MCU_RESET_REASON__H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MCU_RESET_REASON__H
+
+#include "py/obj.h"
+#include "py/enum.h"
+
+typedef enum {
+ RESET_REASON_POWER_ON,
+ RESET_REASON_BROWNOUT,
+ RESET_REASON_SOFTWARE,
+ RESET_REASON_DEEP_SLEEP_ALARM,
+ RESET_REASON_RESET_PIN,
+ RESET_REASON_WATCHDOG,
+ RESET_REASON_UNKNOWN,
+ RESET_REASON_RESCUE_DEBUG,
+} mcu_reset_reason_t;
+
+extern const mp_obj_type_t mcu_reset_reason_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MCU_RESET_REASON__H
diff --git a/circuitpython/shared-bindings/microcontroller/RunMode.c b/circuitpython/shared-bindings/microcontroller/RunMode.c
new file mode 100644
index 0000000..477168d
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/RunMode.c
@@ -0,0 +1,101 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/microcontroller/RunMode.h"
+
+//| class RunMode:
+//| """run state of the microcontroller"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the run mode of the microcontroller and
+//| CircuitPython."""
+//|
+//| NORMAL: RunMode
+//| """Run CircuitPython as normal.
+//|
+//| :type microcontroller.RunMode:"""
+//|
+//| SAFE_MODE: RunMode
+//| """Run CircuitPython in safe mode. User code will not run and the
+//| file system will be writeable over USB.
+//|
+//| :type microcontroller.RunMode:"""
+//|
+//| UF2: RunMode
+//| """Run the uf2 bootloader.
+//|
+//| :type microcontroller.RunMode:"""
+//|
+//| BOOTLOADER: RunMode
+//| """Run the default bootloader.
+//|
+//| :type microcontroller.RunMode:"""
+//|
+const mp_obj_type_t mcu_runmode_type;
+
+const mcu_runmode_obj_t mcu_runmode_uf2_obj = {
+ { &mcu_runmode_type },
+};
+
+const mcu_runmode_obj_t mcu_runmode_normal_obj = {
+ { &mcu_runmode_type },
+};
+
+const mcu_runmode_obj_t mcu_runmode_safe_mode_obj = {
+ { &mcu_runmode_type },
+};
+
+const mcu_runmode_obj_t mcu_runmode_bootloader_obj = {
+ { &mcu_runmode_type },
+};
+
+STATIC const mp_rom_map_elem_t mcu_runmode_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_UF2), MP_ROM_PTR(&mcu_runmode_uf2_obj)},
+ {MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_PTR(&mcu_runmode_normal_obj)},
+ {MP_ROM_QSTR(MP_QSTR_SAFE_MODE), MP_ROM_PTR(&mcu_runmode_safe_mode_obj)},
+ {MP_ROM_QSTR(MP_QSTR_BOOTLOADER), MP_ROM_PTR(&mcu_runmode_bootloader_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_table);
+
+STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr runmode = MP_QSTR_NORMAL;
+ if (self_in == MP_ROM_PTR(&mcu_runmode_uf2_obj)) {
+ runmode = MP_QSTR_UF2;
+ } else if (self_in == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) {
+ runmode = MP_QSTR_SAFE_MODE;
+ } else if (self_in == MP_ROM_PTR(&mcu_runmode_bootloader_obj)) {
+ runmode = MP_QSTR_BOOTLOADER;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode,
+ runmode);
+}
+
+const mp_obj_type_t mcu_runmode_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RunMode,
+ .print = mcu_runmode_print,
+ .locals_dict = (mp_obj_dict_t *)&mcu_runmode_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/microcontroller/RunMode.h b/circuitpython/shared-bindings/microcontroller/RunMode.h
new file mode 100644
index 0000000..172256d
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/RunMode.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
+
+#include "py/obj.h"
+
+typedef enum {
+ RUNMODE_UF2,
+ RUNMODE_NORMAL,
+ RUNMODE_SAFE_MODE,
+ RUNMODE_BOOTLOADER
+} mcu_runmode_t;
+
+extern const mp_obj_type_t mcu_runmode_type;
+
+typedef struct {
+ mp_obj_base_t base;
+} mcu_runmode_obj_t;
+
+extern const mcu_runmode_obj_t mcu_runmode_uf2_obj;
+extern const mcu_runmode_obj_t mcu_runmode_normal_obj;
+extern const mcu_runmode_obj_t mcu_runmode_safe_mode_obj;
+extern const mcu_runmode_obj_t mcu_runmode_bootloader_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H
diff --git a/circuitpython/shared-bindings/microcontroller/__init__.c b/circuitpython/shared-bindings/microcontroller/__init__.c
new file mode 100644
index 0000000..707080c
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/__init__.c
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// Microcontroller contains pin references and microcontroller specific control
+// functions.
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/microcontroller/Processor.h"
+
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/microcontroller/Processor.h"
+
+#include "supervisor/shared/translate.h"
+
+//| """Pin references and cpu functionality
+//|
+//| The `microcontroller` module defines the pins and other bare-metal hardware
+//| from the perspective of the microcontroller. See :py:mod:`board` for
+//| board-specific pin mappings."""
+//|
+//| from nvm import ByteArray
+//| from watchdog import WatchDogTimer
+//|
+
+//| cpu: Processor
+//| """CPU information and control, such as ``cpu.temperature`` and ``cpu.frequency``
+//| (clock frequency).
+//| This object is an instance of `microcontroller.Processor`."""
+//|
+
+//| cpus: Processor
+//| """CPU information and control, such as ``cpus[0].temperature`` and ``cpus[1].frequency``
+//| (clock frequency) on chips with more than 1 cpu. The index selects which cpu.
+//| This object is an instance of `microcontroller.Processor`."""
+//|
+
+//| def delay_us(delay: int) -> None:
+//| """Dedicated delay method used for very short delays. **Do not** do long delays
+//| because this stops all other functions from completing. Think of this as an empty
+//| ``while`` loop that runs for the specified ``(delay)`` time. If you have other
+//| code or peripherals (e.g audio recording) that require specific timing or
+//| processing while you are waiting, explore a different avenue such as using
+//| `time.sleep()`."""
+//| ...
+//|
+STATIC mp_obj_t mcu_delay_us(mp_obj_t delay_obj) {
+ uint32_t delay = mp_obj_get_int(delay_obj);
+
+ common_hal_mcu_delay_us(delay);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_delay_us_obj, mcu_delay_us);
+
+//| def disable_interrupts() -> None:
+//| """Disable all interrupts. Be very careful, this can stall everything."""
+//| ...
+//|
+STATIC mp_obj_t mcu_disable_interrupts(void) {
+ common_hal_mcu_disable_interrupts();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_disable_interrupts_obj, mcu_disable_interrupts);
+
+//| def enable_interrupts() -> None:
+//| """Enable the interrupts that were enabled at the last disable."""
+//| ...
+//|
+STATIC mp_obj_t mcu_enable_interrupts(void) {
+ common_hal_mcu_enable_interrupts();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts);
+
+//| def on_next_reset(run_mode: microcontroller.RunMode) -> None:
+//| """Configure the run mode used the next time the microcontroller is reset but
+//| not powered down.
+//|
+//| :param ~microcontroller.RunMode run_mode: The next run mode"""
+//| ...
+//|
+STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) {
+ mcu_runmode_t run_mode;
+ if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_uf2_obj)) {
+ run_mode = RUNMODE_UF2;
+ } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_normal_obj)) {
+ run_mode = RUNMODE_NORMAL;
+ } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_safe_mode_obj)) {
+ run_mode = RUNMODE_SAFE_MODE;
+ } else if (run_mode_obj == MP_OBJ_FROM_PTR(&mcu_runmode_bootloader_obj)) {
+ run_mode = RUNMODE_BOOTLOADER;
+ } else {
+ mp_raise_ValueError(translate("Invalid run mode."));
+ }
+ common_hal_mcu_on_next_reset(run_mode);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset);
+
+//| def reset() -> None:
+//| """Reset the microcontroller. After reset, the microcontroller will enter the
+//| run mode last set by `on_next_reset`.
+//|
+//| .. warning:: This may result in file system corruption when connected to a
+//| host computer. Be very careful when calling this! Make sure the device
+//| "Safely removed" on Windows or "ejected" on Mac OSX and Linux."""
+//| ...
+//|
+STATIC mp_obj_t mcu_reset(void) {
+ common_hal_mcu_reset();
+ // We won't actually get here because we're resetting.
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset);
+
+//| nvm: Optional[ByteArray]
+//| """Available non-volatile memory.
+//| This object is the sole instance of `nvm.ByteArray` when available or ``None`` otherwise.
+//|
+//| :type: nvm.ByteArray or None"""
+//|
+
+//| watchdog: Optional[WatchDogTimer]
+//| """Available watchdog timer.
+//| This object is the sole instance of `watchdog.WatchDogTimer` when available or ``None`` otherwise."""
+//|
+
+const mp_obj_module_t mcu_pin_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mcu_pin_globals,
+};
+
+STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_microcontroller) },
+ { MP_ROM_QSTR(MP_QSTR_cpu), MP_ROM_PTR(&common_hal_mcu_processor_obj) },
+ #if CIRCUITPY_PROCESSOR_COUNT > 1
+ { MP_ROM_QSTR(MP_QSTR_cpus), MP_ROM_PTR(&common_hal_multi_processor_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) },
+ { MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) },
+ #if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0
+ { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) },
+ #else
+ { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_NONE },
+ #endif
+ #if CIRCUITPY_WATCHDOG
+ { MP_ROM_QSTR(MP_QSTR_watchdog), MP_ROM_PTR(&common_hal_mcu_watchdogtimer_obj) },
+ #else
+ { MP_ROM_QSTR(MP_QSTR_watchdog), MP_ROM_NONE },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_ResetReason), MP_ROM_PTR(&mcu_reset_reason_type) },
+ { MP_ROM_QSTR(MP_QSTR_RunMode), MP_ROM_PTR(&mcu_runmode_type) },
+ { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) },
+ { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) },
+ { MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) },
+
+};
+
+STATIC MP_DEFINE_CONST_DICT(mcu_module_globals, mcu_module_globals_table);
+
+const mp_obj_module_t microcontroller_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mcu_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_microcontroller, microcontroller_module, CIRCUITPY_MICROCONTROLLER);
diff --git a/circuitpython/shared-bindings/microcontroller/__init__.h b/circuitpython/shared-bindings/microcontroller/__init__.h
new file mode 100644
index 0000000..e41cce8
--- /dev/null
+++ b/circuitpython/shared-bindings/microcontroller/__init__.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H
+
+#include "py/obj.h"
+#include "py/mpconfig.h"
+#include "py/objtuple.h"
+
+#include "common-hal/microcontroller/Processor.h"
+#include "shared-bindings/microcontroller/ResetReason.h"
+#include "shared-bindings/microcontroller/RunMode.h"
+
+extern void common_hal_mcu_delay_us(uint32_t);
+
+extern void common_hal_mcu_disable_interrupts(void);
+extern void common_hal_mcu_enable_interrupts(void);
+
+extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode);
+extern void common_hal_mcu_reset(void);
+
+extern const mp_obj_dict_t mcu_pin_globals;
+
+#if CIRCUITPY_PROCESSOR_COUNT == 1
+extern const mcu_processor_obj_t common_hal_mcu_processor_obj;
+#elif CIRCUITPY_PROCESSOR_COUNT > 1
+extern const mcu_processor_obj_t common_hal_mcu_processor_obj;
+extern const mp_rom_obj_tuple_t common_hal_multi_processor_obj;
+#else
+#error "Invalid processor count"
+#endif
+
+
+#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0
+#include "common-hal/nvm/ByteArray.h"
+extern const nvm_bytearray_obj_t common_hal_mcu_nvm_obj;
+#endif
+
+#if CIRCUITPY_WATCHDOG
+#include "common-hal/watchdog/WatchDogTimer.h"
+extern watchdog_watchdogtimer_obj_t common_hal_mcu_watchdogtimer_obj;
+#endif
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H
diff --git a/circuitpython/shared-bindings/msgpack/ExtType.c b/circuitpython/shared-bindings/msgpack/ExtType.c
new file mode 100644
index 0000000..1719e20
--- /dev/null
+++ b/circuitpython/shared-bindings/msgpack/ExtType.c
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Bernhard Boser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/smallint.h"
+#include "py/objproperty.h"
+#include "shared-bindings/msgpack/ExtType.h"
+
+//| class ExtType:
+//| """ExtType represents ext type in msgpack."""
+//| def __init__(self, code: int, data: bytes) -> None:
+//| """Constructor
+//| :param int code: type code in range 0~127.
+//| :param bytes data: representation."""
+//|
+STATIC mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ mod_msgpack_extype_obj_t *self = m_new_obj(mod_msgpack_extype_obj_t);
+ self->base.type = &mod_msgpack_exttype_type;
+ enum { ARG_code, ARG_data };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_code, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ int code = args[ARG_code].u_int;
+ if (code < 0 || code > 127) {
+ mp_raise_AttributeError(translate("code outside range 0~127"));
+ }
+ self->code = code;
+
+ mp_obj_t data = args[ARG_data].u_obj;
+ self->data = data;
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+//| code: int
+//| """The type code, in range 0~127."""
+//| ...
+//|
+STATIC mp_obj_t mod_msgpack_exttype_get_code(mp_obj_t self_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(self->code);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_code_obj, mod_msgpack_exttype_get_code);
+
+STATIC mp_obj_t mod_msgpack_exttype_set_code(mp_obj_t self_in, mp_obj_t code_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int code = mp_obj_get_int(code_in);
+ if (code < 0 || code > 127) {
+ mp_raise_AttributeError(translate("code outside range 0~127"));
+ }
+ self->code = code;
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_code_obj, mod_msgpack_exttype_set_code);
+
+MP_PROPERTY_GETSET(mod_msgpack_exttype_code_obj,
+ (mp_obj_t)&mod_msgpack_exttype_get_code_obj,
+ (mp_obj_t)&mod_msgpack_exttype_set_code_obj);
+
+//| data: bytes
+//| """Data."""
+//| ...
+//|
+STATIC mp_obj_t mod_msgpack_exttype_get_data(mp_obj_t self_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return self->data;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_data_obj, mod_msgpack_exttype_get_data);
+
+STATIC mp_obj_t mod_msgpack_exttype_set_data(mp_obj_t self_in, mp_obj_t data_in) {
+ mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ self->data = data_in;
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_data_obj, mod_msgpack_exttype_set_data);
+
+MP_PROPERTY_GETSET(mod_msgpack_exttype_data_obj,
+ (mp_obj_t)&mod_msgpack_exttype_get_data_obj,
+ (mp_obj_t)&mod_msgpack_exttype_set_data_obj);
+
+STATIC mp_rom_map_elem_t mod_msgpack_exttype_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_code), MP_ROM_PTR(&mod_msgpack_exttype_code_obj) },
+ { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&mod_msgpack_exttype_data_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(mod_msgpack_exttype_locals_dict, mod_msgpack_exttype_locals_dict_table);
+
+const mp_obj_type_t mod_msgpack_exttype_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ExtType,
+ .make_new = mod_msgpack_exttype_make_new,
+ .locals_dict = (mp_obj_dict_t *)&mod_msgpack_exttype_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/msgpack/ExtType.h b/circuitpython/shared-bindings/msgpack/ExtType.h
new file mode 100644
index 0000000..64173b2
--- /dev/null
+++ b/circuitpython/shared-bindings/msgpack/ExtType.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Bernhard Boser
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
+
+#include "py/obj.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ int32_t code;
+ mp_obj_t data;
+} mod_msgpack_extype_obj_t;
+
+extern const mp_obj_type_t mod_msgpack_exttype_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H
diff --git a/circuitpython/shared-bindings/msgpack/__init__.c b/circuitpython/shared-bindings/msgpack/__init__.c
new file mode 100644
index 0000000..65374fb
--- /dev/null
+++ b/circuitpython/shared-bindings/msgpack/__init__.c
@@ -0,0 +1,164 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Bernhard Boser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "shared-bindings/msgpack/__init__.h"
+#include "shared-module/msgpack/__init__.h"
+#include "shared-bindings/msgpack/ExtType.h"
+
+#define MP_OBJ_IS_METH(o) (mp_obj_is_obj(o) && (((mp_obj_base_t *)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_bound_method))
+
+//| """Pack object in msgpack format
+//|
+//| The msgpack format is similar to json, except that the encoded data is binary.
+//| See https://msgpack.org for details. The module implements a subset of the cpython
+//| module msgpack-python.
+//|
+//| Not implemented: 64-bit int, uint, float.
+//|
+//| Example 1::
+//|
+//| import msgpack
+//| from io import BytesIO
+//|
+//| b = BytesIO()
+//| msgpack.pack({'list': [True, False, None, 1, 3.14], 'str': 'blah'}, b)
+//| b.seek(0)
+//| print(msgpack.unpack(b))
+//|
+//| Example 2: handling objects::
+//|
+//| from msgpack import pack, unpack, ExtType
+//| from io import BytesIO
+//|
+//| class MyClass:
+//| def __init__(self, val):
+//| self.value = val
+//| def __str__(self):
+//| return str(self.value)
+//|
+//| data = MyClass(b'my_value')
+//|
+//| def encoder(obj):
+//| if isinstance(obj, MyClass):
+//| return ExtType(1, obj.value)
+//| return f"no encoder for {obj}"
+//|
+//| def decoder(code, data):
+//| if code == 1:
+//| return MyClass(data)
+//| return f"no decoder for type {code}"
+//|
+//| buffer = BytesIO()
+//| pack(data, buffer, default=encoder)
+//| buffer.seek(0)
+//| decoded = unpack(buffer, ext_hook=decoder)
+//| print(f"{data} -> {buffer.getvalue()} -> {decoded}")
+//|
+//| """
+//|
+
+//| def pack(obj: object, stream: circuitpython_typing.ByteStream, *, default: Union[Callable[[object], None], None] = None) -> None:
+//| """Output object to stream in msgpack format.
+//|
+//| :param object obj: Object to convert to msgpack format.
+//| :param ~circuitpython_typing.ByteStream stream: stream to write to
+//| :param Optional[~circuitpython_typing.Callable[[object], None]] default:
+//| function called for python objects that do not have
+//| a representation in msgpack format.
+//| """
+//| ...
+//|
+STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_obj, ARG_buffer, ARG_default };
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_obj, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_stream, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_default, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t handler = args[ARG_default].u_obj;
+ if (handler != mp_const_none && !mp_obj_is_fun(handler) && !MP_OBJ_IS_METH(handler)) {
+ mp_raise_ValueError(translate("default is not a function"));
+ }
+
+ common_hal_msgpack_pack(args[ARG_obj].u_obj, args[ARG_buffer].u_obj, handler);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_pack_obj, 0, mod_msgpack_pack);
+
+
+//| def unpack(stream: circuitpython_typing.ByteStream, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object:
+//| """Unpack and return one object from stream.
+//|
+//| :param ~circuitpython_typing.ByteStream stream: stream to read from
+//| :param Optional[~circuitpython_typing.Callable[[int, bytes], object]] ext_hook: function called for objects in
+//| msgpack ext format.
+//| :param Optional[bool] use_list: return array as list or tuple (use_list=False).
+//|
+//| :return object: object read from stream.
+//| """
+//| ...
+//|
+STATIC mp_obj_t mod_msgpack_unpack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_buffer, ARG_ext_hook, ARG_use_list };
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_stream, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+ { MP_QSTR_ext_hook, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } },
+ { MP_QSTR_use_list, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t hook = args[ARG_ext_hook].u_obj;
+ if (hook != mp_const_none && !mp_obj_is_fun(hook) && !MP_OBJ_IS_METH(hook)) {
+ mp_raise_ValueError(translate("ext_hook is not a function"));
+ }
+
+ return common_hal_msgpack_unpack(args[ARG_buffer].u_obj, hook, args[ARG_use_list].u_bool);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_unpack_obj, 0, mod_msgpack_unpack);
+
+
+STATIC const mp_rom_map_elem_t msgpack_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_msgpack) },
+ { MP_ROM_QSTR(MP_QSTR_ExtType), MP_ROM_PTR(&mod_msgpack_exttype_type) },
+ { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&mod_msgpack_pack_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&mod_msgpack_unpack_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(msgpack_module_globals, msgpack_module_globals_table);
+
+const mp_obj_module_t msgpack_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&msgpack_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_msgpack, msgpack_module, CIRCUITPY_MSGPACK);
diff --git a/circuitpython/shared-bindings/msgpack/__init__.h b/circuitpython/shared-bindings/msgpack/__init__.h
new file mode 100644
index 0000000..a02ead0
--- /dev/null
+++ b/circuitpython/shared-bindings/msgpack/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H
+
+#include "py/obj.h"
+
+// nothing for now
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H
diff --git a/circuitpython/shared-bindings/multiterminal/__init__.c b/circuitpython/shared-bindings/multiterminal/__init__.c
new file mode 100644
index 0000000..f3f8d1a
--- /dev/null
+++ b/circuitpython/shared-bindings/multiterminal/__init__.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "shared-bindings/multiterminal/__init__.h"
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| """Manage additional terminal sources
+//|
+//| The `multiterminal` module allows you to configure an additional serial
+//| terminal source. Incoming characters are accepted from both the internal
+//| serial connection and the optional secondary connection."""
+//|
+
+//| def get_secondary_terminal() -> Optional[typing.BinaryIO]:
+//| """Returns the current secondary terminal."""
+//| ...
+//|
+STATIC mp_obj_t multiterminal_obj_get_secondary_terminal() {
+ return common_hal_multiterminal_get_secondary_terminal();
+}
+MP_DEFINE_CONST_FUN_OBJ_0(multiterminal_get_secondary_terminal_obj, multiterminal_obj_get_secondary_terminal);
+
+//| def set_secondary_terminal(stream: typing.BinaryIO) -> None:
+//| """Read additional input from the given stream and write out back to it.
+//| This doesn't replace the core stream (usually UART or native USB) but is
+//| mixed in instead.
+//|
+//| :param stream stream: secondary stream"""
+//| ...
+//|
+STATIC mp_obj_t multiterminal_obj_set_secondary_terminal(mp_obj_t secondary_terminal) {
+ mp_obj_t write_m[3];
+ mp_load_method_maybe(secondary_terminal, MP_QSTR_write, write_m);
+ mp_obj_t readinto_m[3];
+ mp_load_method_maybe(secondary_terminal, MP_QSTR_readinto, readinto_m);
+ if (write_m[0] == MP_OBJ_NULL || readinto_m[0] == MP_OBJ_NULL) {
+ mp_raise_ValueError(translate("Stream missing readinto() or write() method."));
+ return mp_const_none;
+ }
+ common_hal_multiterminal_set_secondary_terminal(secondary_terminal);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(multiterminal_set_secondary_terminal_obj, multiterminal_obj_set_secondary_terminal);
+
+//| def clear_secondary_terminal() -> None:
+//| """Clears the secondary terminal."""
+//| ...
+//|
+STATIC mp_obj_t multiterminal_obj_clear_secondary_terminal() {
+ common_hal_multiterminal_clear_secondary_terminal();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(multiterminal_clear_secondary_terminal_obj, multiterminal_obj_clear_secondary_terminal);
+
+//| def schedule_secondary_terminal_read(socket: socket.socket) -> None:
+//| """In cases where the underlying OS is doing task scheduling, this notifies
+//| the OS when more data is available on the socket to read. This is useful
+//| as a callback for lwip sockets."""
+//| ...
+//|
+// TODO(tannewt): This is a funny API. Replace it with a direct call into the OS
+// by the lwip object.
+STATIC mp_obj_t multiterminal_obj_schedule_secondary_terminal_read(mp_obj_t socket) {
+ common_hal_multiterminal_schedule_secondary_terminal_read(socket);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(multiterminal_schedule_secondary_terminal_read_obj, multiterminal_obj_schedule_secondary_terminal_read);
+
+// TODO(tannewt): Expose the internal serial connection as `primary_terminal`
+
+STATIC const mp_rom_map_elem_t multiterminal_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_multiterminal) },
+ { MP_ROM_QSTR(MP_QSTR_get_secondary_terminal), MP_ROM_PTR(&multiterminal_get_secondary_terminal_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_secondary_terminal), MP_ROM_PTR(&multiterminal_set_secondary_terminal_obj) },
+ { MP_ROM_QSTR(MP_QSTR_clear_secondary_terminal), MP_ROM_PTR(&multiterminal_clear_secondary_terminal_obj) },
+ { MP_ROM_QSTR(MP_QSTR_schedule_secondary_terminal_read), MP_ROM_PTR(&multiterminal_schedule_secondary_terminal_read_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(multiterminal_module_globals, multiterminal_module_globals_table);
+
+const mp_obj_module_t multiterminal_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&multiterminal_module_globals,
+};
diff --git a/circuitpython/shared-bindings/multiterminal/__init__.h b/circuitpython/shared-bindings/multiterminal/__init__.h
new file mode 100644
index 0000000..7c28842
--- /dev/null
+++ b/circuitpython/shared-bindings/multiterminal/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_BINDINGS_MULTITERMINAL___INIT___H
+#define SHARED_BINDINGS_MULTITERMINAL___INIT___H
+
+#include "py/obj.h"
+
+void common_hal_multiterminal_schedule_secondary_terminal_read(mp_obj_t socket);
+mp_obj_t common_hal_multiterminal_get_secondary_terminal();
+void common_hal_multiterminal_set_secondary_terminal(mp_obj_t secondary_terminal);
+void common_hal_multiterminal_clear_secondary_terminal();
+
+#endif // SHARED_BINDINGS_MULTITERMINAL___INIT___H
diff --git a/circuitpython/shared-bindings/neopixel_write/__init__.c b/circuitpython/shared-bindings/neopixel_write/__init__.c
new file mode 100644
index 0000000..d0234fe
--- /dev/null
+++ b/circuitpython/shared-bindings/neopixel_write/__init__.c
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "shared-bindings/neopixel_write/__init__.h"
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "shared-bindings/digitalio/DigitalInOut.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+// RGB LED timing information:
+
+// From the WS2811 datasheet: high speed mode
+// - T0H 0 code,high voltage time 0.25 us +-150ns
+// - T1H 1 code,high voltage time 0.6 us +-150ns
+// - T0L 0 code,low voltage time 1.0 us +-150ns
+// - T1L 1 code,low voltage time 0.65 us +-150ns
+// - RES low voltage time Above 50us
+
+// From the SK6812 datasheet:
+// - T0H 0 code, high level time 0.3us +-0.15us
+// - T1H 1 code, high level time 0.6us +-0.15us
+// - T0L 0 code, low level time 0.9us +-0.15us
+// - T1L 1 code, low level time 0.6us +-0.15us
+// - Trst Reset code,low level time 80us
+
+// From the WS2812 datasheet:
+// - T0H 0 code, high voltage time 0.35us +-150ns
+// - T1H 1 code, high voltage time 0.7us +-150ns
+// - T0L 0 code, low voltage time 0.8us +-150ns
+// - T1L 1 code, low voltage time 0.6us +-150ns
+// - RES low voltage time Above 50us
+
+// From the WS28212B datasheet:
+// - T0H 0 code, high voltage time 0.4us +-150ns
+// - T1H 1 code, high voltage time 0.8us +-150ns
+// - T0L 0 code, low voltage time 0.85us +-150ns
+// - T1L 1 code, low voltage time 0.45us +-150ns
+// - RES low voltage time Above 50us
+
+// The timings used in various ports do not always follow the guidelines above.
+// In general, a zero bit is about 300ns high, 900ns low.
+// A one bit is about 700ns high, 500ns low.
+// But the ports vary based on implementation considerations; the proof is in the testing.
+// https://adafru.it/5225 is more sensitive to timing and should be included in testing.
+
+STATIC void check_for_deinit(digitalio_digitalinout_obj_t *self) {
+ if (common_hal_digitalio_digitalinout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| """Low-level neopixel implementation
+//|
+//| The `neopixel_write` module contains a helper method to write out bytes in
+//| the 800khz neopixel protocol.
+//|
+//| For example, to turn off a single neopixel (like the status pixel on Express
+//| boards.)
+//|
+//| .. code-block:: python
+//|
+//| import board
+//| import neopixel_write
+//| import digitalio
+//|
+//| pin = digitalio.DigitalInOut(board.NEOPIXEL)
+//| pin.direction = digitalio.Direction.OUTPUT
+//| pixel_off = bytearray([0, 0, 0])
+//| neopixel_write.neopixel_write(pin, pixel_off)
+//|
+//| .. note::
+//|
+//| This module is typically not used by user level code.
+//|
+//| For more information on actually using NeoPixels, refer to the `CircuitPython
+//| Essentials Learn guide <https://learn.adafruit.com/circuitpython-essentials/circuitpython-neopixel>`_
+//|
+//| For a much more thorough guide about using NeoPixels, refer to the `Adafruit NeoPixel Überguide
+//| <https://learn.adafruit.com/adafruit-neopixel-uberguide>`_.
+//|
+//| """
+//|
+//| def neopixel_write(digitalinout: digitalio.DigitalInOut, buf: ReadableBuffer) -> None:
+//| """Write buf out on the given DigitalInOut.
+//|
+//| :param ~digitalio.DigitalInOut digitalinout: the DigitalInOut to output with
+//| :param ~circuitpython_typing.ReadableBuffer buf: The bytes to clock out. No assumption is made about color order"""
+//| ...
+STATIC mp_obj_t neopixel_write_neopixel_write_(mp_obj_t digitalinout_obj, mp_obj_t buf) {
+ if (!mp_obj_is_type(digitalinout_obj, &digitalio_digitalinout_type)) {
+ mp_raise_TypeError_varg(translate("Expected a %q"), digitalio_digitalinout_type.name);
+ }
+
+ // Convert parameters into expected types.
+ const digitalio_digitalinout_obj_t *digitalinout = MP_OBJ_TO_PTR(digitalinout_obj);
+
+ // Check to see if the NeoPixel has been deinited before writing to it.
+ check_for_deinit(digitalinout_obj);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ // Call platform's neopixel write function with provided buffer and options.
+ common_hal_neopixel_write(digitalinout, (uint8_t *)bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(neopixel_write_neopixel_write_obj, neopixel_write_neopixel_write_);
+
+STATIC const mp_rom_map_elem_t neopixel_write_module_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&neopixel_write_neopixel_write_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(neopixel_write_module_globals, neopixel_write_module_globals_table);
+
+const mp_obj_module_t neopixel_write_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&neopixel_write_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_neopixel_write, neopixel_write_module, CIRCUITPY_NEOPIXEL_WRITE);
diff --git a/circuitpython/shared-bindings/neopixel_write/__init__.h b/circuitpython/shared-bindings/neopixel_write/__init__.h
new file mode 100644
index 0000000..89b087d
--- /dev/null
+++ b/circuitpython/shared-bindings/neopixel_write/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "common-hal/digitalio/DigitalInOut.h"
+
+extern void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *gpio, uint8_t *pixels, uint32_t numBytes);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_NEOPIXEL_WRITE_H
diff --git a/circuitpython/shared-bindings/nvm/ByteArray.c b/circuitpython/shared-bindings/nvm/ByteArray.c
new file mode 100644
index 0000000..6e34b76
--- /dev/null
+++ b/circuitpython/shared-bindings/nvm/ByteArray.c
@@ -0,0 +1,178 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/nvm/ByteArray.h"
+#include "supervisor/shared/translate.h"
+
+//| class ByteArray:
+//| r"""Presents a stretch of non-volatile memory as a bytearray.
+//|
+//| Non-volatile memory is available as a byte array that persists over reloads
+//| and power cycles. Each assignment causes an erase and write cycle so its recommended to assign
+//| all values to change at once.
+//|
+//| Usage::
+//|
+//| import microcontroller
+//| microcontroller.nvm[0:3] = b"\xcc\x10\x00"
+//| """
+//|
+
+//| def __init__(self) -> None:
+//| """Not currently dynamically supported. Access the sole instance through `microcontroller.nvm`."""
+//| ...
+//|
+
+//| def __bool__(self) -> bool:
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Return the length. This is used by (`len`)"""
+//| ...
+//|
+STATIC mp_obj_t nvm_bytearray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ nvm_bytearray_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint16_t len = common_hal_nvm_bytearray_get_length(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC const mp_rom_map_elem_t nvm_bytearray_locals_dict_table[] = {
+};
+
+STATIC MP_DEFINE_CONST_DICT(nvm_bytearray_locals_dict, nvm_bytearray_locals_dict_table);
+
+//| @overload
+//| def __getitem__(self, index: slice) -> bytearray: ...
+//| @overload
+//| def __getitem__(self, index: int) -> int:
+//| """Returns the value at the given index."""
+//| ...
+//|
+//| @overload
+//| def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ...
+//| @overload
+//| def __setitem__(self, index: int, value: int) -> None:
+//| """Set the value at the given index."""
+//| ...
+//|
+STATIC mp_obj_t nvm_bytearray_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {
+ if (value == MP_OBJ_NULL) {
+ // delete item
+ // slice deletion
+ return MP_OBJ_NULL; // op not supported
+ } else {
+ nvm_bytearray_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (0) {
+ #if MICROPY_PY_BUILTINS_SLICE
+ } else if (mp_obj_is_type(index_in, &mp_type_slice)) {
+ mp_bound_slice_t slice;
+ if (!mp_seq_get_fast_slice_indexes(common_hal_nvm_bytearray_get_length(self), index_in, &slice)) {
+ mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported"));
+ }
+ if (value != MP_OBJ_SENTINEL) {
+ #if MICROPY_PY_ARRAY_SLICE_ASSIGN
+ // Assign
+ size_t src_len = slice.stop - slice.start;
+ uint8_t *src_items;
+ if (mp_obj_is_type(value, &mp_type_array) ||
+ mp_obj_is_type(value, &mp_type_bytearray) ||
+ mp_obj_is_type(value, &mp_type_memoryview) ||
+ mp_obj_is_type(value, &mp_type_bytes)) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != src_len) {
+ mp_raise_ValueError(translate("Slice and value different lengths."));
+ }
+ src_len = bufinfo.len;
+ src_items = bufinfo.buf;
+ if (1 != mp_binary_get_size('@', bufinfo.typecode, NULL)) {
+ mp_raise_ValueError(translate("Array values should be single bytes."));
+ }
+ } else {
+ mp_raise_NotImplementedError(translate("array/bytes required on right side"));
+ }
+
+ if (!common_hal_nvm_bytearray_set_bytes(self, slice.start, src_items, src_len)) {
+ mp_raise_RuntimeError(translate("Unable to write to nvm."));
+ }
+ return mp_const_none;
+ #else
+ return MP_OBJ_NULL; // op not supported
+ #endif
+ } else {
+ // Read slice.
+ size_t len = slice.stop - slice.start;
+ uint8_t *items = m_new(uint8_t, len);
+ common_hal_nvm_bytearray_get_bytes(self, slice.start, len, items);
+ return mp_obj_new_bytearray_by_ref(len, items);
+ }
+ #endif
+ } else {
+ // Single index rather than slice.
+ size_t index = mp_get_index(self->base.type, common_hal_nvm_bytearray_get_length(self),
+ index_in, false);
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ uint8_t value_out;
+ common_hal_nvm_bytearray_get_bytes(self, index, 1, &value_out);
+ return MP_OBJ_NEW_SMALL_INT(value_out);
+ } else {
+ // store
+ mp_int_t byte_value = mp_obj_get_int(value);
+ if (byte_value > 0xff || byte_value < 0) {
+ mp_raise_ValueError(translate("Bytes must be between 0 and 255."));
+ }
+ uint8_t short_value = byte_value;
+ if (!common_hal_nvm_bytearray_set_bytes(self, index, &short_value, 1)) {
+ mp_raise_RuntimeError(translate("Unable to write to nvm."));
+ }
+ return mp_const_none;
+ }
+ }
+ }
+}
+
+const mp_obj_type_t nvm_bytearray_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_ByteArray,
+ .locals_dict = (mp_obj_t)&nvm_bytearray_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = nvm_bytearray_subscr,
+ .unary_op = nvm_bytearray_unary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/nvm/ByteArray.h b/circuitpython/shared-bindings/nvm/ByteArray.h
new file mode 100644
index 0000000..c0446b5
--- /dev/null
+++ b/circuitpython/shared-bindings/nvm/ByteArray.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_NVM_BYTEARRAY_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_NVM_BYTEARRAY_H
+
+#include "common-hal/nvm/ByteArray.h"
+
+extern const mp_obj_type_t nvm_bytearray_type;
+
+uint32_t common_hal_nvm_bytearray_get_length(const nvm_bytearray_obj_t *self);
+
+bool common_hal_nvm_bytearray_set_bytes(const nvm_bytearray_obj_t *self,
+ uint32_t start_index, uint8_t *values, uint32_t len);
+// len and values are intentionally swapped to signify values is an output and
+// also leverage the compiler to validate uses are expected.
+void common_hal_nvm_bytearray_get_bytes(const nvm_bytearray_obj_t *self,
+ uint32_t start_index, uint32_t len, uint8_t *values);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_NVM_BYTEARRAY_H
diff --git a/circuitpython/shared-bindings/nvm/__init__.c b/circuitpython/shared-bindings/nvm/__init__.c
new file mode 100644
index 0000000..dffc4cd
--- /dev/null
+++ b/circuitpython/shared-bindings/nvm/__init__.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/nvm/__init__.h"
+#include "shared-bindings/nvm/ByteArray.h"
+
+//| """Non-volatile memory
+//|
+//| The `nvm` module allows you to store whatever raw bytes you wish in a
+//| reserved section non-volatile memory.
+//|
+//| Note that this module can't be imported and used directly. The sole
+//| instance of :class:`ByteArray` is available at
+//| :attr:`microcontroller.nvm`."""
+//|
+STATIC const mp_rom_map_elem_t nvm_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_nvm) },
+ { MP_ROM_QSTR(MP_QSTR_ByteArray), MP_ROM_PTR(&nvm_bytearray_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(nvm_module_globals, nvm_module_globals_table);
+
+const mp_obj_module_t nvm_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&nvm_module_globals,
+};
diff --git a/circuitpython/shared-bindings/nvm/__init__.h b/circuitpython/shared-bindings/nvm/__init__.h
new file mode 100644
index 0000000..9e17999
--- /dev/null
+++ b/circuitpython/shared-bindings/nvm/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_BINDINGS_NVM_H
+#define SHARED_BINDINGS_NVM_H
+
+#endif // SHARED_BINDINGS_NVM_H
diff --git a/circuitpython/shared-bindings/onewireio/OneWire.c b/circuitpython/shared-bindings/onewireio/OneWire.c
new file mode 100644
index 0000000..a167c86
--- /dev/null
+++ b/circuitpython/shared-bindings/onewireio/OneWire.c
@@ -0,0 +1,170 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/onewireio/OneWire.h"
+#include "shared-bindings/util.h"
+
+//| class OneWire:
+//| def __init__(self, pin: microcontroller.Pin) -> None:
+//| """Create a OneWire object associated with the given pin.
+//|
+//| The object implements the lowest level timing-sensitive bits of the protocol.
+//|
+//| :param ~microcontroller.Pin pin: Pin connected to the OneWire bus
+//|
+//| .. note:: The OneWire class is available on `busio` and `bitbangio` in CircuitPython
+//| 7.x for backwards compatibility but will be removed in CircuitPython 8.0.0.
+//|
+//| Read a short series of pulses::
+//|
+//| import onewireio
+//| import board
+//|
+//| onewire = onewireio.OneWire(board.D7)
+//| onewire.reset()
+//| onewire.write_bit(True)
+//| onewire.write_bit(False)
+//| print(onewire.read_bit())"""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+
+ onewireio_onewire_obj_t *self = m_new_obj(onewireio_onewire_obj_t);
+ self->base.type = &onewireio_onewire_type;
+
+ common_hal_onewireio_onewire_construct(self, pin);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialize the OneWire bus and release any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_deinit(mp_obj_t self_in) {
+ onewireio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_onewireio_onewire_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewireio_onewire_deinit_obj, onewireio_onewire_deinit);
+
+STATIC void check_for_deinit(onewireio_onewire_obj_t *self) {
+ if (common_hal_onewireio_onewire_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> OneWire:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_onewireio_onewire_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(onewireio_onewire___exit___obj, 4, 4, onewireio_onewire_obj___exit__);
+
+//| def reset(self) -> bool:
+//| """Reset the OneWire bus and read presence
+//|
+//| :returns: False when at least one device is present
+//| :rtype: bool"""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_obj_reset(mp_obj_t self_in) {
+ onewireio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_bool(common_hal_onewireio_onewire_reset(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(onewireio_onewire_reset_obj, onewireio_onewire_obj_reset);
+
+//| def read_bit(self) -> bool:
+//| """Read in a bit
+//|
+//| :returns: bit state read
+//| :rtype: bool"""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_obj_read_bit(mp_obj_t self_in) {
+ onewireio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_bool(common_hal_onewireio_onewire_read_bit(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(onewireio_onewire_read_bit_obj, onewireio_onewire_obj_read_bit);
+
+//| def write_bit(self, value: bool) -> None:
+//| """Write out a bit based on value."""
+//| ...
+//|
+STATIC mp_obj_t onewireio_onewire_obj_write_bit(mp_obj_t self_in, mp_obj_t bool_obj) {
+ onewireio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_onewireio_onewire_write_bit(self, mp_obj_is_true(bool_obj));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(onewireio_onewire_write_bit_obj, onewireio_onewire_obj_write_bit);
+
+STATIC const mp_rom_map_elem_t onewireio_onewire_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&onewireio_onewire_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&onewireio_onewire___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&onewireio_onewire_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read_bit), MP_ROM_PTR(&onewireio_onewire_read_bit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_bit), MP_ROM_PTR(&onewireio_onewire_write_bit_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(onewireio_onewire_locals_dict, onewireio_onewire_locals_dict_table);
+
+const mp_obj_type_t onewireio_onewire_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_OneWire,
+ .make_new = onewireio_onewire_make_new,
+ .locals_dict = (mp_obj_dict_t *)&onewireio_onewire_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/onewireio/OneWire.h b/circuitpython/shared-bindings/onewireio/OneWire.h
new file mode 100644
index 0000000..c6d0fd6
--- /dev/null
+++ b/circuitpython/shared-bindings/onewireio/OneWire.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO_ONEWIRE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO_ONEWIRE_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-module/onewireio/OneWire.h"
+
+extern const mp_obj_type_t onewireio_onewire_type;
+
+extern void common_hal_onewireio_onewire_construct(onewireio_onewire_obj_t *self,
+ const mcu_pin_obj_t *pin);
+extern void common_hal_onewireio_onewire_deinit(onewireio_onewire_obj_t *self);
+extern bool common_hal_onewireio_onewire_deinited(onewireio_onewire_obj_t *self);
+extern bool common_hal_onewireio_onewire_reset(onewireio_onewire_obj_t *self);
+extern bool common_hal_onewireio_onewire_read_bit(onewireio_onewire_obj_t *self);
+extern void common_hal_onewireio_onewire_write_bit(onewireio_onewire_obj_t *self, bool bit);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO_ONEWIRE_H
diff --git a/circuitpython/shared-bindings/onewireio/__init__.c b/circuitpython/shared-bindings/onewireio/__init__.c
new file mode 100644
index 0000000..45d78b2
--- /dev/null
+++ b/circuitpython/shared-bindings/onewireio/__init__.c
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/onewireio/__init__.h"
+#include "shared-bindings/onewireio/OneWire.h"
+
+#include "py/runtime.h"
+
+//| """Low-level bit primitives for Maxim (formerly Dallas Semi) one-wire protocol.
+//|
+//| Protocol definition is here: https://www.maximintegrated.com/en/app-notes/index.mvp/id/126"""
+//|
+
+STATIC const mp_rom_map_elem_t onewireio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_onewireio) },
+ { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&onewireio_onewire_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(onewireio_module_globals, onewireio_module_globals_table);
+
+const mp_obj_module_t onewireio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&onewireio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_onewireio, onewireio_module, CIRCUITPY_ONEWIREIO);
diff --git a/circuitpython/shared-bindings/onewireio/__init__.h b/circuitpython/shared-bindings/onewireio/__init__.h
new file mode 100644
index 0000000..25384f6
--- /dev/null
+++ b/circuitpython/shared-bindings/onewireio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ONEWIREIO___INIT___H
diff --git a/circuitpython/shared-bindings/os/__init__.c b/circuitpython/shared-bindings/os/__init__.c
new file mode 100644
index 0000000..2daca52
--- /dev/null
+++ b/circuitpython/shared-bindings/os/__init__.c
@@ -0,0 +1,250 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "extmod/vfs.h"
+#include "lib/oofatfs/ff.h"
+#include "lib/oofatfs/diskio.h"
+#include "py/mpstate.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/os/__init__.h"
+
+//| """functions that an OS normally provides
+//|
+//| |see_cpython_module| :mod:`cpython:os`.
+//| """
+//|
+//| import typing
+
+//| def uname() -> _Uname:
+//| """Returns a named tuple of operating specific and CircuitPython port
+//| specific information."""
+//| ...
+//|
+//| class _Uname(typing.NamedTuple):
+//| """The type of values that :py:func:`.uname()` returns"""
+//|
+//| sysname: str
+//| nodename: str
+//| release: str
+//| version: str
+//| machine: str
+//|
+STATIC mp_obj_t os_uname(void) {
+ return common_hal_os_uname();
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
+
+//| def chdir(path: str) -> None:
+//| """Change current directory."""
+//| ...
+//|
+STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ common_hal_os_chdir(path);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
+
+//| def getcwd() -> str:
+//| """Get the current directory."""
+//| ...
+//|
+STATIC mp_obj_t os_getcwd(void) {
+ return common_hal_os_getcwd();
+}
+MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
+
+//| def listdir(dir: str) -> str:
+//| """With no argument, list the current directory. Otherwise list the given directory."""
+//| ...
+//|
+STATIC mp_obj_t os_listdir(size_t n_args, const mp_obj_t *args) {
+ const char *path;
+ if (n_args == 1) {
+ path = mp_obj_str_get_str(args[0]);
+ } else {
+ path = mp_obj_str_get_str(common_hal_os_getcwd());
+ }
+ return common_hal_os_listdir(path);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
+
+//| def mkdir(path: str) -> None:
+//| """Create a new directory."""
+//| ...
+//|
+STATIC mp_obj_t os_mkdir(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ common_hal_os_mkdir(path);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
+
+//| def remove(path: str) -> None:
+//| """Remove a file."""
+//| ...
+//|
+STATIC mp_obj_t os_remove(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ common_hal_os_remove(path);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
+
+//| def rmdir(path: str) -> None:
+//| """Remove a directory."""
+//| ...
+//|
+STATIC mp_obj_t os_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) {
+ const char *old_path = mp_obj_str_get_str(old_path_in);
+ const char *new_path = mp_obj_str_get_str(new_path_in);
+ common_hal_os_rename(old_path, new_path);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
+
+//| def rename(old_path: str, new_path: str) -> str:
+//| """Rename a file."""
+//| ...
+//|
+STATIC mp_obj_t os_rmdir(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ common_hal_os_rmdir(path);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir);
+
+//| def stat(path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+//| """Get the status of a file or directory.
+//|
+//| .. note:: On builds without long integers, the number of seconds
+//| for contemporary dates will not fit in a small integer.
+//| So the time fields return 946684800,
+//| which is the number of seconds corresponding to 1999-12-31."""
+//| ...
+//|
+STATIC mp_obj_t os_stat(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ return common_hal_os_stat(path);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
+
+//| def statvfs(path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+//| """Get the status of a filesystem.
+//|
+//| Returns a tuple with the filesystem information in the following order:
+//|
+//| * ``f_bsize`` -- file system block size
+//| * ``f_frsize`` -- fragment size
+//| * ``f_blocks`` -- size of fs in f_frsize units
+//| * ``f_bfree`` -- number of free blocks
+//| * ``f_bavail`` -- number of free blocks for unprivileged users
+//| * ``f_files`` -- number of inodes
+//| * ``f_ffree`` -- number of free inodes
+//| * ``f_favail`` -- number of free inodes for unprivileged users
+//| * ``f_flag`` -- mount flags
+//| * ``f_namemax`` -- maximum filename length
+//|
+//| Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
+//| and the ``f_flags`` parameter may return ``0`` as they can be unavailable
+//| in a port-specific implementation."""
+//| ...
+//|
+STATIC mp_obj_t os_statvfs(mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ return common_hal_os_statvfs(path);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_statvfs_obj, os_statvfs);
+
+//| def sync() -> None:
+//| """Sync all filesystems."""
+//| ...
+//|
+STATIC mp_obj_t os_sync(void) {
+ for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
+ // this assumes that vfs->obj is fs_user_mount_t with block device functions
+ disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
+
+//| def urandom(size: int) -> str:
+//| """Returns a string of *size* random bytes based on a hardware True Random
+//| Number Generator. When not available, it will raise a NotImplementedError."""
+//| ...
+//|
+STATIC mp_obj_t os_urandom(mp_obj_t size_in) {
+ mp_int_t size = mp_obj_get_int(size_in);
+ mp_obj_str_t *result = MP_OBJ_TO_PTR(mp_obj_new_bytes_of_zeros(size));
+ if (!common_hal_os_urandom((uint8_t *)result->data, size)) {
+ mp_raise_NotImplementedError(translate("No hardware random available"));
+ }
+ return result;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
+
+STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
+
+ { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&os_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&os_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&os_listdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&os_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&os_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&os_statvfs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&os_remove_obj) }, // unlink aliases to remove
+
+ { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&os_sync_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
+
+//|
+//| sep: str
+//| """Separator used to delineate path components such as folder and file names."""
+//|
+ { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t os_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&os_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_os, os_module, CIRCUITPY_OS);
diff --git a/circuitpython/shared-bindings/os/__init__.h b/circuitpython/shared-bindings/os/__init__.h
new file mode 100644
index 0000000..f6f0a25
--- /dev/null
+++ b/circuitpython/shared-bindings/os/__init__.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_OS___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_OS___INIT___H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/objtuple.h"
+
+extern const mp_rom_obj_tuple_t common_hal_os_uname_info_obj;
+
+mp_obj_t common_hal_os_uname(void);
+void common_hal_os_chdir(const char *path);
+mp_obj_t common_hal_os_getcwd(void);
+mp_obj_t common_hal_os_listdir(const char *path);
+void common_hal_os_mkdir(const char *path);
+void common_hal_os_remove(const char *path);
+void common_hal_os_rename(const char *old_path, const char *new_path);
+void common_hal_os_rmdir(const char *path);
+mp_obj_t common_hal_os_stat(const char *path);
+mp_obj_t common_hal_os_statvfs(const char *path);
+
+// Returns true if data was correctly sourced from a true random number generator.
+bool common_hal_os_urandom(uint8_t *buffer, mp_uint_t length);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_OS___INIT___H
diff --git a/circuitpython/shared-bindings/paralleldisplay/ParallelBus.c b/circuitpython/shared-bindings/paralleldisplay/ParallelBus.c
new file mode 100644
index 0000000..6e6e778
--- /dev/null
+++ b/circuitpython/shared-bindings/paralleldisplay/ParallelBus.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/paralleldisplay/ParallelBus.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| class ParallelBus:
+//| """Manage updating a display over 8-bit parallel bus in the background while Python code runs. This
+//| protocol may be refered to as 8080-I Series Parallel Interface in datasheets. It doesn't handle
+//| display initialization."""
+//|
+//| def __init__(self, *, data0: microcontroller.Pin, command: microcontroller.Pin, chip_select: microcontroller.Pin, write: microcontroller.Pin, read: Optional[microcontroller.Pin], reset: Optional[microcontroller.Pin] = None, frequency: int = 30_000_000) -> None:
+//| """Create a ParallelBus object associated with the given pins. The bus is inferred from data0
+//| by implying the next 7 additional pins on a given GPIO port.
+//|
+//| The parallel bus and pins are then in use by the display until `displayio.release_displays()`
+//| is called even after a reload. (It does this so CircuitPython can use the display after your
+//| code is done.) So, the first time you initialize a display bus in code.py you should call
+//| :py:func:`displayio.release_displays` first, otherwise it will error after the first code.py run.
+//|
+//| :param microcontroller.Pin data_pins: A list of data pins. Specify exactly one of ``data_pins`` or ``data0``.
+//| :param microcontroller.Pin data0: The first data pin. The rest are implied
+//| :param microcontroller.Pin command: Data or command pin
+//| :param microcontroller.Pin chip_select: Chip select pin
+//| :param microcontroller.Pin write: Write pin
+//| :param microcontroller.Pin read: Read pin, optional
+//| :param microcontroller.Pin reset: Reset pin, optional
+//| :param int frequency: The communication frequency in Hz for the display on the bus"""
+//| ...
+//|
+STATIC mp_obj_t paralleldisplay_parallelbus_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_data0, ARG_data_pins, ARG_command, ARG_chip_select, ARG_write, ARG_read, ARG_reset, ARG_frequency };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data0, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
+ { MP_QSTR_data_pins, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
+ { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_write, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_read, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
+ { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none } },
+ { MP_QSTR_frequency, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 30000000 } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
+ const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ const mcu_pin_obj_t *write = validate_obj_is_free_pin(args[ARG_write].u_obj);
+ const mcu_pin_obj_t *read = validate_obj_is_free_pin_or_none(args[ARG_read].u_obj);
+ const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj);
+
+ paralleldisplay_parallelbus_obj_t *self = &allocate_display_bus_or_raise()->parallel_bus;
+ self->base.type = &paralleldisplay_parallelbus_type;
+
+ bool specified_data0 = args[ARG_data0].u_obj != mp_const_none;
+ bool specified_data_pins = args[ARG_data_pins].u_obj != mp_const_none;
+
+ if (specified_data0 == specified_data_pins) {
+ mp_raise_ValueError(translate("Specify exactly one of data0 or data_pins"));
+ }
+
+ if (specified_data0) {
+ const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj);
+ common_hal_paralleldisplay_parallelbus_construct(self, data0, command, chip_select, write, read, reset, args[ARG_frequency].u_int);
+ } else {
+ uint8_t num_pins;
+ const mcu_pin_obj_t *data_pins[16];
+ validate_list_is_free_pins(MP_QSTR_data_pins, data_pins, (mp_int_t)MP_ARRAY_SIZE(data_pins), args[ARG_data_pins].u_obj, &num_pins);
+ common_hal_paralleldisplay_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, args[ARG_frequency].u_int);
+ }
+ return self;
+}
+
+//| def reset(self) -> None:
+//| """Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin
+//| is available."""
+//| ...
+//|
+
+STATIC mp_obj_t paralleldisplay_parallelbus_obj_reset(mp_obj_t self_in) {
+ paralleldisplay_parallelbus_obj_t *self = self_in;
+
+ if (!common_hal_paralleldisplay_parallelbus_reset(self)) {
+ mp_raise_RuntimeError(translate("no reset pin available"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(paralleldisplay_parallelbus_reset_obj, paralleldisplay_parallelbus_obj_reset);
+
+//| def send(self, command: int, data: ReadableBuffer) -> None:
+//| """Sends the given command value followed by the full set of data. Display state, such as
+//| vertical scroll, set via ``send`` may or may not be reset once the code is done."""
+//| ...
+//|
+STATIC mp_obj_t paralleldisplay_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) {
+ mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj);
+ if (!mp_obj_is_small_int(command_obj) || command_int > 255 || command_int < 0) {
+ mp_raise_ValueError(translate("Command must be an int between 0 and 255"));
+ }
+ uint8_t command = command_int;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ);
+
+ // Wait for display bus to be available.
+ while (!common_hal_paralleldisplay_parallelbus_begin_transaction(self)) {
+ RUN_BACKGROUND_TASKS;
+ }
+ common_hal_paralleldisplay_parallelbus_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1);
+ common_hal_paralleldisplay_parallelbus_send(self, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t *)bufinfo.buf), bufinfo.len);
+ common_hal_paralleldisplay_parallelbus_end_transaction(self);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(paralleldisplay_parallelbus_send_obj, paralleldisplay_parallelbus_obj_send);
+
+STATIC const mp_rom_map_elem_t paralleldisplay_parallelbus_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&paralleldisplay_parallelbus_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&paralleldisplay_parallelbus_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(paralleldisplay_parallelbus_locals_dict, paralleldisplay_parallelbus_locals_dict_table);
+
+const mp_obj_type_t paralleldisplay_parallelbus_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ParallelBus,
+ .make_new = paralleldisplay_parallelbus_make_new,
+ .locals_dict = (mp_obj_dict_t *)&paralleldisplay_parallelbus_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/paralleldisplay/ParallelBus.h b/circuitpython/shared-bindings/paralleldisplay/ParallelBus.h
new file mode 100644
index 0000000..e890683
--- /dev/null
+++ b/circuitpython/shared-bindings/paralleldisplay/ParallelBus.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "common-hal/paralleldisplay/ParallelBus.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/displayio/__init__.h"
+#include "shared-module/displayio/Group.h"
+
+extern const mp_obj_type_t paralleldisplay_parallelbus_type;
+
+void common_hal_paralleldisplay_parallelbus_construct(paralleldisplay_parallelbus_obj_t *self,
+ const mcu_pin_obj_t *data0, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select,
+ const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency);
+
+void common_hal_paralleldisplay_parallelbus_construct_nonsequential(paralleldisplay_parallelbus_obj_t *self,
+ uint8_t n_pins, const mcu_pin_obj_t **data_pins, const mcu_pin_obj_t *command, const mcu_pin_obj_t *chip_select,
+ const mcu_pin_obj_t *write, const mcu_pin_obj_t *read, const mcu_pin_obj_t *reset, uint32_t frequency);
+
+void common_hal_paralleldisplay_parallelbus_deinit(paralleldisplay_parallelbus_obj_t *self);
+
+bool common_hal_paralleldisplay_parallelbus_reset(mp_obj_t self);
+bool common_hal_paralleldisplay_parallelbus_bus_free(mp_obj_t self);
+
+bool common_hal_paralleldisplay_parallelbus_begin_transaction(mp_obj_t self);
+
+void common_hal_paralleldisplay_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type,
+ display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length);
+
+void common_hal_paralleldisplay_parallelbus_end_transaction(mp_obj_t self);
diff --git a/circuitpython/shared-bindings/paralleldisplay/__init__.c b/circuitpython/shared-bindings/paralleldisplay/__init__.c
new file mode 100644
index 0000000..e87479a
--- /dev/null
+++ b/circuitpython/shared-bindings/paralleldisplay/__init__.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/paralleldisplay/__init__.h"
+#include "shared-bindings/paralleldisplay/ParallelBus.h"
+
+//| """Native helpers for driving parallel displays"""
+
+
+STATIC const mp_rom_map_elem_t paralleldisplay_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_paralleldisplay) },
+ { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&paralleldisplay_parallelbus_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(paralleldisplay_module_globals, paralleldisplay_module_globals_table);
+
+const mp_obj_module_t paralleldisplay_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&paralleldisplay_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_paralleldisplay, paralleldisplay_module, CIRCUITPY_PARALLELDISPLAY);
diff --git a/circuitpython/shared-bindings/paralleldisplay/__init__.h b/circuitpython/shared-bindings/paralleldisplay/__init__.h
new file mode 100644
index 0000000..f7b4287
--- /dev/null
+++ b/circuitpython/shared-bindings/paralleldisplay/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/ps2io/Ps2.c b/circuitpython/shared-bindings/ps2io/Ps2.c
new file mode 100644
index 0000000..a0fb6d6
--- /dev/null
+++ b/circuitpython/shared-bindings/ps2io/Ps2.c
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/ps2io/Ps2.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class Ps2:
+//| """Communicate with a PS/2 keyboard or mouse
+//|
+//| Ps2 implements the PS/2 keyboard/mouse serial protocol, used in
+//| legacy devices. It is similar to UART but there are only two
+//| lines (Data and Clock). PS/2 devices are 5V, so bidirectional
+//| level converters must be used to connect the I/O lines to pins
+//| of 3.3V boards."""
+//|
+//| def __init__(self, data_pin: microcontroller.Pin, clock_pin: microcontroller.Pin) -> None:
+//| """Create a Ps2 object associated with the given pins.
+//|
+//| :param ~microcontroller.Pin data_pin: Pin tied to data wire.
+//| :param ~microcontroller.Pin clock_pin: Pin tied to clock wire.
+//| This pin must support interrupts.
+//|
+//| Read one byte from PS/2 keyboard and turn on Scroll Lock LED::
+//|
+//| import ps2io
+//| import board
+//|
+//| kbd = ps2io.Ps2(board.D10, board.D11)
+//|
+//| while len(kbd) == 0:
+//| pass
+//|
+//| print(kbd.popleft())
+//| print(kbd.sendcmd(0xed))
+//| print(kbd.sendcmd(0x01))"""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_datapin, ARG_clkpin };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_datapin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_clkpin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clkpin = validate_obj_is_free_pin(args[ARG_clkpin].u_obj);
+ const mcu_pin_obj_t *datapin = validate_obj_is_free_pin(args[ARG_datapin].u_obj);
+
+ ps2io_ps2_obj_t *self = m_new_obj(ps2io_ps2_obj_t);
+ self->base.type = &ps2io_ps2_type;
+
+ common_hal_ps2io_ps2_construct(self, datapin, clkpin);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the Ps2 and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_deinit(mp_obj_t self_in) {
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_ps2io_ps2_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_deinit_obj, ps2io_ps2_deinit);
+
+STATIC void check_for_deinit(ps2io_ps2_obj_t *self) {
+ if (common_hal_ps2io_ps2_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> Ps2:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ mp_check_self(mp_obj_is_type(args[0], &ps2io_ps2_type));
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ common_hal_ps2io_ps2_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ps2io_ps2___exit___obj, 4, 4, ps2io_ps2_obj___exit__);
+
+//| def popleft(self) -> int:
+//| """Removes and returns the oldest received byte. When buffer
+//| is empty, raises an IndexError exception."""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_obj_popleft(mp_obj_t self_in) {
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ int b = common_hal_ps2io_ps2_popleft(self);
+ if (b < 0) {
+ mp_raise_IndexError_varg(translate("pop from empty %q"), MP_QSTR_Ps2_space_buffer);
+ }
+ return MP_OBJ_NEW_SMALL_INT(b);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_popleft_obj, ps2io_ps2_obj_popleft);
+
+//| def sendcmd(self, byte: int) -> int:
+//| """Sends a command byte to PS/2. Returns the response byte, typically
+//| the general ack value (0xFA). Some commands return additional data
+//| which is available through :py:func:`popleft()`.
+//|
+//| Raises a RuntimeError in case of failure. The root cause can be found
+//| by calling :py:func:`clear_errors()`. It is advisable to call
+//| :py:func:`clear_errors()` before :py:func:`sendcmd()` to flush any
+//| previous errors.
+//|
+//| :param int byte: byte value of the command"""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_obj_sendcmd(mp_obj_t self_in, mp_obj_t ob) {
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ mp_int_t cmd = mp_obj_get_int(ob) & 0xff;
+ int resp = common_hal_ps2io_ps2_sendcmd(self, cmd);
+ if (resp < 0) {
+ mp_raise_RuntimeError(translate("Failed sending command."));
+ }
+ return MP_OBJ_NEW_SMALL_INT(resp);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(ps2io_ps2_sendcmd_obj, ps2io_ps2_obj_sendcmd);
+
+//| def clear_errors(self) -> None:
+//| """Returns and clears a bitmap with latest recorded communication errors.
+//|
+//| Reception errors (arise asynchronously, as data is received):
+//|
+//| 0x01: start bit not 0
+//|
+//| 0x02: timeout
+//|
+//| 0x04: parity bit error
+//|
+//| 0x08: stop bit not 1
+//|
+//| 0x10: buffer overflow, newest data discarded
+//|
+//| Transmission errors (can only arise in the course of sendcmd()):
+//|
+//| 0x100: clock pin didn't go to LO in time
+//|
+//| 0x200: clock pin didn't go to HI in time
+//|
+//| 0x400: data pin didn't ACK
+//|
+//| 0x800: clock pin didn't ACK
+//|
+//| 0x1000: device didn't respond to RTS
+//|
+//| 0x2000: device didn't send a response byte in time"""
+//| ...
+//|
+STATIC mp_obj_t ps2io_ps2_obj_clear_errors(mp_obj_t self_in) {
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_ps2io_ps2_clear_errors(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_clear_errors_obj, ps2io_ps2_obj_clear_errors);
+
+//| def __bool__(self) -> bool: ...
+//|
+//| def __len__(self) -> int:
+//| """Returns the number of received bytes in buffer, available
+//| to :py:func:`popleft()`."""
+//| ...
+//|
+STATIC mp_obj_t ps2_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ uint16_t len = common_hal_ps2io_ps2_get_len(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC const mp_rom_map_elem_t ps2io_ps2_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&ps2io_ps2_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&ps2io_ps2___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&ps2io_ps2_popleft_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendcmd), MP_ROM_PTR(&ps2io_ps2_sendcmd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_clear_errors), MP_ROM_PTR(&ps2io_ps2_clear_errors_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(ps2io_ps2_locals_dict, ps2io_ps2_locals_dict_table);
+
+const mp_obj_type_t ps2io_ps2_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Ps2,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = ps2io_ps2_make_new,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = ps2_unary_op,
+ ),
+ .locals_dict = (mp_obj_dict_t *)&ps2io_ps2_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/ps2io/Ps2.h b/circuitpython/shared-bindings/ps2io/Ps2.h
new file mode 100644
index 0000000..da4c6ba
--- /dev/null
+++ b/circuitpython/shared-bindings/ps2io/Ps2.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co>
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO_PS2_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO_PS2_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/ps2io/Ps2.h"
+
+extern const mp_obj_type_t ps2io_ps2_type;
+
+extern void common_hal_ps2io_ps2_construct(ps2io_ps2_obj_t *self,
+ const mcu_pin_obj_t *data_pin, const mcu_pin_obj_t *clk_pin);
+extern void common_hal_ps2io_ps2_deinit(ps2io_ps2_obj_t *self);
+extern bool common_hal_ps2io_ps2_deinited(ps2io_ps2_obj_t *self);
+extern uint16_t common_hal_ps2io_ps2_get_len(ps2io_ps2_obj_t *self);
+extern int16_t common_hal_ps2io_ps2_popleft(ps2io_ps2_obj_t *self);
+extern int16_t common_hal_ps2io_ps2_sendcmd(ps2io_ps2_obj_t *self, uint8_t b);
+extern uint16_t common_hal_ps2io_ps2_clear_errors(ps2io_ps2_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO_PS2_H
diff --git a/circuitpython/shared-bindings/ps2io/__init__.c b/circuitpython/shared-bindings/ps2io/__init__.c
new file mode 100644
index 0000000..517816d
--- /dev/null
+++ b/circuitpython/shared-bindings/ps2io/__init__.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/ps2io/Ps2.h"
+
+//| """Support for PS/2 protocol
+//|
+//| The `ps2io` module contains classes to provide PS/2 communication.
+//|
+
+//| .. warning:: This module is not available in some SAMD21 builds. See the
+//| :ref:`module-support-matrix` for more info.
+//|
+
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//|
+
+STATIC const mp_rom_map_elem_t ps2io_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ps2io) },
+ { MP_ROM_QSTR(MP_QSTR_Ps2), MP_ROM_PTR(&ps2io_ps2_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ps2io_module_globals, ps2io_module_globals_table);
+
+const mp_obj_module_t ps2io_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&ps2io_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_ps2io, ps2io_module, CIRCUITPY_PS2IO);
diff --git a/circuitpython/shared-bindings/ps2io/__init__.h b/circuitpython/shared-bindings/ps2io/__init__.h
new file mode 100644
index 0000000..1ff3d97
--- /dev/null
+++ b/circuitpython/shared-bindings/ps2io/__init__.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co>
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO___INIT___H
diff --git a/circuitpython/shared-bindings/pulseio/PulseIn.c b/circuitpython/shared-bindings/pulseio/PulseIn.c
new file mode 100644
index 0000000..21dfdae
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/PulseIn.c
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/pulseio/PulseIn.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class PulseIn:
+//| """Measure a series of active and idle pulses. This is commonly used in infrared receivers
+//| and low cost temperature sensors (DHT). The pulsed signal consists of timed active and
+//| idle periods. Unlike PWM, there is no set duration for active and idle pairs."""
+//|
+//| def __init__(self, pin: microcontroller.Pin, maxlen: int = 2, *, idle_state: bool = False) -> None:
+//| """Create a PulseIn object associated with the given pin. The object acts as
+//| a read-only sequence of pulse lengths with a given max length. When it is
+//| active, new pulse lengths are added to the end of the list. When there is
+//| no more room (len() == `maxlen`) the oldest pulse length is removed to
+//| make room.
+//|
+//| :param ~microcontroller.Pin pin: Pin to read pulses from.
+//| :param int maxlen: Maximum number of pulse durations to store at once
+//| :param bool idle_state: Idle state of the pin. At start and after `resume`
+//| the first recorded pulse will the opposite state from idle.
+//|
+//| Read a short series of pulses::
+//|
+//| import pulseio
+//| import board
+//|
+//| pulses = pulseio.PulseIn(board.D7)
+//|
+//| # Wait for an active pulse
+//| while len(pulses) == 0:
+//| pass
+//| # Pause while we do something with the pulses
+//| pulses.pause()
+//|
+//| # Print the pulses. pulses[0] is an active pulse unless the length
+//| # reached max length and idle pulses are recorded.
+//| print(pulses)
+//|
+//| # Clear the rest
+//| pulses.clear()
+//|
+//| # Resume with an 80 microsecond active pulse
+//| pulses.resume(80)"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin, ARG_maxlen, ARG_idle_state };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_maxlen, MP_ARG_INT, {.u_int = 2} },
+ { MP_QSTR_idle_state, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
+
+ pulseio_pulsein_obj_t *self = m_new_obj(pulseio_pulsein_obj_t);
+ self->base.type = &pulseio_pulsein_type;
+
+ common_hal_pulseio_pulsein_construct(self, pin, args[ARG_maxlen].u_int,
+ args[ARG_idle_state].u_bool);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the PulseIn and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_deinit(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_pulseio_pulsein_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_deinit_obj, pulseio_pulsein_deinit);
+
+STATIC void check_for_deinit(pulseio_pulsein_obj_t *self) {
+ if (common_hal_pulseio_pulsein_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> PulseIn:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_pulseio_pulsein_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pulsein___exit___obj, 4, 4, pulseio_pulsein_obj___exit__);
+
+//| def pause(self) -> None:
+//| """Pause pulse capture"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_pause(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_pulseio_pulsein_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_pause_obj, pulseio_pulsein_obj_pause);
+
+//| def resume(self, trigger_duration: int = 0) -> None:
+//| """Resumes pulse capture after an optional trigger pulse.
+//|
+//| .. warning:: Using trigger pulse with a device that drives both high and
+//| low signals risks a short. Make sure your device is open drain (only
+//| drives low) when using a trigger pulse. You most likely added a
+//| "pull-up" resistor to your circuit to do this.
+//|
+//| :param int trigger_duration: trigger pulse duration in microseconds"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_resume(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_trigger_duration };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_trigger_duration, MP_ARG_INT, {.u_int = 0} },
+ };
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ common_hal_pulseio_pulsein_resume(self, args[ARG_trigger_duration].u_int);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(pulseio_pulsein_resume_obj, 1, pulseio_pulsein_obj_resume);
+
+//| def clear(self) -> None:
+//| """Clears all captured pulses"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_clear(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_pulseio_pulsein_clear(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_clear_obj, pulseio_pulsein_obj_clear);
+
+//| def popleft(self) -> int:
+//| """Removes and returns the oldest read pulse."""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_popleft(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pulsein_popleft(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_popleft_obj, pulseio_pulsein_obj_popleft);
+
+//| maxlen: int
+//| """The maximum length of the PulseIn. When len() is equal to maxlen,
+//| it is unclear which pulses are active and which are idle."""
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_get_maxlen(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pulsein_get_maxlen(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_get_maxlen_obj, pulseio_pulsein_obj_get_maxlen);
+
+MP_PROPERTY_GETTER(pulseio_pulsein_maxlen_obj,
+ (mp_obj_t)&pulseio_pulsein_get_maxlen_obj);
+
+//| paused: bool
+//| """True when pulse capture is paused as a result of :py:func:`pause` or an error during capture
+//| such as a signal that is too fast."""
+//|
+STATIC mp_obj_t pulseio_pulsein_obj_get_paused(mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_bool(common_hal_pulseio_pulsein_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_get_paused_obj, pulseio_pulsein_obj_get_paused);
+
+MP_PROPERTY_GETTER(pulseio_pulsein_paused_obj,
+ (mp_obj_t)&pulseio_pulsein_get_paused_obj);
+
+//| def __bool__(self) -> bool: ...
+//|
+//| def __len__(self) -> int:
+//| """Returns the number of pulse durations currently stored.
+//|
+//| This allows you to::
+//|
+//| pulses = pulseio.PulseIn(pin)
+//| print(len(pulses))"""
+//| ...
+//|
+STATIC mp_obj_t pulsein_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ uint16_t len = common_hal_pulseio_pulsein_get_len(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __getitem__(self, index: int) -> Optional[int]:
+//| """Returns the value at the given index or values in slice.
+//|
+//| This allows you to::
+//|
+//| pulses = pulseio.PulseIn(pin)
+//| print(pulses[0])"""
+//| ...
+//|
+STATIC mp_obj_t pulsein_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) {
+ if (value == mp_const_none) {
+ // delete item
+ mp_raise_AttributeError(translate("Cannot delete values"));
+ } else {
+ pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (mp_obj_is_type(index_obj, &mp_type_slice)) {
+ mp_raise_NotImplementedError(translate("Slices not supported"));
+ } else {
+ size_t index = mp_get_index(&pulseio_pulsein_type, common_hal_pulseio_pulsein_get_len(self), index_obj, false);
+ if (value == MP_OBJ_SENTINEL) {
+ // load
+ return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pulsein_get_item(self, index));
+ } else {
+ mp_raise_AttributeError(translate("Read-only"));
+ }
+ }
+ }
+ return mp_const_none;
+}
+
+STATIC const mp_rom_map_elem_t pulseio_pulsein_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pulseio_pulsein_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pulseio_pulsein___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&pulseio_pulsein_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&pulseio_pulsein_resume_obj) },
+ { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&pulseio_pulsein_clear_obj) },
+ { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&pulseio_pulsein_popleft_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_maxlen), MP_ROM_PTR(&pulseio_pulsein_maxlen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&pulseio_pulsein_paused_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(pulseio_pulsein_locals_dict, pulseio_pulsein_locals_dict_table);
+
+const mp_obj_type_t pulseio_pulsein_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_PulseIn,
+ .make_new = pulseio_pulsein_make_new,
+ .locals_dict = (mp_obj_dict_t *)&pulseio_pulsein_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .subscr = pulsein_subscr,
+ .unary_op = pulsein_unary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/pulseio/PulseIn.h b/circuitpython/shared-bindings/pulseio/PulseIn.h
new file mode 100644
index 0000000..09d01fd
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/PulseIn.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEIN_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/pulseio/PulseIn.h"
+
+extern const mp_obj_type_t pulseio_pulsein_type;
+
+extern void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self,
+ const mcu_pin_obj_t *pin, uint16_t maxlen, bool idle_state);
+extern void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t *self);
+extern bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t *self);
+extern void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t *self);
+extern void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t *self, uint16_t trigger_duration);
+extern void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t *self);
+extern uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t *self);
+extern uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t *self);
+extern bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t *self);
+extern uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t *self);
+extern uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t *self, int16_t index);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEIN_H
diff --git a/circuitpython/shared-bindings/pulseio/PulseOut.c b/circuitpython/shared-bindings/pulseio/PulseOut.c
new file mode 100644
index 0000000..ac56823
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/PulseOut.c
@@ -0,0 +1,170 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/pulseio/PulseOut.h"
+#include "shared-bindings/pwmio/PWMOut.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class PulseOut:
+//| """Pulse PWM "carrier" output on and off. This is commonly used in infrared remotes. The
+//| pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration
+//| for on and off pairs."""
+//|
+//| def __init__(self, pin: microcontroller.Pin, *, frequency: int = 38000, duty_cycle: int = 1 << 15) -> None:
+//| """Create a PulseOut object associated with the given pin.
+//|
+//| :param ~microcontroller.Pin pin: Signal output pin
+//| :param int frequency: Carrier signal frequency in Hertz
+//| :param int duty_cycle: 16-bit duty cycle of carrier frequency (0 - 65536)
+//|
+//| For backwards compatibility, ``pin`` may be a PWMOut object used as the carrier. This
+//| compatibility will be removed in CircuitPython 8.0.0.
+//|
+//| Send a short series of pulses::
+//|
+//| import array
+//| import pulseio
+//| import pwmio
+//| import board
+//|
+//| # 50% duty cycle at 38kHz.
+//| pulse = pulseio.PulseOut(board.LED, frequency=38000, duty_cycle=32768)
+//| # on off on off on
+//| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000])
+//| pulse.send(pulses)
+//|
+//| # Modify the array of pulses.
+//| pulses[0] = 200
+//| pulse.send(pulses)"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin, ARG_frequency, ARG_duty_cycle};
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 38000} },
+ { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 << 15} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin = args[ARG_pin].u_obj;
+ mp_int_t frequency = args[ARG_frequency].u_int;
+ mp_int_t duty_cycle = args[ARG_duty_cycle].u_int;
+ if (mp_obj_is_type(args[ARG_pin].u_obj, &pwmio_pwmout_type)) {
+ pwmio_pwmout_obj_t *pwmout = args[ARG_pin].u_obj;
+ duty_cycle = common_hal_pwmio_pwmout_get_duty_cycle(pwmout);
+ frequency = common_hal_pwmio_pwmout_get_frequency(pwmout);
+ pin = common_hal_pwmio_pwmout_get_pin(pwmout);
+ // Deinit the pin so we can use it.
+ common_hal_pwmio_pwmout_deinit(pwmout);
+ }
+ validate_obj_is_free_pin(MP_OBJ_FROM_PTR(pin));
+ pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t);
+ self->base.type = &pulseio_pulseout_type;
+ common_hal_pulseio_pulseout_construct(self, pin, frequency, duty_cycle);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the PulseOut and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulseout_deinit(mp_obj_t self_in) {
+ pulseio_pulseout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_pulseio_pulseout_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulseout_deinit_obj, pulseio_pulseout_deinit);
+
+//| def __enter__(self) -> PulseOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulseout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_pulseio_pulseout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pulseout___exit___obj, 4, 4, pulseio_pulseout_obj___exit__);
+
+//| def send(self, pulses: ReadableBuffer) -> None:
+//| """Pulse alternating on and off durations in microseconds starting with on.
+//| ``pulses`` must be an `array.array` with data type 'H' for unsigned
+//| halfword (two bytes).
+//|
+//| This method waits until the whole array of pulses has been sent and
+//| ensures the signal is off afterwards.
+//|
+//| :param array.array pulses: pulse durations in microseconds"""
+//| ...
+//|
+STATIC mp_obj_t pulseio_pulseout_obj_send(mp_obj_t self_in, mp_obj_t pulses) {
+ pulseio_pulseout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (common_hal_pulseio_pulseout_deinited(self)) {
+ raise_deinited_error();
+ }
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(pulses, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.typecode != 'H') {
+ mp_raise_TypeError(translate("Array must contain halfwords (type 'H')"));
+ }
+ common_hal_pulseio_pulseout_send(self, (uint16_t *)bufinfo.buf, bufinfo.len / 2);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(pulseio_pulseout_send_obj, pulseio_pulseout_obj_send);
+
+STATIC const mp_rom_map_elem_t pulseio_pulseout_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pulseio_pulseout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pulseio_pulseout___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pulseio_pulseout_send_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(pulseio_pulseout_locals_dict, pulseio_pulseout_locals_dict_table);
+
+const mp_obj_type_t pulseio_pulseout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PulseOut,
+ .make_new = pulseio_pulseout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&pulseio_pulseout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/pulseio/PulseOut.h b/circuitpython/shared-bindings/pulseio/PulseOut.h
new file mode 100644
index 0000000..0c64c13
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/PulseOut.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEOUT_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/pulseio/PulseOut.h"
+#include "common-hal/pwmio/PWMOut.h"
+
+extern const mp_obj_type_t pulseio_pulseout_type;
+
+extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self,
+ const mcu_pin_obj_t *pin,
+ uint32_t frequency,
+ uint16_t duty_cycle);
+
+extern void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t *self);
+extern bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t *self);
+extern void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self,
+ uint16_t *pulses, uint16_t len);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PULSEOUT_H
diff --git a/circuitpython/shared-bindings/pulseio/__init__.c b/circuitpython/shared-bindings/pulseio/__init__.c
new file mode 100644
index 0000000..0dba6ff
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/__init__.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/pulseio/__init__.h"
+#include "shared-bindings/pulseio/PulseIn.h"
+#include "shared-bindings/pulseio/PulseOut.h"
+
+//| """Support for individual pulse based protocols
+//|
+//| The `pulseio` module contains classes to provide access to basic pulse IO.
+//| Individual pulses are commonly used in infrared remotes and in DHT
+//| temperature sensors.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//|
+
+STATIC const mp_rom_map_elem_t pulseio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pulseio) },
+ { MP_ROM_QSTR(MP_QSTR_PulseIn), MP_ROM_PTR(&pulseio_pulsein_type) },
+ { MP_ROM_QSTR(MP_QSTR_PulseOut), MP_ROM_PTR(&pulseio_pulseout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pulseio_module_globals, pulseio_module_globals_table);
+
+const mp_obj_module_t pulseio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&pulseio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_pulseio, pulseio_module, CIRCUITPY_PULSEIO);
diff --git a/circuitpython/shared-bindings/pulseio/__init__.h b/circuitpython/shared-bindings/pulseio/__init__.h
new file mode 100644
index 0000000..0691ad2
--- /dev/null
+++ b/circuitpython/shared-bindings/pulseio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO___INIT___H
diff --git a/circuitpython/shared-bindings/pwmio/PWMOut.c b/circuitpython/shared-bindings/pwmio/PWMOut.c
new file mode 100644
index 0000000..60a9dfb
--- /dev/null
+++ b/circuitpython/shared-bindings/pwmio/PWMOut.c
@@ -0,0 +1,284 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/pwmio/PWMOut.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+
+void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result) {
+ switch (result) {
+ case PWMOUT_OK:
+ break;
+ case PWMOUT_INVALID_PIN:
+ mp_raise_ValueError(translate("Invalid pin"));
+ break;
+ case PWMOUT_INVALID_FREQUENCY:
+ mp_raise_ValueError(translate("Invalid PWM frequency"));
+ break;
+ case PWMOUT_INVALID_FREQUENCY_ON_PIN:
+ mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer"));
+ break;
+ case PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE:
+ mp_raise_ValueError(translate("Cannot vary frequency on a timer that is already in use"));
+ break;
+ case PWMOUT_ALL_TIMERS_ON_PIN_IN_USE:
+ mp_raise_ValueError(translate("All timers for this pin are in use"));
+ break;
+ case PWMOUT_ALL_TIMERS_IN_USE:
+ mp_raise_RuntimeError(translate("All timers in use"));
+ break;
+ case PWMOUT_ALL_CHANNELS_IN_USE:
+ mp_raise_RuntimeError(translate("All channels in use"));
+ break;
+ default:
+ case PWMOUT_INITIALIZATION_ERROR:
+ mp_raise_RuntimeError(translate("Could not start PWM"));
+ break;
+ }
+}
+
+//| class PWMOut:
+//| """Output a Pulse Width Modulated signal on a given pin."""
+//|
+//| def __init__(self, pin: microcontroller.Pin, *, duty_cycle: int = 0, frequency: int = 500, variable_frequency: bool = False) -> None:
+//| """Create a PWM object associated with the given pin. This allows you to
+//| write PWM signals out on the given pin. Frequency is fixed after init
+//| unless ``variable_frequency`` is True.
+//|
+//| .. note:: When ``variable_frequency`` is True, further PWM outputs may be
+//| limited because it may take more internal resources to be flexible. So,
+//| when outputting both fixed and flexible frequency signals construct the
+//| fixed outputs first.
+//|
+//| :param ~microcontroller.Pin pin: The pin to output to
+//| :param int duty_cycle: The fraction of each pulse which is high. 16-bit
+//| :param int frequency: The target frequency in Hertz (32-bit)
+//| :param bool variable_frequency: True if the frequency will change over time
+//|
+//|
+//| Simple LED on::
+//|
+//| import pwmio
+//| import board
+//|
+//| pwm = pwmio.PWMOut(board.LED)
+//|
+//| while True:
+//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at the default 500hz
+//|
+//| PWM LED fade::
+//|
+//| import pwmio
+//| import board
+//|
+//| pwm = pwmio.PWMOut(board.LED) # output on LED pin with default of 500Hz
+//|
+//| while True:
+//| for cycle in range(0, 65535): # Cycles through the full PWM range from 0 to 65535
+//| pwm.duty_cycle = cycle # Cycles the LED pin duty cycle through the range of values
+//| for cycle in range(65534, 0, -1): # Cycles through the PWM range backwards from 65534 to 0
+//| pwm.duty_cycle = cycle # Cycles the LED pin duty cycle through the range of values
+//|
+//| PWM at specific frequency (servos and motors)::
+//|
+//| import pwmio
+//| import board
+//|
+//| pwm = pwmio.PWMOut(board.D13, frequency=50)
+//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at 50hz
+//|
+//| Variable frequency (usually tones)::
+//|
+//| import pwmio
+//| import board
+//| import time
+//|
+//| pwm = pwmio.PWMOut(board.D13, duty_cycle=2 ** 15, frequency=440, variable_frequency=True)
+//| time.sleep(0.2)
+//| pwm.frequency = 880
+//| time.sleep(0.1)"""
+//| ...
+//|
+STATIC mp_obj_t pwmio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ enum { ARG_pin, ARG_duty_cycle, ARG_frequency, ARG_variable_frequency };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+ { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500} },
+ { MP_QSTR_variable_frequency, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args);
+
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(parsed_args[ARG_pin].u_obj);
+
+ uint16_t duty_cycle = parsed_args[ARG_duty_cycle].u_int;
+ uint32_t frequency = parsed_args[ARG_frequency].u_int;
+ bool variable_frequency = parsed_args[ARG_variable_frequency].u_bool;
+
+ // create PWM object from the given pin
+ pwmio_pwmout_obj_t *self = m_new_obj(pwmio_pwmout_obj_t);
+ self->base.type = &pwmio_pwmout_type;
+ pwmout_result_t result = common_hal_pwmio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency);
+ common_hal_pwmio_pwmout_raise_error(result);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the PWMOut and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t pwmio_pwmout_deinit(mp_obj_t self_in) {
+ pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_pwmio_pwmout_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_deinit_obj, pwmio_pwmout_deinit);
+
+STATIC void check_for_deinit(pwmio_pwmout_obj_t *self) {
+ if (common_hal_pwmio_pwmout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> PWMOut:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t pwmio_pwmout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_pwmio_pwmout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pwmio_pwmout___exit___obj, 4, 4, pwmio_pwmout_obj___exit__);
+
+//| duty_cycle: int
+//| """16 bit value that dictates how much of one cycle is high (1) versus low
+//| (0). 0xffff will always be high, 0 will always be low and 0x7fff will
+//| be half high and then half low.
+//|
+//| Depending on how PWM is implemented on a specific board, the internal
+//| representation for duty cycle might have less than 16 bits of resolution.
+//| Reading this property will return the value from the internal representation,
+//| so it may differ from the value set."""
+//|
+STATIC mp_obj_t pwmio_pwmout_obj_get_duty_cycle(mp_obj_t self_in) {
+ pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_pwmio_pwmout_get_duty_cycle(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_get_duty_cycle_obj, pwmio_pwmout_obj_get_duty_cycle);
+
+STATIC mp_obj_t pwmio_pwmout_obj_set_duty_cycle(mp_obj_t self_in, mp_obj_t duty_cycle) {
+ pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ mp_int_t duty = mp_obj_get_int(duty_cycle);
+ if (duty < 0 || duty > 0xffff) {
+ mp_raise_ValueError(translate("PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)"));
+ }
+ common_hal_pwmio_pwmout_set_duty_cycle(self, duty);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(pwmio_pwmout_set_duty_cycle_obj, pwmio_pwmout_obj_set_duty_cycle);
+
+MP_PROPERTY_GETSET(pwmio_pwmout_duty_cycle_obj,
+ (mp_obj_t)&pwmio_pwmout_get_duty_cycle_obj,
+ (mp_obj_t)&pwmio_pwmout_set_duty_cycle_obj);
+
+//| frequency: int
+//| """32 bit value that dictates the PWM frequency in Hertz (cycles per
+//| second). Only writeable when constructed with ``variable_frequency=True``.
+//|
+//| Depending on how PWM is implemented on a specific board, the internal value
+//| for the PWM's duty cycle may need to be recalculated when the frequency
+//| changes. In these cases, the duty cycle is automatically recalculated
+//| from the original duty cycle value. This should happen without any need
+//| to manually re-set the duty cycle."""
+//|
+STATIC mp_obj_t pwmio_pwmout_obj_get_frequency(mp_obj_t self_in) {
+ pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_pwmio_pwmout_get_frequency(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_get_frequency_obj, pwmio_pwmout_obj_get_frequency);
+
+STATIC mp_obj_t pwmio_pwmout_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency) {
+ pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ if (!common_hal_pwmio_pwmout_get_variable_frequency(self)) {
+ mp_raise_AttributeError(translate(
+ "PWM frequency not writable when variable_frequency is False on "
+ "construction."));
+ }
+ mp_int_t freq = mp_obj_get_int(frequency);
+ if (freq == 0) {
+ mp_raise_ValueError(translate("Invalid PWM frequency"));
+ }
+ common_hal_pwmio_pwmout_set_frequency(self, freq);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(pwmio_pwmout_set_frequency_obj, pwmio_pwmout_obj_set_frequency);
+
+MP_PROPERTY_GETSET(pwmio_pwmout_frequency_obj,
+ (mp_obj_t)&pwmio_pwmout_get_frequency_obj,
+ (mp_obj_t)&pwmio_pwmout_set_frequency_obj);
+
+STATIC const mp_rom_map_elem_t pwmio_pwmout_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pwmio_pwmout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pwmio_pwmout___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_duty_cycle), MP_ROM_PTR(&pwmio_pwmout_duty_cycle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&pwmio_pwmout_frequency_obj) },
+ // TODO(tannewt): Add enabled to determine whether the signal is output
+ // without giving up the resources. Useful for IR output.
+};
+STATIC MP_DEFINE_CONST_DICT(pwmio_pwmout_locals_dict, pwmio_pwmout_locals_dict_table);
+
+const mp_obj_type_t pwmio_pwmout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PWMOut,
+ .make_new = pwmio_pwmout_make_new,
+ .locals_dict = (mp_obj_dict_t *)&pwmio_pwmout_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/pwmio/PWMOut.h b/circuitpython/shared-bindings/pwmio/PWMOut.h
new file mode 100644
index 0000000..e55205e
--- /dev/null
+++ b/circuitpython/shared-bindings/pwmio/PWMOut.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/pwmio/PWMOut.h"
+
+extern const mp_obj_type_t pwmio_pwmout_type;
+
+typedef enum pwmout_result_t {
+ PWMOUT_OK,
+ PWMOUT_INVALID_PIN,
+ PWMOUT_INVALID_FREQUENCY,
+ PWMOUT_INVALID_FREQUENCY_ON_PIN,
+ PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE,
+ PWMOUT_ALL_TIMERS_ON_PIN_IN_USE,
+ PWMOUT_ALL_TIMERS_IN_USE,
+ PWMOUT_ALL_CHANNELS_IN_USE,
+ PWMOUT_INITIALIZATION_ERROR,
+} pwmout_result_t;
+
+extern pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
+ const mcu_pin_obj_t *pin, uint16_t duty, uint32_t frequency,
+ bool variable_frequency);
+extern void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self);
+extern bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t *self);
+extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t duty);
+extern uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t *self);
+extern void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t *self, uint32_t frequency);
+extern uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self);
+extern bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self);
+
+// Don't use this! It is only used internally for backwards compatibility.
+extern const mcu_pin_obj_t *common_hal_pwmio_pwmout_get_pin(pwmio_pwmout_obj_t *self);
+
+// This is used by the supervisor to claim PWMOut devices indefinitely.
+extern void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self);
+extern void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self);
+
+extern void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H
diff --git a/circuitpython/shared-bindings/pwmio/__init__.c b/circuitpython/shared-bindings/pwmio/__init__.c
new file mode 100644
index 0000000..90aff45
--- /dev/null
+++ b/circuitpython/shared-bindings/pwmio/__init__.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/pwmio/__init__.h"
+#include "shared-bindings/pwmio/PWMOut.h"
+
+//| """Support for PWM based protocols
+//|
+//| The `pwmio` module contains classes to provide access to basic pulse IO.
+//|
+
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import time
+//| import pwmio
+//| import board
+//|
+//| pwm = pwmio.PWMOut(board.LED)
+//| pwm.duty_cycle = 2 ** 15
+//| time.sleep(0.1)
+//|
+//| This example will initialize the the device, set
+//| :py:data:`~pwmio.PWMOut.duty_cycle`, and then sleep 0.1 seconds.
+//| CircuitPython will automatically turn off the PWM when it resets all
+//| hardware after program completion. Use ``deinit()`` or a ``with`` statement
+//| to do it yourself.
+//|
+//| For the essentials of `pwmio`, see the `CircuitPython Essentials
+//| Learn guide <https://learn.adafruit.com/circuitpython-essentials/circuitpython-pwm>`_.
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t pwmio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pwmio) },
+ { MP_ROM_QSTR(MP_QSTR_PWMOut), MP_ROM_PTR(&pwmio_pwmout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pwmio_module_globals, pwmio_module_globals_table);
+
+const mp_obj_module_t pwmio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&pwmio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_pwmio, pwmio_module, CIRCUITPY_PWMIO);
diff --git a/circuitpython/shared-bindings/pwmio/__init__.h b/circuitpython/shared-bindings/pwmio/__init__.h
new file mode 100644
index 0000000..93c7037
--- /dev/null
+++ b/circuitpython/shared-bindings/pwmio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO___INIT___H
diff --git a/circuitpython/shared-bindings/qrio/PixelPolicy.c b/circuitpython/shared-bindings/qrio/PixelPolicy.c
new file mode 100644
index 0000000..6887081
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/PixelPolicy.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/qrio/__init__.h"
+#include "shared-bindings/qrio/PixelPolicy.h"
+#include "py/obj.h"
+#include "py/enum.h"
+
+//| class PixelPolicy:
+//| EVERY_BYTE: PixelPolicy
+//| """The input buffer to `QRDecoder.decode` consists of greyscale values in every byte"""
+//|
+//| EVEN_BYTES: PixelPolicy
+//| """The input buffer to `QRDecoder.decode` consists of greyscale values in positions 0, 2, …, and ignored bytes in positions 1, 3, …. This can decode directly from YUV images where the even bytes hold the Y (luminance) data."""
+//|
+//| ODD_BYTES: PixelPolicy
+//| """The input buffer to `QRDecoder.decode` consists of greyscale values in positions 1, 3, …, and ignored bytes in positions 0, 2, …. This can decode directly from YUV images where the odd bytes hold the Y (luminance) data"""
+//|
+
+MAKE_ENUM_VALUE(qrio_pixel_policy_type, qrio_pixel_policy, EVERY_BYTE, QRIO_EVERY_BYTE);
+MAKE_ENUM_VALUE(qrio_pixel_policy_type, qrio_pixel_policy, EVEN_BYTES, QRIO_EVEN_BYTES);
+MAKE_ENUM_VALUE(qrio_pixel_policy_type, qrio_pixel_policy, ODD_BYTES, QRIO_EVEN_BYTES);
+
+MAKE_ENUM_MAP(qrio_pixel_policy) {
+ MAKE_ENUM_MAP_ENTRY(qrio_pixel_policy, EVERY_BYTE),
+ MAKE_ENUM_MAP_ENTRY(qrio_pixel_policy, EVEN_BYTES),
+ MAKE_ENUM_MAP_ENTRY(qrio_pixel_policy, ODD_BYTES),
+};
+STATIC MP_DEFINE_CONST_DICT(qrio_pixel_policy_locals_dict, qrio_pixel_policy_locals_table);
+
+MAKE_PRINTER(qrio, qrio_pixel_policy);
+
+MAKE_ENUM_TYPE(qrio, PixelPolicy, qrio_pixel_policy);
diff --git a/circuitpython/shared-bindings/qrio/PixelPolicy.h b/circuitpython/shared-bindings/qrio/PixelPolicy.h
new file mode 100644
index 0000000..8be5dde
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/PixelPolicy.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/enum.h"
+#include "py/obj.h"
+#include "py/objnamedtuple.h"
+
+extern const mp_obj_type_t qrio_pixel_policy_type;
+
+typedef enum {
+ QRIO_EVERY_BYTE, QRIO_EVEN_BYTES, QRIO_ODD_BYTES
+} qrio_pixel_policy_t;
+
+extern const cp_enum_obj_t qrio_pixel_policy_EVERY_BYTE_obj;
diff --git a/circuitpython/shared-bindings/qrio/QRDecoder.c b/circuitpython/shared-bindings/qrio/QRDecoder.c
new file mode 100644
index 0000000..d2d4785
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/QRDecoder.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/qrio/__init__.h"
+#include "shared-bindings/qrio/QRDecoder.h"
+#include "shared-module/qrio/QRDecoder.h"
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/enum.h"
+
+//| class QRDecoder:
+//|
+//| def __init__(self, width: int, height: int) -> None:
+//| """Construct a QRDecoder object
+//|
+//| :param int width: The pixel width of the image to decode
+//| :param int height: The pixel height of the image to decode
+//| """
+//| ...
+
+STATIC mp_obj_t qrio_qrdecoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
+ enum { ARG_width, ARG_height };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args_in, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ qrio_qrdecoder_obj_t *self = m_new_obj(qrio_qrdecoder_obj_t);
+ self->base.type = &qrio_qrdecoder_type_obj;
+ shared_module_qrio_qrdecoder_construct(self, args[ARG_width].u_int, args[ARG_height].u_int);
+
+ return self;
+}
+
+//| def decode(self, buffer: ReadableBuffer, pixel_policy: PixelPolicy = PixelPolicy.EVERY_BYTE) -> List[QRInfo]:
+//| """Decode zero or more QR codes from the given image. The size of the buffer must be at least ``length``×``width`` bytes for `EVERY_BYTE`, and 2×``length``×``width`` bytes for `EVEN_BYTES` or `ODD_BYTES`."""
+//|
+STATIC mp_obj_t qrio_qrdecoder_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_buffer, ARG_pixel_policy };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_pixel_policy, MP_ARG_OBJ, {.u_obj = MP_ROM_PTR((mp_obj_t *)&qrio_pixel_policy_EVERY_BYTE_obj)} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ int width = shared_module_qrio_qrdecoder_get_width(self);
+ int height = shared_module_qrio_qrdecoder_get_height(self);
+
+ // verify that the buffer is big enough
+ int sz = width * height;
+ qrio_pixel_policy_t policy = cp_enum_value(&qrio_pixel_policy_type, args[ARG_pixel_policy].u_obj);
+ if (policy != QRIO_EVERY_BYTE) {
+ sz *= 2;
+ }
+ mp_get_index(mp_obj_get_type(args[ARG_buffer].u_obj), bufinfo.len, MP_OBJ_NEW_SMALL_INT(sz - 1), false);
+
+ return shared_module_qrio_qrdecoder_decode(self, &bufinfo, policy);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(qrio_qrdecoder_decode_obj, 1, qrio_qrdecoder_decode);
+
+//| width: int
+//| """The width of image the decoder expects"""
+//|
+STATIC mp_obj_t qrio_qrdecoder_get_width(mp_obj_t self_in) {
+ qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(shared_module_qrio_qrdecoder_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(qrio_qrdecoder_get_width_obj, qrio_qrdecoder_get_width);
+
+STATIC mp_obj_t qrio_qrdecoder_set_width(mp_obj_t self_in, mp_obj_t width_in) {
+ qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int width = mp_obj_get_int(width_in);
+ shared_module_qrio_qrdecoder_set_width(self, width);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(qrio_qrdecoder_set_width_obj, qrio_qrdecoder_set_width);
+
+MP_PROPERTY_GETSET(qrio_qrdecoder_width_obj,
+ (mp_obj_t)&qrio_qrdecoder_get_width_obj,
+ (mp_obj_t)&qrio_qrdecoder_set_width_obj);
+
+//| height: int
+//| """The height of image the decoder expects"""
+//|
+STATIC mp_obj_t qrio_qrdecoder_get_height(mp_obj_t self_in) {
+ qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(shared_module_qrio_qrdecoder_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(qrio_qrdecoder_get_height_obj, qrio_qrdecoder_get_height);
+
+STATIC mp_obj_t qrio_qrdecoder_set_height(mp_obj_t self_in, mp_obj_t height_in) {
+ qrio_qrdecoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ int height = mp_obj_get_int(height_in);
+ shared_module_qrio_qrdecoder_set_height(self, height);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(qrio_qrdecoder_set_height_obj, qrio_qrdecoder_set_height);
+
+MP_PROPERTY_GETSET(qrio_qrdecoder_height_obj,
+ (mp_obj_t)&qrio_qrdecoder_get_height_obj,
+ (mp_obj_t)&qrio_qrdecoder_set_height_obj);
+
+STATIC const mp_rom_map_elem_t qrio_qrdecoder_locals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_QRDecoder) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&qrio_qrdecoder_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&qrio_qrdecoder_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&qrio_qrdecoder_decode_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(qrio_qrdecoder_locals, qrio_qrdecoder_locals_table);
+
+const mp_obj_type_t qrio_qrdecoder_type_obj = {
+ { &mp_type_type },
+ .name = MP_QSTR_QRDecoder,
+ .make_new = qrio_qrdecoder_make_new,
+ .locals_dict = (mp_obj_dict_t *)&qrio_qrdecoder_locals,
+};
diff --git a/circuitpython/shared-bindings/qrio/QRDecoder.h b/circuitpython/shared-bindings/qrio/QRDecoder.h
new file mode 100644
index 0000000..0b01aeb
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/QRDecoder.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/obj.h"
+
+typedef struct qrio_qrdecoder_obj qrio_qrdecoder_obj_t;
+
+extern const mp_obj_type_t qrio_qrdecoder_type_obj;
+
+void common_hal_qrio_qrdecoder_construct(qrio_qrdecoder_obj_t *self);
+
+mp_obj_t common_hal_qrio_qrdecoder_decode(qrio_qrdecoder_obj_t *self, int width, int height, mp_buffer_info_t *buf);
diff --git a/circuitpython/shared-bindings/qrio/QRInfo.c b/circuitpython/shared-bindings/qrio/QRInfo.c
new file mode 100644
index 0000000..8eb0387
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/QRInfo.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/qrio/__init__.h"
+#include "shared-bindings/qrio/QRInfo.h"
+#include "py/obj.h"
+#include "py/enum.h"
+
+//| class QRInfo:
+//| """Information about a decoded QR code"""
+//|
+//| payload: bytes
+//| """The content of the QR code"""
+//|
+//| data_type: Union[str, int]
+//| """The encoding of the payload as a string (if a standard encoding) or int (if not standard)"""
+
+const mp_obj_namedtuple_type_t qrio_qrinfo_type_obj = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_QRInfo,
+ .print = namedtuple_print,
+ .parent = &mp_type_tuple,
+ .make_new = namedtuple_make_new,
+ .attr = namedtuple_attr,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ ),
+ },
+ .n_fields = 2,
+ .fields = {
+ MP_QSTR_payload,
+ MP_QSTR_data_type,
+ },
+};
diff --git a/circuitpython/shared-bindings/qrio/QRInfo.h b/circuitpython/shared-bindings/qrio/QRInfo.h
new file mode 100644
index 0000000..956cb42
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/QRInfo.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "py/objnamedtuple.h"
+
+extern const mp_obj_namedtuple_type_t qrio_qrinfo_type_obj;
diff --git a/circuitpython/shared-bindings/qrio/__init__.c b/circuitpython/shared-bindings/qrio/__init__.c
new file mode 100644
index 0000000..04c86fd
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/__init__.c
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/qrio/__init__.h"
+#include "shared-bindings/qrio/QRDecoder.h"
+#include "shared-bindings/qrio/QRInfo.h"
+#include "shared-bindings/qrio/PixelPolicy.h"
+#include "py/obj.h"
+#include "py/enum.h"
+
+//| """Low-level QR code decoding
+//|
+//| Provides the `QRDecoder` object used for decoding QR codes. For more
+//| information about working with QR codes, see
+//| `this Learn guide <https://learn.adafruit.com/scan-qr-codes-with-circuitpython>`_.
+//|
+//| .. note:: This module only handles decoding QR codes. If you are looking
+//| to generate a QR code, use the
+//| `adafruit_miniqr library <https://github.com/adafruit/Adafruit_CircuitPython_miniQR>`_"""
+//|
+
+STATIC const mp_rom_map_elem_t qrio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_qrio) },
+ { MP_ROM_QSTR(MP_QSTR_QRInfo), MP_ROM_PTR(&qrio_qrinfo_type_obj) },
+ { MP_ROM_QSTR(MP_QSTR_QRDecoder), MP_ROM_PTR(&qrio_qrdecoder_type_obj) },
+ { MP_ROM_QSTR(MP_QSTR_PixelPolicy), MP_ROM_PTR(&qrio_pixel_policy_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(qrio_module_globals, qrio_module_globals_table);
+
+const mp_obj_module_t qrio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&qrio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_qrio, qrio_module, CIRCUITPY_QRIO);
diff --git a/circuitpython/shared-bindings/qrio/__init__.h b/circuitpython/shared-bindings/qrio/__init__.h
new file mode 100644
index 0000000..be9b3ae
--- /dev/null
+++ b/circuitpython/shared-bindings/qrio/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/rainbowio/__init__.c b/circuitpython/shared-bindings/rainbowio/__init__.c
new file mode 100644
index 0000000..0dfdcd3
--- /dev/null
+++ b/circuitpython/shared-bindings/rainbowio/__init__.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Kattni Rembor
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/rainbowio/__init__.h"
+#include "py/mpconfig.h"
+#include "py/obj.h"
+//| """`rainbowio` module.
+//|
+//| Provides the `colorwheel()` function."""
+//|
+//| def colorwheel(n: float) -> int:
+//| """C implementation of the common colorwheel() function found in many examples.
+//| Returns the colorwheel RGB value as an integer value for n (usable in neopixel and dotstar)."""
+//| ...
+//|
+STATIC mp_obj_t rainbowio_colorwheel(mp_obj_t n) {
+ mp_float_t f = mp_obj_get_float(n);
+ return MP_OBJ_NEW_SMALL_INT(colorwheel(f));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(rainbowio_colorwheel_obj, rainbowio_colorwheel);
+
+STATIC const mp_rom_map_elem_t rainbowio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rainbowio) },
+ { MP_ROM_QSTR(MP_QSTR_colorwheel), MP_ROM_PTR(&rainbowio_colorwheel_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(rainbowio_module_globals, rainbowio_module_globals_table);
+
+const mp_obj_module_t rainbowio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&rainbowio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_rainbowio, rainbowio_module, CIRCUITPY_RAINBOWIO);
diff --git a/circuitpython/shared-bindings/rainbowio/__init__.h b/circuitpython/shared-bindings/rainbowio/__init__.h
new file mode 100644
index 0000000..3599e3a
--- /dev/null
+++ b/circuitpython/shared-bindings/rainbowio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the CircuitPython project, https://github.com/adafruit/circuitpython
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Kattni Rembor
+ *
+ * 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.
+ */
+
+#ifndef CP_SHARED_BINDINGS_RAINBOWIO_INIT_H
+#define CP_SHARED_BINDINGS_RAINBOWIO_INIT_H
+#include <stdint.h>
+#include "py/misc.h"
+
+int32_t colorwheel(mp_float_t pos);
+
+#endif // CP_SHARED_BINDINGS_RAINBOWIO_INIT_H
diff --git a/circuitpython/shared-bindings/random/__init__.c b/circuitpython/shared-bindings/random/__init__.c
new file mode 100644
index 0000000..63570fe
--- /dev/null
+++ b/circuitpython/shared-bindings/random/__init__.c
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "shared-bindings/random/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| """pseudo-random numbers and choices
+//|
+//| |see_cpython_module| :mod:`cpython:random`.
+//|
+//| Like its CPython cousin, CircuitPython's random seeds itself on first use
+//| with a true random from os.urandom() when available or the uptime otherwise.
+//| Once seeded, it will be deterministic, which is why its bad for cryptography.
+//|
+//| .. warning:: Numbers from this module are not cryptographically strong! Use
+//| bytes from `os.urandom` directly for true randomness."""
+//|
+//| from typing import TypeVar
+//| _T = TypeVar('_T')
+//|
+
+//| def seed(seed: int) -> None:
+//| """Sets the starting seed of the random number generation. Further calls to
+//| `random` will return deterministic results afterwards."""
+//| ...
+//|
+STATIC mp_obj_t random_seed(mp_obj_t seed_in) {
+ mp_uint_t seed = mp_obj_get_int_truncated(seed_in);
+ shared_modules_random_seed(seed);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(random_seed_obj, random_seed);
+
+//| def getrandbits(k: int) -> int:
+//| """Returns an integer with *k* random bits."""
+//| ...
+//|
+STATIC mp_obj_t random_getrandbits(mp_obj_t num_in) {
+ int n = mp_obj_get_int(num_in);
+ if (n > 32 || n == 0) {
+ mp_raise_ValueError(NULL);
+ }
+ return mp_obj_new_int_from_uint(shared_modules_random_getrandbits((uint8_t)n));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(random_getrandbits_obj, random_getrandbits);
+
+//| @overload
+//| def randrange(stop: int) -> int: ...
+//| @overload
+//| def randrange(start: int, stop: int) -> int: ...
+//| @overload
+//| def randrange(start: int, stop: int, step: int) -> int:
+//| """Returns a randomly selected integer from ``range(start[, stop[, step]])``."""
+//| ...
+//|
+STATIC mp_obj_t random_randrange(size_t n_args, const mp_obj_t *args) {
+ mp_int_t start = 0;
+ mp_int_t stop = mp_obj_get_int(args[0]);
+ mp_int_t step = 1;
+ if (n_args == 1) {
+ // range(stop)
+ if (stop <= 0) {
+ mp_raise_ValueError(translate("stop not reachable from start"));
+ }
+ } else {
+ start = stop;
+ stop = mp_obj_get_int(args[1]);
+ if (n_args == 2) {
+ // range(start, stop)
+ if (start >= stop) {
+ mp_raise_ValueError(translate("stop not reachable from start"));
+ }
+ } else {
+ // range(start, stop, step)
+ step = mp_obj_get_int(args[2]);
+ mp_int_t n;
+ if (step > 0) {
+ n = (stop - start + step - 1) / step;
+ } else if (step < 0) {
+ n = (stop - start + step + 1) / step;
+ } else {
+ mp_raise_ValueError(translate("step must be non-zero"));
+ }
+ if (n <= 0) {
+ mp_raise_ValueError(translate("invalid step"));
+ }
+ }
+ }
+
+ return mp_obj_new_int(shared_modules_random_randrange(start, stop, step));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(random_randrange_obj, 1, 3, random_randrange);
+
+//| def randint(a: int, b: int) -> int:
+//| """Returns a randomly selected integer between a and b inclusive. Equivalent
+//| to ``randrange(a, b + 1, 1)``"""
+//| ...
+//|
+STATIC mp_obj_t random_randint(mp_obj_t a_in, mp_obj_t b_in) {
+ mp_int_t a = mp_obj_get_int(a_in);
+ mp_int_t b = mp_obj_get_int(b_in);
+ if (a > b) {
+ mp_raise_ValueError(NULL);
+ }
+ return mp_obj_new_int(shared_modules_random_randrange(a, b + 1, 1));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(random_randint_obj, random_randint);
+
+//| def choice(seq: Sequence[_T]) -> _T:
+//| """Returns a randomly selected element from the given sequence. Raises
+//| IndexError when the sequence is empty."""
+//| ...
+//|
+STATIC mp_obj_t random_choice(mp_obj_t seq) {
+ mp_int_t len = mp_obj_get_int(mp_obj_len(seq));
+ if (len == 0) {
+ mp_raise_IndexError(translate("empty sequence"));
+ }
+ return mp_obj_subscr(seq, mp_obj_new_int(shared_modules_random_randrange(0, len, 1)), MP_OBJ_SENTINEL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(random_choice_obj, random_choice);
+
+//| def random() -> float:
+//| """Returns a random float between 0 and 1.0."""
+//| ...
+//|
+STATIC mp_obj_t random_random(void) {
+ return mp_obj_new_float(shared_modules_random_random());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(random_random_obj, random_random);
+
+//| def uniform(a: float, b: float) -> float:
+//| """Returns a random float between a and b. It may or may not be inclusive
+//| depending on float rounding."""
+//| ...
+//|
+STATIC mp_obj_t random_uniform(mp_obj_t a_in, mp_obj_t b_in) {
+ mp_float_t a = mp_obj_get_float(a_in);
+ mp_float_t b = mp_obj_get_float(b_in);
+ return mp_obj_new_float(shared_modules_random_uniform(a, b));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(random_uniform_obj, random_uniform);
+
+STATIC const mp_rom_map_elem_t mp_module_random_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) },
+ { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&random_seed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&random_getrandbits_obj) },
+ { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&random_randrange_obj) },
+ { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&random_randint_obj) },
+ { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&random_choice_obj) },
+ { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&random_random_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&random_uniform_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_random_globals, mp_module_random_globals_table);
+
+const mp_obj_module_t random_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_random_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_random, random_module, CIRCUITPY_RANDOM);
diff --git a/circuitpython/shared-bindings/random/__init__.h b/circuitpython/shared-bindings/random/__init__.h
new file mode 100644
index 0000000..9e05805
--- /dev/null
+++ b/circuitpython/shared-bindings/random/__init__.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RANDOM___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_RANDOM___INIT___H
+
+// This depends on shared_module because nearly all functionality is port
+// agnostic. The random module only depends on the common_hal_os_urandom or
+// common_hal_time_monotonic_ms to seed it initially.
+
+void shared_modules_random_seed(mp_uint_t seed);
+mp_uint_t shared_modules_random_getrandbits(uint8_t n);
+mp_int_t shared_modules_random_randrange(mp_int_t start, mp_int_t stop, mp_int_t step);
+mp_float_t shared_modules_random_random(void);
+mp_float_t shared_modules_random_uniform(mp_float_t a, mp_float_t b);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_RANDOM___INIT___H
diff --git a/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.c b/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.c
new file mode 100644
index 0000000..4739807
--- /dev/null
+++ b/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.c
@@ -0,0 +1,447 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/objarray.h"
+
+#include "common-hal/rgbmatrix/RGBMatrix.h"
+#include "shared-bindings/rgbmatrix/RGBMatrix.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/util.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/framebufferio/__init__.h"
+#include "shared-module/framebufferio/FramebufferDisplay.h"
+
+//| class RGBMatrix:
+//| """Displays an in-memory framebuffer to a HUB75-style RGB LED matrix."""
+//|
+
+extern Protomatter_core *_PM_protoPtr;
+
+STATIC uint8_t validate_pin(mp_obj_t obj) {
+ const mcu_pin_obj_t *result = validate_obj_is_free_pin(obj);
+ return common_hal_mcu_pin_number(result);
+}
+
+STATIC void claim_and_never_reset_pin(mp_obj_t pin) {
+ common_hal_mcu_pin_claim(pin);
+ common_hal_never_reset_pin(pin);
+}
+
+STATIC void claim_and_never_reset_pins(mp_obj_t seq) {
+ mp_int_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(seq));
+ for (mp_int_t i = 0; i < len; i++) {
+ claim_and_never_reset_pin(mp_obj_subscr(seq, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
+ }
+}
+
+STATIC void preflight_pins_or_throw(uint8_t clock_pin, uint8_t *rgb_pins, uint8_t rgb_pin_count, bool allow_inefficient) {
+ uint32_t port = clock_pin / 32;
+ uint32_t bit_mask = 1 << (clock_pin % 32);
+
+ if (rgb_pin_count <= 0 || rgb_pin_count % 6 != 0 || rgb_pin_count > 30) {
+ mp_raise_ValueError_varg(translate("The length of rgb_pins must be 6, 12, 18, 24, or 30"));
+ }
+
+ for (uint8_t i = 0; i < rgb_pin_count; i++) {
+ uint32_t pin_port = rgb_pins[i] / 32;
+
+ if (pin_port != port) {
+ mp_raise_ValueError_varg(
+ translate("rgb_pins[%d] is not on the same port as clock"), i);
+ }
+
+ uint32_t pin_mask = 1 << (rgb_pins[i] % 32);
+ if (pin_mask & bit_mask) {
+ mp_raise_ValueError_varg(
+ translate("rgb_pins[%d] duplicates another pin assignment"), i);
+ }
+
+ bit_mask |= pin_mask;
+ }
+
+ if (allow_inefficient) {
+ return;
+ }
+
+ uint8_t byte_mask = 0;
+ if (bit_mask & 0x000000FF) {
+ byte_mask |= 0b0001;
+ }
+ if (bit_mask & 0x0000FF00) {
+ byte_mask |= 0b0010;
+ }
+ if (bit_mask & 0x00FF0000) {
+ byte_mask |= 0b0100;
+ }
+ if (bit_mask & 0xFF000000) {
+ byte_mask |= 0b1000;
+ }
+
+ uint8_t bytes_per_element = 0xff;
+ uint8_t ideal_bytes_per_element = (rgb_pin_count + 7) / 8;
+
+ switch (byte_mask) {
+ case 0b0001:
+ case 0b0010:
+ case 0b0100:
+ case 0b1000:
+ bytes_per_element = 1;
+ break;
+
+ case 0b0011:
+ case 0b1100:
+ bytes_per_element = 2;
+ break;
+
+ default:
+ bytes_per_element = 4;
+ break;
+ }
+
+ if (bytes_per_element != ideal_bytes_per_element) {
+ mp_raise_ValueError_varg(
+ translate("Pinout uses %d bytes per element, which consumes more than the ideal %d bytes. If this cannot be avoided, pass allow_inefficient=True to the constructor"),
+ bytes_per_element, ideal_bytes_per_element);
+ }
+}
+
+//| def __init__(self, *, width: int, bit_depth: int,
+//| rgb_pins: Sequence[digitalio.DigitalInOut],
+//| addr_pins: Sequence[digitalio.DigitalInOut],
+//| clock_pin: digitalio.DigitalInOut,
+//| latch_pin: digitalio.DigitalInOut,
+//| output_enable_pin: digitalio.DigitalInOut,
+//| doublebuffer: bool = True,
+//| framebuffer: Optional[WriteableBuffer] = None,
+//| height: int = 0, tile: int = 1, serpentine: bool = True) -> None:
+//| """Create a RGBMatrix object with the given attributes. The height of
+//| the display is determined by the number of rgb and address pins and the number of tiles:
+//| ``len(rgb_pins) // 3 * 2 ** len(address_pins) * abs(tile)``. With 6 RGB pins, 4
+//| address lines, and a single matrix, the display will be 32 pixels tall. If the optional height
+//| parameter is specified and is not 0, it is checked against the calculated
+//| height.
+//|
+//| Up to 30 RGB pins and 8 address pins are supported.
+//|
+//| The RGB pins must be within a single "port" and performance and memory
+//| usage are best when they are all within "close by" bits of the port.
+//| The clock pin must also be on the same port as the RGB pins. See the
+//| documentation of the underlying protomatter C library for more
+//| information. Generally, Adafruit's interface boards are designed so
+//| that these requirements are met when matched with the intended
+//| microcontroller board. For instance, the Feather M4 Express works
+//| together with the RGB Matrix Feather.
+//|
+//| The framebuffer is in "RGB565" format.
+//|
+//| "RGB565" means that it is organized as a series of 16-bit numbers
+//| where the highest 5 bits are interpreted as red, the next 6 as
+//| green, and the final 5 as blue. The object can be any buffer, but
+//| `array.array` and ``ulab.ndarray`` objects are most often useful.
+//| To update the content, modify the framebuffer and call refresh.
+//|
+//| If a framebuffer is not passed in, one is allocated and initialized
+//| to all black. In any case, the framebuffer can be retrieved
+//| by passing the RGBMatrix object to memoryview().
+//|
+//| If doublebuffer is False, some memory is saved, but the display may
+//| flicker during updates.
+//|
+//| A RGBMatrix is often used in conjunction with a
+//| `framebufferio.FramebufferDisplay`."""
+//|
+
+STATIC mp_obj_t rgbmatrix_rgbmatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_width, ARG_bit_depth, ARG_rgb_list, ARG_addr_list,
+ ARG_clock_pin, ARG_latch_pin, ARG_output_enable_pin, ARG_doublebuffer, ARG_framebuffer, ARG_height, ARG_tile, ARG_serpentine };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_bit_depth, MP_ARG_INT | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_rgb_pins, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_addr_pins, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_clock_pin, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_latch_pin, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_output_enable_pin, MP_ARG_OBJ | MP_ARG_REQUIRED | MP_ARG_KW_ONLY },
+ { MP_QSTR_doublebuffer, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = true } },
+ { MP_QSTR_framebuffer, MP_ARG_OBJ | MP_ARG_KW_ONLY, { .u_obj = mp_const_none } },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, { .u_int = 0 } },
+ { MP_QSTR_tile, MP_ARG_INT | MP_ARG_KW_ONLY, { .u_int = 1 } },
+ { MP_QSTR_serpentine, MP_ARG_BOOL | MP_ARG_KW_ONLY, { .u_bool = true } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ rgbmatrix_rgbmatrix_obj_t *self = &allocate_display_bus_or_raise()->rgbmatrix;
+ self->base.type = &rgbmatrix_RGBMatrix_type;
+
+ uint8_t rgb_count, addr_count;
+ uint8_t rgb_pins[MP_ARRAY_SIZE(self->rgb_pins)];
+ uint8_t addr_pins[MP_ARRAY_SIZE(self->addr_pins)];
+ uint8_t clock_pin = validate_pin(args[ARG_clock_pin].u_obj);
+ uint8_t latch_pin = validate_pin(args[ARG_latch_pin].u_obj);
+ uint8_t output_enable_pin = validate_pin(args[ARG_output_enable_pin].u_obj);
+ int bit_depth = args[ARG_bit_depth].u_int;
+
+ if (bit_depth <= 0 || bit_depth > 6) {
+ mp_raise_ValueError_varg(translate("Bit depth must be from 1 to 6 inclusive, not %d"), bit_depth);
+ }
+
+ validate_pins(MP_QSTR_rgb_pins, rgb_pins, MP_ARRAY_SIZE(self->rgb_pins), args[ARG_rgb_list].u_obj, &rgb_count);
+ validate_pins(MP_QSTR_addr_pins, addr_pins, MP_ARRAY_SIZE(self->addr_pins), args[ARG_addr_list].u_obj, &addr_count);
+
+ if (rgb_count % 6) {
+ mp_raise_ValueError_varg(translate("Must use a multiple of 6 rgb pins, not %d"), rgb_count);
+ }
+
+ int tile = args[ARG_tile].u_int;
+
+ if (tile <= 0) {
+ mp_raise_ValueError_varg(
+ translate("tile must be greater than zero"));
+ }
+
+ int computed_height = (rgb_count / 3) * (1 << (addr_count)) * tile;
+ if (args[ARG_height].u_int != 0) {
+ if (computed_height != args[ARG_height].u_int) {
+ mp_raise_ValueError_varg(
+ translate("%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d"), addr_count, rgb_count, tile, computed_height, args[ARG_height].u_int);
+ }
+ }
+
+ if (args[ARG_width].u_int <= 0) {
+ mp_raise_ValueError(translate("width must be greater than zero"));
+ }
+
+ preflight_pins_or_throw(clock_pin, rgb_pins, rgb_count, true);
+
+ mp_obj_t framebuffer = args[ARG_framebuffer].u_obj;
+ if (framebuffer == mp_const_none) {
+ int width = args[ARG_width].u_int;
+ int bufsize = 2 * width * computed_height;
+ framebuffer = mp_obj_new_bytearray_of_zeros(bufsize);
+ }
+
+ common_hal_rgbmatrix_rgbmatrix_construct(self,
+ args[ARG_width].u_int,
+ bit_depth,
+ rgb_count, rgb_pins,
+ addr_count, addr_pins,
+ clock_pin, latch_pin, output_enable_pin,
+ args[ARG_doublebuffer].u_bool,
+ framebuffer, tile, args[ARG_serpentine].u_bool, NULL);
+
+ claim_and_never_reset_pins(args[ARG_rgb_list].u_obj);
+ claim_and_never_reset_pins(args[ARG_addr_list].u_obj);
+ claim_and_never_reset_pin(args[ARG_clock_pin].u_obj);
+ claim_and_never_reset_pin(args[ARG_output_enable_pin].u_obj);
+ claim_and_never_reset_pin(args[ARG_latch_pin].u_obj);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Free the resources (pins, timers, etc.) associated with this
+//| rgbmatrix instance. After deinitialization, no further operations
+//| may be performed."""
+//| ...
+//|
+STATIC mp_obj_t rgbmatrix_rgbmatrix_deinit(mp_obj_t self_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ common_hal_rgbmatrix_rgbmatrix_deinit(self);
+ return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_deinit_obj, rgbmatrix_rgbmatrix_deinit);
+
+static void check_for_deinit(rgbmatrix_rgbmatrix_obj_t *self) {
+ if (!self->protomatter.rgbPins) {
+ raise_deinited_error();
+ }
+}
+
+//| brightness: float
+//| """In the current implementation, 0.0 turns the display off entirely
+//| and any other value up to 1.0 turns the display on fully."""
+//|
+STATIC mp_obj_t rgbmatrix_rgbmatrix_get_brightness(mp_obj_t self_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_rgbmatrix_rgbmatrix_get_paused(self)? 0.0f : 1.0f);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_get_brightness_obj, rgbmatrix_rgbmatrix_get_brightness);
+
+STATIC mp_obj_t rgbmatrix_rgbmatrix_set_brightness(mp_obj_t self_in, mp_obj_t value_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+ mp_float_t brightness = mp_obj_get_float(value_in);
+ if (brightness < 0.0f || brightness > 1.0f) {
+ mp_raise_ValueError(translate("Brightness must be 0-1.0"));
+ }
+ common_hal_rgbmatrix_rgbmatrix_set_paused(self, brightness <= 0);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(rgbmatrix_rgbmatrix_set_brightness_obj, rgbmatrix_rgbmatrix_set_brightness);
+
+MP_PROPERTY_GETSET(rgbmatrix_rgbmatrix_brightness_obj,
+ (mp_obj_t)&rgbmatrix_rgbmatrix_get_brightness_obj,
+ (mp_obj_t)&rgbmatrix_rgbmatrix_set_brightness_obj);
+
+//| def refresh(self) -> None:
+//| """Transmits the color data in the buffer to the pixels so that
+//| they are shown."""
+//| ...
+//|
+STATIC mp_obj_t rgbmatrix_rgbmatrix_refresh(mp_obj_t self_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+ common_hal_rgbmatrix_rgbmatrix_refresh(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_refresh_obj, rgbmatrix_rgbmatrix_refresh);
+
+//| width: int
+//| """The width of the display, in pixels"""
+//|
+STATIC mp_obj_t rgbmatrix_rgbmatrix_get_width(mp_obj_t self_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_rgbmatrix_rgbmatrix_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_get_width_obj, rgbmatrix_rgbmatrix_get_width);
+MP_PROPERTY_GETTER(rgbmatrix_rgbmatrix_width_obj,
+ (mp_obj_t)&rgbmatrix_rgbmatrix_get_width_obj);
+
+//| height: int
+//| """The height of the display, in pixels"""
+//|
+STATIC mp_obj_t rgbmatrix_rgbmatrix_get_height(mp_obj_t self_in) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_rgbmatrix_rgbmatrix_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_get_height_obj, rgbmatrix_rgbmatrix_get_height);
+
+MP_PROPERTY_GETTER(rgbmatrix_rgbmatrix_height_obj,
+ (mp_obj_t)&rgbmatrix_rgbmatrix_get_height_obj);
+
+STATIC const mp_rom_map_elem_t rgbmatrix_rgbmatrix_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rgbmatrix_rgbmatrix_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&rgbmatrix_rgbmatrix_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&rgbmatrix_rgbmatrix_refresh_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&rgbmatrix_rgbmatrix_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&rgbmatrix_rgbmatrix_height_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(rgbmatrix_rgbmatrix_locals_dict, rgbmatrix_rgbmatrix_locals_dict_table);
+
+STATIC void rgbmatrix_rgbmatrix_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ check_for_deinit(self);
+
+ *bufinfo = self->bufinfo;
+}
+
+// These version exists so that the prototype matches the protocol,
+// avoiding a type cast that can hide errors
+STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) {
+ (void)dirty_row_bitmap;
+ common_hal_rgbmatrix_rgbmatrix_refresh(self_in);
+}
+
+STATIC void rgbmatrix_rgbmatrix_deinit_proto(mp_obj_t self_in) {
+ common_hal_rgbmatrix_rgbmatrix_deinit(self_in);
+}
+
+STATIC float rgbmatrix_rgbmatrix_get_brightness_proto(mp_obj_t self_in) {
+ return common_hal_rgbmatrix_rgbmatrix_get_paused(self_in) ? 0.0f : 1.0f;
+}
+
+STATIC bool rgbmatrix_rgbmatrix_set_brightness_proto(mp_obj_t self_in, mp_float_t value) {
+ common_hal_rgbmatrix_rgbmatrix_set_paused(self_in, value <= 0);
+ return true;
+}
+
+STATIC int rgbmatrix_rgbmatrix_get_width_proto(mp_obj_t self_in) {
+ return common_hal_rgbmatrix_rgbmatrix_get_width(self_in);
+}
+
+STATIC int rgbmatrix_rgbmatrix_get_height_proto(mp_obj_t self_in) {
+ return common_hal_rgbmatrix_rgbmatrix_get_height(self_in);
+}
+
+STATIC int rgbmatrix_rgbmatrix_get_color_depth_proto(mp_obj_t self_in) {
+ return 16;
+}
+
+STATIC int rgbmatrix_rgbmatrix_get_bytes_per_cell_proto(mp_obj_t self_in) {
+ return 1;
+}
+
+STATIC int rgbmatrix_rgbmatrix_get_native_frames_per_second_proto(mp_obj_t self_in) {
+ return 250;
+}
+
+
+STATIC const framebuffer_p_t rgbmatrix_rgbmatrix_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer)
+ .get_bufinfo = rgbmatrix_rgbmatrix_get_bufinfo,
+ .set_brightness = rgbmatrix_rgbmatrix_set_brightness_proto,
+ .get_brightness = rgbmatrix_rgbmatrix_get_brightness_proto,
+ .get_width = rgbmatrix_rgbmatrix_get_width_proto,
+ .get_height = rgbmatrix_rgbmatrix_get_height_proto,
+ .get_color_depth = rgbmatrix_rgbmatrix_get_color_depth_proto,
+ .get_bytes_per_cell = rgbmatrix_rgbmatrix_get_bytes_per_cell_proto,
+ .get_native_frames_per_second = rgbmatrix_rgbmatrix_get_native_frames_per_second_proto,
+ .swapbuffers = rgbmatrix_rgbmatrix_swapbuffers,
+ .deinit = rgbmatrix_rgbmatrix_deinit_proto,
+};
+
+STATIC mp_int_t rgbmatrix_rgbmatrix_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ rgbmatrix_rgbmatrix_obj_t *self = (rgbmatrix_rgbmatrix_obj_t *)self_in;
+ // a readonly framebuffer would be unusual but not impossible
+ if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
+ return 1;
+ }
+ *bufinfo = self->bufinfo;
+ bufinfo->typecode = 'H';
+ return 0;
+}
+
+const mp_obj_type_t rgbmatrix_RGBMatrix_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_RGBMatrix,
+ .locals_dict = (mp_obj_dict_t *)&rgbmatrix_rgbmatrix_locals_dict,
+ .make_new = rgbmatrix_rgbmatrix_make_new,
+ MP_TYPE_EXTENDED_FIELDS(
+ .buffer_p = { .get_buffer = rgbmatrix_rgbmatrix_get_buffer, },
+ .protocol = &rgbmatrix_rgbmatrix_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.h b/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.h
new file mode 100644
index 0000000..127f920
--- /dev/null
+++ b/circuitpython/shared-bindings/rgbmatrix/RGBMatrix.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "shared-module/rgbmatrix/RGBMatrix.h"
+#include "lib/protomatter/src/core.h"
+
+extern const mp_obj_type_t rgbmatrix_RGBMatrix_type;
+
+void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, int width, int bit_depth, uint8_t rgb_count, uint8_t *rgb_pins, uint8_t addr_count, uint8_t *addr_pins, uint8_t clock_pin, uint8_t latch_pin, uint8_t oe_pin, bool doublebuffer, mp_obj_t framebuffer, int8_t tile, bool serpentine, void *timer);
+void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t *);
+void rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t *);
+void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t *self, mp_obj_t framebuffer);
+void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t *self, bool paused);
+bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t *self);
+void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t *self);
+int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t *self);
+int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t *self);
diff --git a/circuitpython/shared-bindings/rgbmatrix/__init__.c b/circuitpython/shared-bindings/rgbmatrix/__init__.c
new file mode 100644
index 0000000..a7da708
--- /dev/null
+++ b/circuitpython/shared-bindings/rgbmatrix/__init__.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/rgbmatrix/RGBMatrix.h"
+
+//| """Low-level routines for bitbanged LED matrices"""
+//|
+
+STATIC const mp_rom_map_elem_t rgbmatrix_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rgbmatrix) },
+ { MP_ROM_QSTR(MP_QSTR_RGBMatrix), MP_ROM_PTR(&rgbmatrix_RGBMatrix_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(rgbmatrix_module_globals, rgbmatrix_module_globals_table);
+
+const mp_obj_module_t rgbmatrix_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&rgbmatrix_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_rgbmatrix, rgbmatrix_module, CIRCUITPY_RGBMATRIX);
diff --git a/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.c b/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.c
new file mode 100644
index 0000000..0fe22be
--- /dev/null
+++ b/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.c
@@ -0,0 +1,188 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/runtime0.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/rotaryio/IncrementalEncoder.h"
+#include "shared-bindings/util.h"
+
+//| class IncrementalEncoder:
+//| """IncrementalEncoder determines the relative rotational position based on two series of pulses."""
+//|
+//| def __init__(self, pin_a: microcontroller.Pin, pin_b: microcontroller.Pin, divisor: int = 4) -> None:
+//| """Create an IncrementalEncoder object associated with the given pins. It tracks the positional
+//| state of an incremental rotary encoder (also known as a quadrature encoder.) Position is
+//| relative to the position when the object is contructed.
+//|
+//| :param ~microcontroller.Pin pin_a: First pin to read pulses from.
+//| :param ~microcontroller.Pin pin_b: Second pin to read pulses from.
+//| :param int divisor: The divisor of the quadrature signal.
+//|
+//| For example::
+//|
+//| import rotaryio
+//| import time
+//| from board import *
+//|
+//| enc = rotaryio.IncrementalEncoder(D1, D2)
+//| last_position = None
+//| while True:
+//| position = enc.position
+//| if last_position == None or position != last_position:
+//| print(position)
+//| last_position = position"""
+//| ...
+//|
+STATIC mp_obj_t rotaryio_incrementalencoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin_a, ARG_pin_b, ARG_divisor };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin_a, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_pin_b, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_divisor, MP_ARG_INT, { .u_int = 4 } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *pin_a = validate_obj_is_free_pin(args[ARG_pin_a].u_obj);
+ const mcu_pin_obj_t *pin_b = validate_obj_is_free_pin(args[ARG_pin_b].u_obj);
+
+ rotaryio_incrementalencoder_obj_t *self = m_new_obj(rotaryio_incrementalencoder_obj_t);
+ self->base.type = &rotaryio_incrementalencoder_type;
+
+ common_hal_rotaryio_incrementalencoder_construct(self, pin_a, pin_b);
+ common_hal_rotaryio_incrementalencoder_set_divisor(self, args[ARG_divisor].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitializes the IncrementalEncoder and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t rotaryio_incrementalencoder_deinit(mp_obj_t self_in) {
+ rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_rotaryio_incrementalencoder_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_deinit_obj, rotaryio_incrementalencoder_deinit);
+
+STATIC void check_for_deinit(rotaryio_incrementalencoder_obj_t *self) {
+ if (common_hal_rotaryio_incrementalencoder_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> IncrementalEncoder:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t rotaryio_incrementalencoder_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_rotaryio_incrementalencoder_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___obj, 4, 4, rotaryio_incrementalencoder_obj___exit__);
+
+
+//| divisor: int
+//| """The divisor of the quadrature signal. Use 1 for encoders without
+//| detents, or encoders with 4 detents per cycle. Use 2 for encoders with 2
+//| detents per cycle. Use 4 for encoders with 1 detent per cycle."""
+//|
+STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_divisor(mp_obj_t self_in) {
+ rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_divisor(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_divisor_obj, rotaryio_incrementalencoder_obj_get_divisor);
+
+STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_divisor(mp_obj_t self_in, mp_obj_t new_divisor) {
+ rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_rotaryio_incrementalencoder_set_divisor(self, mp_obj_get_int(new_divisor));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(rotaryio_incrementalencoder_set_divisor_obj, rotaryio_incrementalencoder_obj_set_divisor);
+
+MP_PROPERTY_GETSET(rotaryio_incrementalencoder_divisor_obj,
+ (mp_obj_t)&rotaryio_incrementalencoder_get_divisor_obj,
+ (mp_obj_t)&rotaryio_incrementalencoder_set_divisor_obj);
+
+//| position: int
+//| """The current position in terms of pulses. The number of pulses per rotation is defined by the
+//| specific hardware and by the divisor."""
+//|
+STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) {
+ rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_position(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_position_obj, rotaryio_incrementalencoder_obj_get_position);
+
+STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_position(mp_obj_t self_in, mp_obj_t new_position) {
+ rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_rotaryio_incrementalencoder_set_position(self, mp_obj_get_int(new_position));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(rotaryio_incrementalencoder_set_position_obj, rotaryio_incrementalencoder_obj_set_position);
+
+MP_PROPERTY_GETSET(rotaryio_incrementalencoder_position_obj,
+ (mp_obj_t)&rotaryio_incrementalencoder_get_position_obj,
+ (mp_obj_t)&rotaryio_incrementalencoder_set_position_obj);
+
+STATIC const mp_rom_map_elem_t rotaryio_incrementalencoder_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rotaryio_incrementalencoder_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&rotaryio_incrementalencoder___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&rotaryio_incrementalencoder_position_obj) },
+ { MP_ROM_QSTR(MP_QSTR_divisor), MP_ROM_PTR(&rotaryio_incrementalencoder_divisor_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(rotaryio_incrementalencoder_locals_dict, rotaryio_incrementalencoder_locals_dict_table);
+
+const mp_obj_type_t rotaryio_incrementalencoder_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_IncrementalEncoder,
+ .make_new = rotaryio_incrementalencoder_make_new,
+ .locals_dict = (mp_obj_dict_t *)&rotaryio_incrementalencoder_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.h b/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.h
new file mode 100644
index 0000000..45551c3
--- /dev/null
+++ b/circuitpython/shared-bindings/rotaryio/IncrementalEncoder.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/rotaryio/IncrementalEncoder.h"
+
+extern const mp_obj_type_t rotaryio_incrementalencoder_type;
+
+extern void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self,
+ const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b);
+extern void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self);
+extern bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self);
+extern mp_int_t common_hal_rotaryio_incrementalencoder_get_position(rotaryio_incrementalencoder_obj_t *self);
+extern void common_hal_rotaryio_incrementalencoder_set_position(rotaryio_incrementalencoder_obj_t *self,
+ mp_int_t new_position);
+extern mp_int_t common_hal_rotaryio_incrementalencoder_get_divisor(rotaryio_incrementalencoder_obj_t *self);
+extern void common_hal_rotaryio_incrementalencoder_set_divisor(rotaryio_incrementalencoder_obj_t *self,
+ mp_int_t new_divisor);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO_INCREMENTALENCODER_H
diff --git a/circuitpython/shared-bindings/rotaryio/__init__.c b/circuitpython/shared-bindings/rotaryio/__init__.c
new file mode 100644
index 0000000..43a884e
--- /dev/null
+++ b/circuitpython/shared-bindings/rotaryio/__init__.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/rotaryio/__init__.h"
+#include "shared-bindings/rotaryio/IncrementalEncoder.h"
+
+//| """Support for reading rotation sensors
+//|
+//| The `rotaryio` module contains classes to read different rotation encoding schemes. See
+//| `Wikipedia's Rotary Encoder page <https://en.wikipedia.org/wiki/Rotary_encoder>`_ for more
+//| background.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//|
+
+STATIC const mp_rom_map_elem_t rotaryio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rotaryio) },
+ { MP_ROM_QSTR(MP_QSTR_IncrementalEncoder), MP_ROM_PTR(&rotaryio_incrementalencoder_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(rotaryio_module_globals, rotaryio_module_globals_table);
+
+const mp_obj_module_t rotaryio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&rotaryio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_rotaryio, rotaryio_module, CIRCUITPY_ROTARYIO);
diff --git a/circuitpython/shared-bindings/rotaryio/__init__.h b/circuitpython/shared-bindings/rotaryio/__init__.h
new file mode 100644
index 0000000..5d051d5
--- /dev/null
+++ b/circuitpython/shared-bindings/rotaryio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ROTARYIO___INIT___H
diff --git a/circuitpython/shared-bindings/rtc/RTC.c b/circuitpython/shared-bindings/rtc/RTC.c
new file mode 100644
index 0000000..b07f90b
--- /dev/null
+++ b/circuitpython/shared-bindings/rtc/RTC.c
@@ -0,0 +1,133 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared/timeutils/timeutils.h"
+#include "shared-bindings/rtc/__init__.h"
+#include "shared-bindings/rtc/RTC.h"
+#include "shared-bindings/time/__init__.h"
+#include "supervisor/shared/translate.h"
+
+const rtc_rtc_obj_t rtc_rtc_obj = {{&rtc_rtc_type}};
+
+//| class RTC:
+//| """Real Time Clock"""
+//|
+//| def __init__(self) -> None:
+//| """This class represents the onboard Real Time Clock. It is a singleton and will always return the same instance."""
+//| ...
+//|
+STATIC mp_obj_t rtc_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // No arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ // return constant object
+ return (mp_obj_t)&rtc_rtc_obj;
+}
+
+//| datetime: time.struct_time
+//| """The current date and time of the RTC as a `time.struct_time`.
+//|
+//| This must be set to the current date and time whenever the board loses power::
+//|
+//| import rtc
+//| import time
+//|
+//| r = rtc.RTC()
+//| r.datetime = time.struct_time((2019, 5, 29, 15, 14, 15, 0, -1, -1))
+//|
+//|
+//| Once set, the RTC will automatically update this value as time passes. You can read this
+//| property to get a snapshot of the current time::
+//|
+//| current_time = r.datetime
+//| print(current_time)
+//| # struct_time(tm_year=2019, tm_month=5, ...)"""
+//|
+STATIC mp_obj_t rtc_rtc_obj_get_datetime(mp_obj_t self_in) {
+ timeutils_struct_time_t tm;
+ common_hal_rtc_get_time(&tm);
+ return struct_time_from_tm(&tm);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rtc_rtc_get_datetime_obj, rtc_rtc_obj_get_datetime);
+
+STATIC mp_obj_t rtc_rtc_obj_set_datetime(mp_obj_t self_in, mp_obj_t datetime) {
+ timeutils_struct_time_t tm;
+ struct_time_to_tm(datetime, &tm);
+ common_hal_rtc_set_time(&tm);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(rtc_rtc_set_datetime_obj, rtc_rtc_obj_set_datetime);
+
+MP_PROPERTY_GETSET(rtc_rtc_datetime_obj,
+ (mp_obj_t)&rtc_rtc_get_datetime_obj,
+ (mp_obj_t)&rtc_rtc_set_datetime_obj);
+
+//| calibration: int
+//| """The RTC calibration value as an `int`.
+//|
+//| A positive value speeds up the clock and a negative value slows it down.
+//| Range and value is hardware specific, but one step is often approximately 1 ppm::
+//|
+//| import rtc
+//| import time
+//|
+//| r = rtc.RTC()
+//| r.calibration = 1"""
+//|
+STATIC mp_obj_t rtc_rtc_obj_get_calibration(mp_obj_t self_in) {
+ int calibration = common_hal_rtc_get_calibration();
+ return mp_obj_new_int(calibration);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rtc_rtc_get_calibration_obj, rtc_rtc_obj_get_calibration);
+
+STATIC mp_obj_t rtc_rtc_obj_set_calibration(mp_obj_t self_in, mp_obj_t calibration) {
+ common_hal_rtc_set_calibration(mp_obj_get_int(calibration));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(rtc_rtc_set_calibration_obj, rtc_rtc_obj_set_calibration);
+
+MP_PROPERTY_GETSET(rtc_rtc_calibration_obj,
+ (mp_obj_t)&rtc_rtc_get_calibration_obj,
+ (mp_obj_t)&rtc_rtc_set_calibration_obj);
+
+STATIC const mp_rom_map_elem_t rtc_rtc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&rtc_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_calibration), MP_ROM_PTR(&rtc_rtc_calibration_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(rtc_rtc_locals_dict, rtc_rtc_locals_dict_table);
+
+const mp_obj_type_t rtc_rtc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RTC,
+ .make_new = rtc_rtc_make_new,
+ .locals_dict = (mp_obj_dict_t *)&rtc_rtc_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/rtc/RTC.h b/circuitpython/shared-bindings/rtc/RTC.h
new file mode 100644
index 0000000..ede824f
--- /dev/null
+++ b/circuitpython/shared-bindings/rtc/RTC.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RTC_RTC_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_RTC_RTC_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "py/obj.h"
+#include "shared/timeutils/timeutils.h"
+
+extern void common_hal_rtc_get_time(timeutils_struct_time_t *tm);
+extern void common_hal_rtc_set_time(timeutils_struct_time_t *tm);
+
+extern int common_hal_rtc_get_calibration(void);
+extern void common_hal_rtc_set_calibration(int calibration);
+
+extern const mp_obj_type_t rtc_rtc_type;
+
+typedef struct _rtc_rtc_obj_t {
+ mp_obj_base_t base;
+} rtc_rtc_obj_t;
+
+extern const rtc_rtc_obj_t rtc_rtc_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_RTC_RTC_H
diff --git a/circuitpython/shared-bindings/rtc/__init__.c b/circuitpython/shared-bindings/rtc/__init__.c
new file mode 100644
index 0000000..0220745
--- /dev/null
+++ b/circuitpython/shared-bindings/rtc/__init__.c
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "shared-bindings/rtc/__init__.h"
+#include "shared-bindings/rtc/RTC.h"
+#include "shared-bindings/time/__init__.h"
+
+//| """Real Time Clock
+//|
+//| The `rtc` module provides support for a Real Time Clock. You can access and manage the
+//| RTC using :class:`rtc.RTC`. It also backs the :func:`time.time` and :func:`time.localtime`
+//| functions using the onboard RTC if present."""
+//|
+
+void rtc_reset(void) {
+ MP_STATE_VM(rtc_time_source) = (mp_obj_t)&rtc_rtc_obj;
+}
+
+mp_obj_t rtc_get_time_source_time(void) {
+ mp_obj_t datetime = mp_load_attr(MP_STATE_VM(rtc_time_source), MP_QSTR_datetime);
+ timeutils_struct_time_t tm;
+ struct_time_to_tm(datetime, &tm);
+ // This sets tm_wday and tm_yday
+ return struct_time_from_tm(&tm);
+}
+
+//| def set_time_source(rtc: RTC) -> None:
+//| """Sets the RTC time source used by :func:`time.localtime`.
+//| The default is :class:`rtc.RTC`, but it's useful to use this to override the
+//| time source for testing purposes. For example::
+//|
+//| import rtc
+//| import time
+//|
+//| class RTC(object):
+//| @property
+//| def datetime(self):
+//| return time.struct_time((2018, 3, 17, 21, 1, 47, 0, 0, 0))
+//|
+//| r = RTC()
+//| rtc.set_time_source(r)"""
+//| ...
+//|
+STATIC mp_obj_t rtc_set_time_source(mp_obj_t time_source) {
+ MP_STATE_VM(rtc_time_source) = time_source;
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(rtc_set_time_source_obj, rtc_set_time_source);
+
+STATIC const mp_rom_map_elem_t rtc_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rtc) },
+ { MP_ROM_QSTR(MP_QSTR_set_time_source), MP_ROM_PTR(&rtc_set_time_source_obj) },
+ { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&rtc_rtc_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(rtc_module_globals, rtc_module_globals_table);
+
+const mp_obj_module_t rtc_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&rtc_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_rtc, rtc_module, CIRCUITPY_RTC);
diff --git a/circuitpython/shared-bindings/rtc/__init__.h b/circuitpython/shared-bindings/rtc/__init__.h
new file mode 100644
index 0000000..04f8f8b
--- /dev/null
+++ b/circuitpython/shared-bindings/rtc/__init__.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RTC___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_RTC___INIT___H
+
+#include "py/obj.h"
+
+extern void rtc_reset(void);
+extern mp_obj_t rtc_get_time_source_time(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_RTC___INIT___H
diff --git a/circuitpython/shared-bindings/sdcardio/SDCard.c b/circuitpython/shared-bindings/sdcardio/SDCard.c
new file mode 100644
index 0000000..5afca79
--- /dev/null
+++ b/circuitpython/shared-bindings/sdcardio/SDCard.c
@@ -0,0 +1,206 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/objarray.h"
+
+#include "shared-bindings/sdcardio/SDCard.h"
+#include "shared-module/sdcardio/SDCard.h"
+#include "common-hal/busio/SPI.h"
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "supervisor/flash.h"
+
+//| class SDCard:
+//| """SD Card Block Interface
+//|
+//| Controls an SD card over SPI. This built-in module has higher read
+//| performance than the library adafruit_sdcard, but it is only compatible with
+//| `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used
+//| with ``storage.VfsFat`` to allow file I/O to an SD card."""
+//|
+//| def __init__(self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000) -> None:
+//| """Construct an SPI SD Card object with the given properties
+//|
+//| :param busio.SPI spi: The SPI bus
+//| :param microcontroller.Pin cs: The chip select connected to the card
+//| :param int baudrate: The SPI data rate to use after card setup
+//|
+//| Note that during detection and configuration, a hard-coded low baudrate is used.
+//| Data transfers use the specified baurate (rounded down to one that is supported by
+//| the microcontroller)
+//|
+//| .. important::
+//| If the same SPI bus is shared with other peripherals, it is important that
+//| the SD card be initialized before accessing any other peripheral on the bus.
+//| Failure to do so can prevent the SD card from being recognized until it is
+//| powered off or re-inserted.
+//|
+//| Example usage:
+//|
+//| .. code-block:: python
+//|
+//| import os
+//|
+//| import board
+//| import sdcardio
+//| import storage
+//|
+//| sd = sdcardio.SDCard(board.SPI(), board.SD_CS)
+//| vfs = storage.VfsFat(sd)
+//| storage.mount(vfs, '/sd')
+//| os.listdir('/sd')"""
+
+STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_spi, ARG_cs, ARG_baudrate, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi, MP_ARG_OBJ, {.u_obj = mp_const_none } },
+ { MP_QSTR_cs, MP_ARG_OBJ, {.u_obj = mp_const_none } },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 8000000} },
+ };
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj);
+ const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj);
+
+ sdcardio_sdcard_obj_t *self = m_new_obj(sdcardio_sdcard_obj_t);
+ self->base.type = &sdcardio_SDCard_type;
+
+ common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int);
+
+ return self;
+}
+
+
+//| def count(self) -> int:
+//| """Returns the total number of sectors
+//|
+//| Due to technical limitations, this is a function and not a property.
+//|
+//| :return: The number of 512-byte blocks, as a number"""
+//|
+STATIC mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) {
+ sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
+ return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count);
+
+//| def deinit(self) -> None:
+//| """Disable permanently.
+//|
+//| :return: None"""
+//|
+STATIC mp_obj_t sdcardio_sdcard_deinit(mp_obj_t self_in) {
+ sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
+ common_hal_sdcardio_sdcard_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit);
+
+
+//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None:
+//|
+//| """Read one or more blocks from the card
+//|
+//| :param int start_block: The block to start reading from
+//| :param ~circuitpython_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
+//|
+//| :return: None"""
+//|
+
+STATIC mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
+ uint32_t start_block = mp_obj_get_int(start_block_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
+ sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
+ int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks);
+
+//| def sync(self) -> None:
+//| """Ensure all blocks written are actually committed to the SD card
+//|
+//| :return: None"""
+//| ...
+STATIC mp_obj_t sdcardio_sdcard_sync(mp_obj_t self_in) {
+ sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
+ int result = common_hal_sdcardio_sdcard_sync(self);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync);
+
+
+//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
+//|
+//| """Write one or more blocks to the card
+//|
+//| :param int start_block: The block to start writing from
+//| :param ~circuitpython_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
+//|
+//| :return: None"""
+//|
+
+STATIC mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
+ uint32_t start_block = mp_obj_get_int(start_block_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in;
+ int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks);
+
+STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&sdcardio_sdcard_sync_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(sdcardio_sdcard_locals_dict, sdcardio_sdcard_locals_dict_table);
+
+const mp_obj_type_t sdcardio_SDCard_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SDCard,
+ .make_new = sdcardio_sdcard_make_new,
+ .locals_dict = (mp_obj_dict_t *)&sdcardio_sdcard_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/sdcardio/SDCard.h b/circuitpython/shared-bindings/sdcardio/SDCard.h
new file mode 100644
index 0000000..5986d5b
--- /dev/null
+++ b/circuitpython/shared-bindings/sdcardio/SDCard.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+extern const mp_obj_type_t sdcardio_SDCard_type;
diff --git a/circuitpython/shared-bindings/sdcardio/__init__.c b/circuitpython/shared-bindings/sdcardio/__init__.c
new file mode 100644
index 0000000..c64a8a3
--- /dev/null
+++ b/circuitpython/shared-bindings/sdcardio/__init__.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/sdcardio/SDCard.h"
+
+//| """Interface to an SD card via the SPI bus"""
+
+STATIC const mp_rom_map_elem_t sdcardio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcardio) },
+ { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdcardio_SDCard_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sdcardio_module_globals, sdcardio_module_globals_table);
+
+const mp_obj_module_t sdcardio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&sdcardio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_sdcardio, sdcardio_module, CIRCUITPY_SDCARDIO);
diff --git a/circuitpython/shared-bindings/sdcardio/__init__.h b/circuitpython/shared-bindings/sdcardio/__init__.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/sdcardio/__init__.h
diff --git a/circuitpython/shared-bindings/sdioio/SDCard.c b/circuitpython/shared-bindings/sdioio/SDCard.c
new file mode 100644
index 0000000..f6407ff
--- /dev/null
+++ b/circuitpython/shared-bindings/sdioio/SDCard.c
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+// This file contains all of the Python API definitions for the
+// sdioio.SDCard class.
+
+#include <string.h>
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/sdioio/SDCard.h"
+#include "shared-bindings/util.h"
+
+#include "shared/runtime/buffer_helper.h"
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/mperrno.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class SDCard:
+//| """SD Card Block Interface with SDIO
+//|
+//| Controls an SD card over SDIO. SDIO is a parallel protocol designed
+//| for SD cards. It uses a clock pin, a command pin, and 1 or 4
+//| data pins. It can be operated at a high frequency such as
+//| 25MHz. Usually an SDCard object is used with ``storage.VfsFat``
+//| to allow file I/O to an SD card."""
+//|
+//| def __init__(self, clock: microcontroller.Pin, command: microcontroller.Pin, data: Sequence[microcontroller.Pin], frequency: int) -> None:
+//| """Construct an SDIO SD Card object with the given properties
+//|
+//| :param ~microcontroller.Pin clock: the pin to use for the clock.
+//| :param ~microcontroller.Pin command: the pin to use for the command.
+//| :param data: A sequence of pins to use for data.
+//| :param frequency: The frequency of the bus in Hz
+//|
+//| Example usage:
+//|
+//| .. code-block:: python
+//|
+//| import os
+//|
+//| import board
+//| import sdioio
+//| import storage
+//|
+//| sd = sdioio.SDCard(
+//| clock=board.SDIO_CLOCK,
+//| command=board.SDIO_COMMAND,
+//| data=board.SDIO_DATA,
+//| frequency=25000000)
+//| vfs = storage.VfsFat(sd)
+//| storage.mount(vfs, '/sd')
+//| os.listdir('/sd')"""
+//| ...
+//|
+
+STATIC mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ sdioio_sdcard_obj_t *self = m_new_obj(sdioio_sdcard_obj_t);
+ self->base.type = &sdioio_SDCard_type;
+ enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ },
+ { MP_QSTR_command, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ },
+ { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT },
+ };
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *command = validate_obj_is_free_pin(args[ARG_command].u_obj);
+ const mcu_pin_obj_t *data_pins[4];
+ uint8_t num_data;
+ validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data);
+
+ common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) {
+ if (common_hal_sdioio_sdcard_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def configure(self, frequency: int = 0, width: int = 0) -> None:
+//| """Configures the SDIO bus.
+//|
+//| :param int frequency: the desired clock rate in Hertz. The actual clock rate may be higher or lower due to the granularity of available clock settings. Check the `frequency` attribute for the actual clock rate.
+//| :param int width: the number of data lines to use. Must be 1 or 4 and must also not exceed the number of data lines at construction
+//|
+//| .. note:: Leaving a value unspecified or 0 means the current setting is kept"""
+//|
+STATIC mp_obj_t sdioio_sdcard_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_frequency, ARG_width, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t frequency = args[ARG_frequency].u_int;
+ if (frequency < 0) {
+ mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_baudrate);
+ }
+
+ uint8_t width = args[ARG_width].u_int;
+ if (width != 0 && width != 1 && width != 4) {
+ mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_width);
+ }
+
+ if (!common_hal_sdioio_sdcard_configure(self, frequency, width)) {
+ mp_raise_OSError(MP_EIO);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(sdioio_sdcard_configure_obj, 1, sdioio_sdcard_configure);
+
+//| def count(self) -> int:
+//| """Returns the total number of sectors
+//|
+//| Due to technical limitations, this is a function and not a property.
+//|
+//| :return: The number of 512-byte blocks, as a number"""
+//|
+STATIC mp_obj_t sdioio_sdcard_count(mp_obj_t self_in) {
+ sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_count_obj, sdioio_sdcard_count);
+
+//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None:
+//|
+//| """Read one or more blocks from the card
+//|
+//| :param int start_block: The block to start reading from
+//| :param ~circuitpython_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
+//|
+//| :return: None"""
+STATIC mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
+ uint32_t start_block = mp_obj_get_int(start_block_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
+ sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t *)self_in;
+ int result = common_hal_sdioio_sdcard_readblocks(self, start_block, &bufinfo);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks);
+
+//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
+//|
+//| """Write one or more blocks to the card
+//|
+//| :param int start_block: The block to start writing from
+//| :param ~circuitpython_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
+//|
+//| :return: None"""
+//|
+STATIC mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
+ uint32_t start_block = mp_obj_get_int(start_block_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t *)self_in;
+ int result = common_hal_sdioio_sdcard_writeblocks(self, start_block, &bufinfo);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, sdioio_sdcard_writeblocks);
+
+//| @property
+//| def frequency(self) -> int:
+//| """The actual SDIO bus frequency. This may not match the frequency
+//| requested due to internal limitations."""
+//| ...
+//|
+STATIC mp_obj_t sdioio_sdcard_obj_get_frequency(mp_obj_t self_in) {
+ sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_frequency(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_frequency_obj, sdioio_sdcard_obj_get_frequency);
+
+MP_PROPERTY_GETTER(sdioio_sdcard_frequency_obj,
+ (mp_obj_t)&sdioio_sdcard_get_frequency_obj);
+
+//| @property
+//| def width(self) -> int:
+//| """The actual SDIO bus width, in bits"""
+//| ...
+//|
+STATIC mp_obj_t sdioio_sdcard_obj_get_width(mp_obj_t self_in) {
+ sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_width_obj, sdioio_sdcard_obj_get_width);
+
+MP_PROPERTY_GETTER(sdioio_sdcard_width_obj,
+ (mp_obj_t)&sdioio_sdcard_get_width_obj);
+
+//| def deinit(self) -> None:
+//| """Disable permanently.
+//|
+//| :return: None"""
+STATIC mp_obj_t sdioio_sdcard_obj_deinit(mp_obj_t self_in) {
+ sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_sdioio_sdcard_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_deinit_obj, sdioio_sdcard_obj_deinit);
+
+//| def __enter__(self) -> SDCard:
+//| """No-op used by Context Managers.
+//| Provided by context manager helper."""
+//| ...
+//|
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t sdioio_sdcard_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_sdioio_sdcard_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sdioio_sdcard_obj___exit___obj, 4, 4, sdioio_sdcard_obj___exit__);
+
+STATIC const mp_rom_map_elem_t sdioio_sdcard_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdioio_sdcard_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&sdioio_sdcard_obj___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&sdioio_sdcard_configure_obj) },
+ { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&sdioio_sdcard_frequency_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sdioio_sdcard_width_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdioio_sdcard_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdioio_sdcard_readblocks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdioio_sdcard_writeblocks_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(sdioio_sdcard_locals_dict, sdioio_sdcard_locals_dict_table);
+
+const mp_obj_type_t sdioio_SDCard_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SDCard,
+ .make_new = sdioio_sdcard_make_new,
+ .locals_dict = (mp_obj_dict_t *)&sdioio_sdcard_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/sdioio/SDCard.h b/circuitpython/shared-bindings/sdioio/SDCard.h
new file mode 100644
index 0000000..cf15762
--- /dev/null
+++ b/circuitpython/shared-bindings/sdioio/SDCard.h
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H
+
+#include "py/obj.h"
+
+#include "common-hal/microcontroller/Pin.h"
+#include "common-hal/sdioio/SDCard.h"
+
+// Type object used in Python. Should be shared between ports.
+extern const mp_obj_type_t sdioio_SDCard_type;
+
+// Construct an underlying SDIO object.
+extern void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self,
+ const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command,
+ uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency);
+
+extern void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self);
+extern bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self);
+
+extern bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t baudrate, uint8_t width);
+
+extern void common_hal_sdioio_sdcard_unlock(sdioio_sdcard_obj_t *self);
+
+// Return actual SDIO bus frequency.
+uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t *self);
+
+// Return SDIO bus width.
+uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self);
+
+// Return number of device blocks
+uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self);
+
+// Read or write blocks
+int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo);
+int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo);
+
+// This is used by the supervisor to claim SDIO devices indefinitely.
+extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H
diff --git a/circuitpython/shared-bindings/sdioio/__init__.c b/circuitpython/shared-bindings/sdioio/__init__.c
new file mode 100644
index 0000000..5204da2
--- /dev/null
+++ b/circuitpython/shared-bindings/sdioio/__init__.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/sdioio/SDCard.h"
+
+//| """Interface to an SD card via the SDIO bus"""
+
+STATIC const mp_rom_map_elem_t sdioio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) },
+ { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sdioio_module_globals, sdioio_module_globals_table);
+
+const mp_obj_module_t sdioio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&sdioio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_sdioio, sdioio_module, CIRCUITPY_SDIOIO);
diff --git a/circuitpython/shared-bindings/sdioio/__init__.h b/circuitpython/shared-bindings/sdioio/__init__.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/sdioio/__init__.h
diff --git a/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c b/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
new file mode 100644
index 0000000..35e06b7
--- /dev/null
+++ b/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objarray.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/busio/SPI.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+#include "shared-module/displayio/__init__.h"
+#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+
+STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, NUM_ARGS };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 2000000} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS);
+
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj);
+ busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj);
+
+ sharpdisplay_framebuffer_obj_t *self = &allocate_display_bus_or_raise()->sharpdisplay;
+ self->base.type = &sharpdisplay_framebuffer_type;
+
+ common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+
+STATIC mp_int_t sharpdisplay_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t *)self_in;
+ // a readonly framebuffer would be unusual but not impossible
+ if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) {
+ return 1;
+ }
+ *bufinfo = self->bufinfo;
+ return 0;
+}
+
+STATIC mp_obj_t sharpdisplay_framebuffer_deinit(mp_obj_t self_in) {
+ sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t *)self_in;
+ common_hal_sharpdisplay_framebuffer_deinit(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(sharpdisplay_framebuffer_deinit_obj, sharpdisplay_framebuffer_deinit);
+
+STATIC const mp_rom_map_elem_t sharpdisplay_framebuffer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sharpdisplay_framebuffer_deinit_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(sharpdisplay_framebuffer_locals_dict, sharpdisplay_framebuffer_locals_dict_table);
+
+const mp_obj_type_t sharpdisplay_framebuffer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SharpMemoryFramebuffer,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = sharpdisplay_framebuffer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&sharpdisplay_framebuffer_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .buffer_p = { .get_buffer = sharpdisplay_framebuffer_get_buffer, },
+ .protocol = &sharpdisplay_framebuffer_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h b/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
new file mode 100644
index 0000000..30f1b86
--- /dev/null
+++ b/circuitpython/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+// #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h"
+// #include "shared-module/framebufferio/FramebufferDisplay.h"
+
+#include "py/objtype.h"
+
+extern const mp_obj_type_t sharpdisplay_framebuffer_type;
diff --git a/circuitpython/shared-bindings/sharpdisplay/__init__.c b/circuitpython/shared-bindings/sharpdisplay/__init__.c
new file mode 100644
index 0000000..8c01c8c
--- /dev/null
+++ b/circuitpython/shared-bindings/sharpdisplay/__init__.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Jeff Epler for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h"
+
+//| """Support for Sharp Memory Display framebuffers"""
+//|
+
+STATIC const mp_rom_map_elem_t sharpdisplay_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sharpdisplay) },
+ { MP_ROM_QSTR(MP_QSTR_SharpMemoryFramebuffer), MP_ROM_PTR(&sharpdisplay_framebuffer_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(sharpdisplay_module_globals, sharpdisplay_module_globals_table);
+
+const mp_obj_module_t sharpdisplay_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&sharpdisplay_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_sharpdisplay, sharpdisplay_module, CIRCUITPY_SHARPDISPLAY);
diff --git a/circuitpython/shared-bindings/sharpdisplay/__init__.h b/circuitpython/shared-bindings/sharpdisplay/__init__.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circuitpython/shared-bindings/sharpdisplay/__init__.h
diff --git a/circuitpython/shared-bindings/socketpool/Socket.c b/circuitpython/shared-bindings/socketpool/Socket.c
new file mode 100644
index 0000000..bea3cd1
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/Socket.c
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2021 Lucian Copeland for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/socketpool/Socket.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+
+#include "shared/netutils/netutils.h"
+
+//| class Socket:
+//| """TCP, UDP and RAW socket. Cannot be created directly. Instead, call
+//| `SocketPool.socket()`.
+//|
+//| Provides a subset of CPython's `socket.socket` API. It only implements the versions of
+//| recv that do not allocate bytes objects."""
+//|
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the Socket."""
+//| ...
+//|
+// Provided by mp_generic_unary_op().
+
+//| def __enter__(self) -> Socket:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically closes the Socket when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_socketpool_socket_close(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket___exit___obj, 4, 4, socketpool_socket___exit__);
+
+//| def accept(self) -> Tuple[Socket, Tuple[str, int]]:
+//| """Accept a connection on a listening socket of type SOCK_STREAM,
+//| creating a new socket of type SOCK_STREAM.
+//| Returns a tuple of (new_socket, remote_address)"""
+//|
+STATIC mp_obj_t socketpool_socket_accept(mp_obj_t self_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint8_t ip[4];
+ uint32_t port;
+
+ socketpool_socket_obj_t *sock = common_hal_socketpool_socket_accept(self, ip, &port);
+
+ mp_obj_t tuple_contents[2];
+ tuple_contents[0] = MP_OBJ_FROM_PTR(sock);
+ tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+ return mp_obj_new_tuple(2, tuple_contents);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_accept_obj, socketpool_socket_accept);
+
+//| def bind(self, address: Tuple[str, int]) -> None:
+//| """Bind a socket to an address
+//|
+//| :param ~tuple address: tuple of (remote_address, remote_port)"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+
+ size_t hostlen;
+ const char *host = mp_obj_str_get_data(addr_items[0], &hostlen);
+ mp_int_t port = mp_obj_get_int(addr_items[1]);
+ if (port < 0) {
+ mp_raise_ValueError(translate("port must be >= 0"));
+ }
+
+ bool ok = common_hal_socketpool_socket_bind(self, host, hostlen, (uint32_t)port);
+ if (!ok) {
+ mp_raise_ValueError(translate("Error: Failure to bind"));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_bind_obj, socketpool_socket_bind);
+
+//| def close(self) -> None:
+//| """Closes this Socket and makes its resources available to its SocketPool."""
+//|
+STATIC mp_obj_t socketpool_socket_close(mp_obj_t self_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_socketpool_socket_close(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_close_obj, socketpool_socket_close);
+
+//| def connect(self, address: Tuple[str, int]) -> None:
+//| """Connect a socket to a remote address
+//|
+//| :param ~tuple address: tuple of (remote_address, remote_port)"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+
+ size_t hostlen;
+ const char *host = mp_obj_str_get_data(addr_items[0], &hostlen);
+ mp_int_t port = mp_obj_get_int(addr_items[1]);
+ if (port < 0) {
+ mp_raise_ValueError(translate("port must be >= 0"));
+ }
+
+ common_hal_socketpool_socket_connect(self, host, hostlen, (uint32_t)port);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_connect_obj, socketpool_socket_connect);
+
+//| def listen(self, backlog: int) -> None:
+//| """Set socket to listen for incoming connections
+//|
+//| :param ~int backlog: length of backlog queue for waiting connetions"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ int backlog = mp_obj_get_int(backlog_in);
+
+ common_hal_socketpool_socket_listen(self, backlog);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_listen_obj, socketpool_socket_listen);
+
+//| def recvfrom_into(self, buffer: WriteableBuffer) -> Tuple[int, Tuple[str, int]]:
+//| """Reads some bytes from a remote address.
+//|
+//| Returns a tuple containing
+//| * the number of bytes received into the given buffer
+//| * a remote_address, which is a tuple of ip address and port number
+//|
+//| :param object buffer: buffer to read into"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_recvfrom_into(mp_obj_t self_in, mp_obj_t data_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_WRITE);
+
+ byte ip[4];
+ mp_uint_t port;
+ mp_int_t ret = common_hal_socketpool_socket_recvfrom_into(self,
+ (byte *)bufinfo.buf, bufinfo.len, ip, &port);
+ mp_obj_t tuple_contents[2];
+ tuple_contents[0] = mp_obj_new_int_from_uint(ret);
+ tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+ return mp_obj_new_tuple(2, tuple_contents);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_recvfrom_into_obj, socketpool_socket_recvfrom_into);
+
+//| def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int:
+//| """Reads some bytes from the connected remote address, writing
+//| into the provided buffer. If bufsize <= len(buffer) is given,
+//| a maximum of bufsize bytes will be read into the buffer. If no
+//| valid value is given for bufsize, the default is the length of
+//| the given buffer.
+//|
+//| Suits sockets of type SOCK_STREAM
+//| Returns an int of number of bytes read.
+//|
+//| :param bytearray buffer: buffer to receive into
+//| :param int bufsize: optionally, a maximum number of bytes to read."""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_recv_into(size_t n_args, const mp_obj_t *args) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (common_hal_socketpool_socket_get_closed(self)) {
+ // Bad file number.
+ mp_raise_OSError(MP_EBADF);
+ }
+ // if (!common_hal_socketpool_socket_get_connected(self)) {
+ // // not connected
+ // mp_raise_OSError(MP_ENOTCONN);
+ // }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ mp_int_t len = bufinfo.len;
+ if (n_args == 3) {
+ mp_int_t given_len = mp_obj_get_int(args[2]);
+ if (given_len > len) {
+ mp_raise_ValueError(translate("buffer too small for requested bytes"));
+ }
+ if (given_len > 0 && given_len < len) {
+ len = given_len;
+ }
+ }
+
+ if (len == 0) {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ mp_int_t ret = common_hal_socketpool_socket_recv_into(self, (byte *)bufinfo.buf, len);
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket_recv_into_obj, 2, 3, socketpool_socket_recv_into);
+
+//| def send(self, bytes: ReadableBuffer) -> int:
+//| """Send some bytes to the connected remote address.
+//| Suits sockets of type SOCK_STREAM
+//|
+//| :param ~bytes bytes: some bytes to send"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (common_hal_socketpool_socket_get_closed(self)) {
+ // Bad file number.
+ mp_raise_OSError(MP_EBADF);
+ }
+ if (!common_hal_socketpool_socket_get_connected(self)) {
+ mp_raise_BrokenPipeError();
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ mp_int_t ret = common_hal_socketpool_socket_send(self, bufinfo.buf, bufinfo.len);
+ if (ret == -1) {
+ mp_raise_BrokenPipeError();
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_send_obj, socketpool_socket_send);
+
+//| def sendto(self, bytes: ReadableBuffer, address: Tuple[str, int]) -> int:
+//| """Send some bytes to a specific address.
+//| Suits sockets of type SOCK_DGRAM
+//|
+//| :param ~bytes bytes: some bytes to send
+//| :param ~tuple address: tuple of (remote_address, remote_port)"""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // get the data
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+
+ size_t hostlen;
+ const char *host = mp_obj_str_get_data(addr_items[0], &hostlen);
+ mp_int_t port = mp_obj_get_int(addr_items[1]);
+ if (port < 0) {
+ mp_raise_ValueError(translate("port must be >= 0"));
+ }
+
+ mp_int_t ret = common_hal_socketpool_socket_sendto(self, host, hostlen, (uint32_t)port, bufinfo.buf, bufinfo.len);
+
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socketpool_socket_sendto_obj, socketpool_socket_sendto);
+
+//| def setblocking(self, flag: bool) -> Optional[int]:
+//| """Set the blocking behaviour of this socket.
+//|
+//| :param ~bool flag: False means non-blocking, True means block indefinitely."""
+//| ...
+//|
+// method socket.setblocking(flag)
+STATIC mp_obj_t socketpool_socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (mp_obj_is_true(blocking)) {
+ common_hal_socketpool_socket_settimeout(self, -1);
+ } else {
+ common_hal_socketpool_socket_settimeout(self, 0);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_setblocking_obj, socketpool_socket_setblocking);
+
+// //| def setsockopt(self, level: int, optname: int, value: int) -> None:
+// //| """Sets socket options"""
+// //| ...
+// //|
+// STATIC mp_obj_t socketpool_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
+// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+// // mp_int_t level = mp_obj_get_int(args[1]);
+// // mp_int_t opt = mp_obj_get_int(args[2]);
+
+// // const void *optval;
+// // mp_uint_t optlen;
+// // mp_int_t val;
+// // if (mp_obj_is_integer(args[3])) {
+// // val = mp_obj_get_int_truncated(args[3]);
+// // optval = &val;
+// // optlen = sizeof(val);
+// // } else {
+// // mp_buffer_info_t bufinfo;
+// // mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+// // optval = bufinfo.buf;
+// // optlen = bufinfo.len;
+// // }
+
+// // int _errno;
+// // if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
+// // mp_raise_OSError(_errno);
+// // }
+
+// return mp_const_none;
+// }
+// STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket_setsockopt_obj, 4, 4, socketpool_socket_setsockopt);
+
+
+//| def settimeout(self, value: int) -> None:
+//| """Set the timeout value for this socket.
+//|
+//| :param ~int value: timeout in seconds. 0 means non-blocking. None means block indefinitely."""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t timeout_ms;
+ if (timeout_in == mp_const_none) {
+ timeout_ms = -1;
+ } else {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ timeout_ms = 1000 * mp_obj_get_float(timeout_in);
+ #else
+ timeout_ms = 1000 * mp_obj_get_int(timeout_in);
+ #endif
+ }
+ common_hal_socketpool_socket_settimeout(self, timeout_ms);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_settimeout_obj, socketpool_socket_settimeout);
+
+STATIC const mp_rom_map_elem_t socketpool_socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&socketpool_socket___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socketpool_socket_close_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socketpool_socket_accept_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socketpool_socket_bind_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socketpool_socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socketpool_socket_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socketpool_socket_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recvfrom_into), MP_ROM_PTR(&socketpool_socket_recvfrom_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socketpool_socket_recv_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socketpool_socket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socketpool_socket_sendto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socketpool_socket_setblocking_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socketpool_socket_setsockopt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socketpool_socket_settimeout_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(socketpool_socket_locals_dict, socketpool_socket_locals_dict_table);
+
+const mp_obj_type_t socketpool_socket_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Socket,
+ .locals_dict = (mp_obj_dict_t *)&socketpool_socket_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_generic_unary_op,
+ )
+};
diff --git a/circuitpython/shared-bindings/socketpool/Socket.h b/circuitpython/shared-bindings/socketpool/Socket.h
new file mode 100644
index 0000000..1f4ab6f
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/Socket.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKET_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKET_H
+
+#include "common-hal/socketpool/Socket.h"
+
+extern const mp_obj_type_t socketpool_socket_type;
+
+socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port);
+bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port);
+void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self);
+void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port);
+bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t *self);
+bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *self);
+mp_uint_t common_hal_socketpool_socket_get_timeout(socketpool_socket_obj_t *self);
+bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog);
+mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *self,
+ uint8_t *buf, uint32_t len, uint8_t *ip, uint32_t *port);
+mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len);
+mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len);
+mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self,
+ const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len);
+void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t *self, uint32_t timeout_ms);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKET_H
diff --git a/circuitpython/shared-bindings/socketpool/SocketPool.c b/circuitpython/shared-bindings/socketpool/SocketPool.c
new file mode 100644
index 0000000..447d2d7
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/SocketPool.c
@@ -0,0 +1,166 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+
+#include "shared-bindings/ipaddress/__init__.h"
+#include "shared-bindings/socketpool/Socket.h"
+#include "shared-bindings/socketpool/SocketPool.h"
+
+//| class SocketPool:
+//| """A pool of socket resources available for the given radio. Only one
+//| SocketPool can be created for each radio.
+//|
+//| SocketPool should be used in place of CPython's socket which provides
+//| a pool of sockets provided by the underlying OS."""
+//|
+
+STATIC mp_obj_t socketpool_socketpool_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ socketpool_socketpool_obj_t *s = m_new_obj_with_finaliser(socketpool_socketpool_obj_t);
+ s->base.type = &socketpool_socketpool_type;
+ mp_obj_t radio = args[0];
+
+ common_hal_socketpool_socketpool_construct(s, radio);
+
+ return MP_OBJ_FROM_PTR(s);
+}
+
+//| AF_INET: int
+//| AF_INET6: int
+//| SOCK_STREAM: int
+//| SOCK_DGRAM: int
+//| SOCK_RAW: int
+//|
+//| def socket(self, family: int = AF_INET, type: int = SOCK_STREAM) -> socketpool.Socket:
+//| """Create a new socket
+//|
+//| :param ~int family: AF_INET or AF_INET6
+//| :param ~int type: SOCK_STREAM, SOCK_DGRAM or SOCK_RAW
+//|
+//| The ``proto`` (protocol) and ``fileno`` arguments available in ``socket.socket()``
+//| in CPython are not supported.
+//| """
+//| ...
+//|
+STATIC mp_obj_t socketpool_socketpool_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_family, ARG_type };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_family, MP_ARG_INT, {.u_int = SOCKETPOOL_AF_INET} },
+ { MP_QSTR_type, MP_ARG_INT, {.u_int = SOCKETPOOL_SOCK_STREAM} },
+ };
+ socketpool_socketpool_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ socketpool_socketpool_addressfamily_t family = args[ARG_family].u_int;
+ socketpool_socketpool_sock_t type = args[ARG_type].u_int;
+
+ return common_hal_socketpool_socket(self, family, type);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_socket_obj, 1, socketpool_socketpool_socket);
+
+//| def getaddrinfo(self, host: str, port: int, family: int = 0, type: int = 0, proto: int = 0, flags: int = 0) -> Tuple[int, int, int, str, Tuple[str, int]]:
+//| """Gets the address information for a hostname and port
+//|
+//| Returns the appropriate family, socket type, socket protocol and
+//| address information to call socket.socket() and socket.connect() with,
+//| as a tuple."""
+//| ...
+//|
+STATIC mp_obj_t socketpool_socketpool_getaddrinfo(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_host, ARG_port, ARG_family, ARG_type, ARG_proto, ARG_flags };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_host, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_port, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_family, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_type, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_port, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_flags, MP_ARG_INT, {.u_int = 0} },
+ };
+ socketpool_socketpool_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *host = mp_obj_str_get_str(args[ARG_host].u_obj);
+ mp_int_t port = args[ARG_port].u_int;
+ mp_obj_t ip_str = mp_const_none;
+
+ if (strlen(host) > 0 && ipaddress_parse_ipv4address(host, strlen(host), NULL)) {
+ ip_str = args[ARG_host].u_obj;
+ }
+
+ if (ip_str == mp_const_none) {
+ ip_str = common_hal_socketpool_socketpool_gethostbyname(self, host);
+ }
+
+ if (ip_str == mp_const_none) {
+ mp_raise_OSError(-2); // socket.EAI_NONAME from CPython
+ }
+
+ mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_AF_INET);
+ tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_SOCK_STREAM);
+ tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ mp_obj_tuple_t *sockaddr = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
+ sockaddr->items[0] = ip_str;
+ sockaddr->items[1] = MP_OBJ_NEW_SMALL_INT(port);
+ tuple->items[4] = MP_OBJ_FROM_PTR(sockaddr);
+ return mp_obj_new_list(1, (mp_obj_t *)&tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_getaddrinfo_obj, 1, socketpool_socketpool_getaddrinfo);
+
+STATIC const mp_rom_map_elem_t socketpool_socketpool_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socketpool_socketpool_socket_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&socketpool_socketpool_getaddrinfo_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(SOCKETPOOL_AF_INET) },
+ { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(SOCKETPOOL_AF_INET6) },
+
+ { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCKETPOOL_SOCK_STREAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCKETPOOL_SOCK_DGRAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCKETPOOL_SOCK_RAW) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(socketpool_socketpool_locals_dict, socketpool_socketpool_locals_dict_table);
+
+const mp_obj_type_t socketpool_socketpool_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SocketPool,
+ .make_new = socketpool_socketpool_make_new,
+ .locals_dict = (mp_obj_dict_t *)&socketpool_socketpool_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/socketpool/SocketPool.h b/circuitpython/shared-bindings/socketpool/SocketPool.h
new file mode 100644
index 0000000..10a943d
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/SocketPool.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKETPOOL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKETPOOL_H
+
+#include "common-hal/socketpool/SocketPool.h"
+
+#include "shared-bindings/socketpool/Socket.h"
+
+extern const mp_obj_type_t socketpool_socketpool_type;
+
+typedef enum {
+ SOCKETPOOL_SOCK_STREAM,
+ SOCKETPOOL_SOCK_DGRAM,
+ SOCKETPOOL_SOCK_RAW
+} socketpool_socketpool_sock_t;
+
+typedef enum {
+ SOCKETPOOL_AF_INET,
+ SOCKETPOOL_AF_INET6
+} socketpool_socketpool_addressfamily_t;
+
+void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *self, mp_obj_t radio);
+
+socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
+ socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type);
+
+mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
+ const char *host);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL_SOCKETPOOL_H
diff --git a/circuitpython/shared-bindings/socketpool/__init__.c b/circuitpython/shared-bindings/socketpool/__init__.c
new file mode 100644
index 0000000..fee81f2
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/__init__.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objexcept.h"
+#include "py/objstr.h"
+#include "py/parsenum.h"
+#include "py/runtime.h"
+#include "shared-bindings/socketpool/__init__.h"
+#include "shared-bindings/socketpool/Socket.h"
+#include "shared-bindings/socketpool/SocketPool.h"
+
+//| """
+//| The `socketpool` module provides sockets through a pool. The pools themselves
+//| act like CPython's `socket` module.
+//|
+//| For more information about the `socket` module, see the CPython documentation:
+//| https://docs.python.org/3/library/socket.html
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t socketpool_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_socketpool) },
+
+ { MP_ROM_QSTR(MP_QSTR_SocketPool), MP_ROM_PTR(&socketpool_socketpool_type) },
+ { MP_ROM_QSTR(MP_QSTR_Socket), MP_ROM_PTR(&socketpool_socket_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(socketpool_globals, socketpool_globals_table);
+
+const mp_obj_module_t socketpool_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&socketpool_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_socketpool, socketpool_module, CIRCUITPY_SOCKETPOOL);
diff --git a/circuitpython/shared-bindings/socketpool/__init__.h b/circuitpython/shared-bindings/socketpool/__init__.h
new file mode 100644
index 0000000..a017e96
--- /dev/null
+++ b/circuitpython/shared-bindings/socketpool/__init__.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL___INIT___H
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SOCKETPOOL___INIT___H
diff --git a/circuitpython/shared-bindings/ssl/SSLContext.c b/circuitpython/shared-bindings/ssl/SSLContext.c
new file mode 100644
index 0000000..5dfa5e5
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/SSLContext.c
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+
+#include "shared-bindings/ssl/SSLContext.h"
+
+//| class SSLContext:
+//| """Settings related to SSL that can be applied to a socket by wrapping it.
+//| This is useful to provide SSL certificates to specific connections
+//| rather than all of them."""
+//|
+
+STATIC mp_obj_t ssl_sslcontext_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+ ssl_sslcontext_obj_t *s = m_new_obj(ssl_sslcontext_obj_t);
+ s->base.type = &ssl_sslcontext_type;
+
+ common_hal_ssl_sslcontext_construct(s);
+
+ return MP_OBJ_FROM_PTR(s);
+}
+
+//| def load_verify_locations(self, cadata: Optional[str] = None) -> None:
+//| """Load a set of certification authority (CA) certificates used to validate
+//| other peers' certificates."""
+//|
+
+STATIC mp_obj_t ssl_sslcontext_load_verify_locations(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_cadata };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_cadata, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ ssl_sslcontext_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *cadata = mp_obj_str_get_str(args[ARG_cadata].u_obj);
+
+ common_hal_ssl_sslcontext_load_verify_locations(self, cadata);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_sslcontext_load_verify_locations_obj, 1, ssl_sslcontext_load_verify_locations);
+
+//| def set_default_verify_paths(self) -> None:
+//| """Load a set of default certification authority (CA) certificates."""
+//|
+
+STATIC mp_obj_t ssl_sslcontext_set_default_verify_paths(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ ssl_sslcontext_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ common_hal_ssl_sslcontext_set_default_verify_paths(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_sslcontext_set_default_verify_paths_obj, 1, ssl_sslcontext_set_default_verify_paths);
+
+//| check_hostname: bool
+//| """Whether to match the peer certificate's hostname."""
+//|
+
+STATIC mp_obj_t ssl_sslcontext_get_check_hostname(mp_obj_t self_in) {
+ ssl_sslcontext_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_ssl_sslcontext_get_check_hostname(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_sslcontext_get_check_hostname_obj, ssl_sslcontext_get_check_hostname);
+
+STATIC mp_obj_t ssl_sslcontext_set_check_hostname(mp_obj_t self_in, mp_obj_t value) {
+ ssl_sslcontext_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_ssl_sslcontext_set_check_hostname(self, mp_obj_is_true(value));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslcontext_set_check_hostname_obj, ssl_sslcontext_set_check_hostname);
+
+MP_PROPERTY_GETSET(ssl_sslcontext_check_hostname_obj,
+ (mp_obj_t)&ssl_sslcontext_get_check_hostname_obj,
+ (mp_obj_t)&ssl_sslcontext_set_check_hostname_obj);
+
+//| def wrap_socket(self, sock: socketpool.Socket, *, server_side: bool = False, server_hostname: Optional[str] = None) -> ssl.SSLSocket:
+//| """Wraps the socket into a socket-compatible class that handles SSL negotiation.
+//| The socket must be of type SOCK_STREAM."""
+//|
+
+STATIC mp_obj_t ssl_sslcontext_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sock, ARG_server_side, ARG_server_hostname };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sock, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ ssl_sslcontext_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *server_hostname = NULL;
+ if (args[ARG_server_hostname].u_obj != mp_const_none) {
+ server_hostname = mp_obj_str_get_str(args[ARG_server_hostname].u_obj);
+ }
+ bool server_side = args[ARG_server_side].u_bool;
+ if (server_side && server_hostname != NULL) {
+ mp_raise_ValueError(translate("Server side context cannot have hostname"));
+ }
+
+ socketpool_socket_obj_t *sock = args[ARG_sock].u_obj;
+
+ return common_hal_ssl_sslcontext_wrap_socket(self, sock, server_side, server_hostname);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_sslcontext_wrap_socket_obj, 1, ssl_sslcontext_wrap_socket);
+
+STATIC const mp_rom_map_elem_t ssl_sslcontext_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&ssl_sslcontext_wrap_socket_obj) },
+ { MP_ROM_QSTR(MP_QSTR_load_verify_locations), MP_ROM_PTR(&ssl_sslcontext_load_verify_locations_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_default_verify_paths), MP_ROM_PTR(&ssl_sslcontext_set_default_verify_paths_obj) },
+ { MP_ROM_QSTR(MP_QSTR_check_hostname), MP_ROM_PTR(&ssl_sslcontext_check_hostname_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ssl_sslcontext_locals_dict, ssl_sslcontext_locals_dict_table);
+
+const mp_obj_type_t ssl_sslcontext_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SSLContext,
+ .make_new = ssl_sslcontext_make_new,
+ .locals_dict = (mp_obj_dict_t *)&ssl_sslcontext_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/ssl/SSLContext.h b/circuitpython/shared-bindings/ssl/SSLContext.h
new file mode 100644
index 0000000..ef04f25
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/SSLContext.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLCONTEXT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLCONTEXT_H
+
+#include "common-hal/ssl/SSLContext.h"
+
+#include "shared-bindings/socketpool/Socket.h"
+#include "shared-bindings/ssl/SSLSocket.h"
+
+extern const mp_obj_type_t ssl_sslcontext_type;
+
+void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t *self);
+
+ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t *self,
+ socketpool_socket_obj_t *sock, bool server_side, const char *server_hostname);
+
+void common_hal_ssl_sslcontext_load_verify_locations(ssl_sslcontext_obj_t *self,
+ const char *cadata);
+
+void common_hal_ssl_sslcontext_set_default_verify_paths(ssl_sslcontext_obj_t *self);
+
+bool common_hal_ssl_sslcontext_get_check_hostname(ssl_sslcontext_obj_t *self);
+void common_hal_ssl_sslcontext_set_check_hostname(ssl_sslcontext_obj_t *self, bool value);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLCONTEXT_H
diff --git a/circuitpython/shared-bindings/ssl/SSLSocket.c b/circuitpython/shared-bindings/ssl/SSLSocket.c
new file mode 100644
index 0000000..630ab28
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/SSLSocket.c
@@ -0,0 +1,318 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Lucian Copeland for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/ssl/SSLSocket.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+
+#include "shared/netutils/netutils.h"
+
+//| class SSLSocket:
+//| """Implements TLS security on a subset of `socketpool.Socket` functions. Cannot be created
+//| directly. Instead, call `wrap_socket` on an existing socket object.
+//|
+//| Provides a subset of CPython's `ssl.SSLSocket` API. It only implements the versions of
+//| recv that do not allocate bytes objects."""
+//|
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the Socket."""
+//| ...
+//|
+// Provided by mp_generic_unary_op().
+
+//| def __enter__(self) -> SSLSocket:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically closes the Socket when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_ssl_sslsocket_close(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ssl_sslsocket___exit___obj, 4, 4, ssl_sslsocket___exit__);
+
+//| def accept(self) -> Tuple[SSLSocket, Tuple[str, int]]:
+//| """Accept a connection on a listening socket of type SOCK_STREAM,
+//| creating a new socket of type SOCK_STREAM.
+//| Returns a tuple of (new_socket, remote_address)"""
+//|
+STATIC mp_obj_t ssl_sslsocket_accept(mp_obj_t self_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint8_t ip[4];
+ uint32_t port;
+
+ ssl_sslsocket_obj_t *sslsock = common_hal_ssl_sslsocket_accept(self, ip, &port);
+
+ mp_obj_t tuple_contents[2];
+ tuple_contents[0] = MP_OBJ_FROM_PTR(sslsock);
+ tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+ return mp_obj_new_tuple(2, tuple_contents);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_sslsocket_accept_obj, ssl_sslsocket_accept);
+
+//| def bind(self, address: Tuple[str, int]) -> None:
+//| """Bind a socket to an address
+//|
+//| :param ~tuple address: tuple of (remote_address, remote_port)"""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+
+ size_t hostlen;
+ const char *host = mp_obj_str_get_data(addr_items[0], &hostlen);
+ mp_int_t port = mp_obj_get_int(addr_items[1]);
+ if (port < 0) {
+ mp_raise_ValueError(translate("port must be >= 0"));
+ }
+
+ bool ok = common_hal_ssl_sslsocket_bind(self, host, hostlen, (uint32_t)port);
+ if (!ok) {
+ mp_raise_ValueError(translate("Error: Failure to bind"));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_bind_obj, ssl_sslsocket_bind);
+
+//| def close(self) -> None:
+//| """Closes this Socket"""
+//|
+STATIC mp_obj_t ssl_sslsocket_close(mp_obj_t self_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_ssl_sslsocket_close(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_sslsocket_close_obj, ssl_sslsocket_close);
+
+//| def connect(self, address: Tuple[str, int]) -> None:
+//| """Connect a socket to a remote address
+//|
+//| :param ~tuple address: tuple of (remote_address, remote_port)"""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+
+ size_t hostlen;
+ const char *host = mp_obj_str_get_data(addr_items[0], &hostlen);
+ mp_int_t port = mp_obj_get_int(addr_items[1]);
+ if (port < 0) {
+ mp_raise_ValueError(translate("port must be >= 0"));
+ }
+
+ common_hal_ssl_sslsocket_connect(self, host, hostlen, (uint32_t)port);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_connect_obj, ssl_sslsocket_connect);
+
+//| def listen(self, backlog: int) -> None:
+//| """Set socket to listen for incoming connections
+//|
+//| :param ~int backlog: length of backlog queue for waiting connetions"""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ int backlog = mp_obj_get_int(backlog_in);
+
+ common_hal_ssl_sslsocket_listen(self, backlog);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_listen_obj, ssl_sslsocket_listen);
+
+//| def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int:
+//| """Reads some bytes from the connected remote address, writing
+//| into the provided buffer. If bufsize <= len(buffer) is given,
+//| a maximum of bufsize bytes will be read into the buffer. If no
+//| valid value is given for bufsize, the default is the length of
+//| the given buffer.
+//|
+//| Suits sockets of type SOCK_STREAM
+//| Returns an int of number of bytes read.
+//|
+//| :param bytearray buffer: buffer to receive into
+//| :param int bufsize: optionally, a maximum number of bytes to read."""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_recv_into(size_t n_args, const mp_obj_t *args) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (common_hal_ssl_sslsocket_get_closed(self)) {
+ // Bad file number.
+ mp_raise_OSError(MP_EBADF);
+ }
+ // if (!common_hal_ssl_sslsocket_get_connected(self)) {
+ // // not connected
+ // mp_raise_OSError(MP_ENOTCONN);
+ // }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ mp_int_t len = bufinfo.len;
+ if (n_args == 3) {
+ mp_int_t given_len = mp_obj_get_int(args[2]);
+ if (given_len > len) {
+ mp_raise_ValueError(translate("buffer too small for requested bytes"));
+ }
+ if (given_len > 0 && given_len < len) {
+ len = given_len;
+ }
+ }
+
+ if (len == 0) {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+
+ mp_int_t ret = common_hal_ssl_sslsocket_recv_into(self, (byte *)bufinfo.buf, len);
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ssl_sslsocket_recv_into_obj, 2, 3, ssl_sslsocket_recv_into);
+
+//| def send(self, bytes: ReadableBuffer) -> int:
+//| """Send some bytes to the connected remote address.
+//| Suits sockets of type SOCK_STREAM
+//|
+//| :param ~bytes bytes: some bytes to send"""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (common_hal_ssl_sslsocket_get_closed(self)) {
+ // Bad file number.
+ mp_raise_OSError(MP_EBADF);
+ }
+ if (!common_hal_ssl_sslsocket_get_connected(self)) {
+ mp_raise_BrokenPipeError();
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ mp_int_t ret = common_hal_ssl_sslsocket_send(self, bufinfo.buf, bufinfo.len);
+ if (ret == -1) {
+ mp_raise_BrokenPipeError();
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_send_obj, ssl_sslsocket_send);
+
+// //| def setsockopt(self, level: int, optname: int, value: int) -> None:
+// //| """Sets socket options"""
+// //| ...
+// //|
+// STATIC mp_obj_t ssl_sslsocket_setsockopt(size_t n_args, const mp_obj_t *args) {
+// }
+// STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ssl_sslsocket_setsockopt_obj, 4, 4, ssl_sslsocket_setsockopt);
+
+//| def settimeout(self, value: int) -> None:
+//| """Set the timeout value for this socket.
+//|
+//| :param ~int value: timeout in seconds. 0 means non-blocking. None means block indefinitely."""
+//| ...
+//|
+STATIC mp_obj_t ssl_sslsocket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t timeout_ms;
+ if (timeout_in == mp_const_none) {
+ timeout_ms = -1;
+ } else {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ timeout_ms = 1000 * mp_obj_get_float(timeout_in);
+ #else
+ timeout_ms = 1000 * mp_obj_get_int(timeout_in);
+ #endif
+ }
+ common_hal_ssl_sslsocket_settimeout(self, timeout_ms);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_settimeout_obj, ssl_sslsocket_settimeout);
+
+//| def setblocking(self, flag: bool) -> Optional[int]:
+//| """Set the blocking behaviour of this socket.
+//|
+//| :param ~bool flag: False means non-blocking, True means block indefinitely."""
+//| ...
+//|
+// method socket.setblocking(flag)
+STATIC mp_obj_t ssl_sslsocket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (mp_obj_is_true(blocking)) {
+ common_hal_ssl_sslsocket_settimeout(self, -1);
+ } else {
+ common_hal_ssl_sslsocket_settimeout(self, 0);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_setblocking_obj, ssl_sslsocket_setblocking);
+
+STATIC const mp_rom_map_elem_t ssl_sslsocket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&ssl_sslsocket___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ssl_sslsocket_close_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&ssl_sslsocket_accept_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&ssl_sslsocket_bind_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&ssl_sslsocket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ssl_sslsocket_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&ssl_sslsocket_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&ssl_sslsocket_recv_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&ssl_sslsocket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ssl_sslsocket_setblocking_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&ssl_sslsocket_setsockopt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&ssl_sslsocket_settimeout_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ssl_sslsocket_locals_dict, ssl_sslsocket_locals_dict_table);
+
+const mp_obj_type_t ssl_sslsocket_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_SSLSocket,
+ .locals_dict = (mp_obj_dict_t *)&ssl_sslsocket_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_generic_unary_op,
+ )
+};
diff --git a/circuitpython/shared-bindings/ssl/SSLSocket.h b/circuitpython/shared-bindings/ssl/SSLSocket.h
new file mode 100644
index 0000000..d651934
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/SSLSocket.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Lucian Copeland for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLSOCKET_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLSOCKET_H
+
+#include "common-hal/ssl/SSLSocket.h"
+
+extern const mp_obj_type_t ssl_sslsocket_type;
+
+ssl_sslsocket_obj_t *common_hal_ssl_sslsocket_accept(ssl_sslsocket_obj_t *self, uint8_t *ip, uint32_t *port);
+bool common_hal_ssl_sslsocket_bind(ssl_sslsocket_obj_t *self, const char *host, size_t hostlen, uint32_t port);
+void common_hal_ssl_sslsocket_close(ssl_sslsocket_obj_t *self);
+void common_hal_ssl_sslsocket_connect(ssl_sslsocket_obj_t *self, const char *host, size_t hostlen, uint32_t port);
+bool common_hal_ssl_sslsocket_get_closed(ssl_sslsocket_obj_t *self);
+bool common_hal_ssl_sslsocket_get_connected(ssl_sslsocket_obj_t *self);
+bool common_hal_ssl_sslsocket_listen(ssl_sslsocket_obj_t *self, int backlog);
+mp_uint_t common_hal_ssl_sslsocket_recv_into(ssl_sslsocket_obj_t *self, const uint8_t *buf, uint32_t len);
+mp_uint_t common_hal_ssl_sslsocket_send(ssl_sslsocket_obj_t *self, const uint8_t *buf, uint32_t len);
+void common_hal_ssl_sslsocket_settimeout(ssl_sslsocket_obj_t *self, uint32_t timeout_ms);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SSL_SSLSOCKET_H
diff --git a/circuitpython/shared-bindings/ssl/__init__.c b/circuitpython/shared-bindings/ssl/__init__.c
new file mode 100644
index 0000000..6967860
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/__init__.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objexcept.h"
+#include "py/objstr.h"
+#include "py/parsenum.h"
+#include "py/runtime.h"
+#include "shared-bindings/ssl/__init__.h"
+#include "shared-bindings/ssl/SSLContext.h"
+
+//| """
+//| The `ssl` module provides SSL contexts to wrap sockets in.
+//|
+//| |see_cpython_module| :mod:`cpython:ssl`.
+//| """
+//|
+
+//| def create_default_context() -> ssl.SSLContext:
+//| """Return the default SSLContext."""
+//| ...
+//|
+
+STATIC mp_obj_t ssl_create_default_context(void) {
+ ssl_sslcontext_obj_t *s = m_new_obj(ssl_sslcontext_obj_t);
+ s->base.type = &ssl_sslcontext_type;
+
+ common_hal_ssl_create_default_context(s);
+ return s;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(ssl_create_default_context_obj, ssl_create_default_context);
+
+STATIC const mp_rom_map_elem_t ssl_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) },
+
+ { MP_ROM_QSTR(MP_QSTR_create_default_context), MP_ROM_PTR(&ssl_create_default_context_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_SSLContext), MP_ROM_PTR(&ssl_sslcontext_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ssl_globals, ssl_globals_table);
+
+const mp_obj_module_t ssl_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&ssl_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_ssl, ssl_module, CIRCUITPY_SSL);
diff --git a/circuitpython/shared-bindings/ssl/__init__.h b/circuitpython/shared-bindings/ssl/__init__.h
new file mode 100644
index 0000000..64f69c3
--- /dev/null
+++ b/circuitpython/shared-bindings/ssl/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SSL___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SSL___INIT___H
+
+#include "common-hal/ssl/SSLContext.h"
+
+void common_hal_ssl_create_default_context(ssl_sslcontext_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SSL___INIT___H
diff --git a/circuitpython/shared-bindings/storage/__init__.c b/circuitpython/shared-bindings/storage/__init__.c
new file mode 100644
index 0000000..277c834
--- /dev/null
+++ b/circuitpython/shared-bindings/storage/__init__.c
@@ -0,0 +1,283 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "extmod/vfs_fat.h"
+#include "py/obj.h"
+#include "py/objnamedtuple.h"
+#include "py/runtime.h"
+#include "shared-bindings/storage/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| """Storage management
+//|
+//| The `storage` provides storage management functionality such as mounting and
+//| unmounting which is typically handled by the operating system hosting Python.
+//| CircuitPython does not have an OS, so this module provides this functionality
+//| directly.
+
+//| For more information regarding using the `storage` module, refer to the `CircuitPython
+//| Essentials Learn guide
+//| <https://learn.adafruit.com/circuitpython-essentials/circuitpython-storage>`_.
+//| """
+//|
+
+//| def mount(filesystem: VfsFat, mount_path: str, *, readonly: bool = False) -> None:
+//| """Mounts the given filesystem object at the given path.
+//|
+//| This is the CircuitPython analog to the UNIX ``mount`` command.
+//|
+//| :param VfsFat filesystem: The filesystem to mount.
+//| :param str mount_path: Where to mount the filesystem.
+//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
+//| """
+//| ...
+//|
+STATIC mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_filesystem, ARG_mount_path, ARG_readonly };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_filesystem, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_mount_path, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get the mount point
+ const char *mnt_str = mp_obj_str_get_str(args[ARG_mount_path].u_obj);
+
+ // Make sure we're given an object we can mount.
+ // TODO(tannewt): Make sure we have all the methods we need to operating it
+ // as a file system.
+ mp_obj_t vfs_obj = args[ARG_filesystem].u_obj;
+ mp_obj_t dest[2];
+ mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest);
+ if (dest[0] == MP_OBJ_NULL) {
+ mp_raise_ValueError(translate("filesystem must provide mount method"));
+ }
+
+ common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(storage_mount_obj, 0, storage_mount);
+
+//| def umount(mount: Union[str, VfsFat]) -> None:
+//| """Unmounts the given filesystem object or if *mount* is a path, then unmount
+//| the filesystem mounted at that location.
+//|
+//| This is the CircuitPython analog to the UNIX ``umount`` command."""
+//| ...
+//|
+STATIC mp_obj_t storage_umount(mp_obj_t mnt_in) {
+ if (mp_obj_is_str(mnt_in)) {
+ common_hal_storage_umount_path(mp_obj_str_get_str(mnt_in));
+ } else {
+ common_hal_storage_umount_object(mnt_in);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(storage_umount_obj, storage_umount);
+
+//| def remount(mount_path: str, readonly: bool = False, *, disable_concurrent_write_protection: bool = False) -> None:
+//| """Remounts the given path with new parameters.
+//|
+//| :param str mount_path: The path to remount.
+//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
+//| :param bool disable_concurrent_write_protection: When True, the check that makes sure the
+//| underlying filesystem data is written by one computer is disabled. Disabling the protection
+//| allows CircuitPython and a host to write to the same filesystem with the risk that the
+//| filesystem will be corrupted."""
+//| ...
+//|
+STATIC mp_obj_t storage_remount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_mount_path, ARG_readonly, ARG_disable_concurrent_write_protection };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_mount_path, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_readonly, MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_disable_concurrent_write_protection, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const char *mnt_str = mp_obj_str_get_str(args[ARG_mount_path].u_obj);
+
+ common_hal_storage_remount(mnt_str, args[ARG_readonly].u_bool, args[ARG_disable_concurrent_write_protection].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(storage_remount_obj, 0, storage_remount);
+
+//| def getmount(mount_path: str) -> VfsFat:
+//| """Retrieves the mount object associated with the mount path"""
+//| ...
+//|
+STATIC mp_obj_t storage_getmount(const mp_obj_t mnt_in) {
+ return common_hal_storage_getmount(mp_obj_str_get_str(mnt_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(storage_getmount_obj, storage_getmount);
+
+//| def erase_filesystem() -> None:
+//| """Erase and re-create the ``CIRCUITPY`` filesystem.
+//|
+//| On boards that present USB-visible ``CIRCUITPY`` drive (e.g., SAMD21 and SAMD51),
+//| then call `microcontroller.reset()` to restart CircuitPython and have the
+//| host computer remount CIRCUITPY.
+//|
+//| This function can be called from the REPL when ``CIRCUITPY``
+//| has become corrupted.
+//|
+//| .. warning:: All the data on ``CIRCUITPY`` will be lost, and
+//| CircuitPython will restart on certain boards."""
+//| ...
+//|
+
+STATIC mp_obj_t storage_erase_filesystem(void) {
+ common_hal_storage_erase_filesystem();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(storage_erase_filesystem_obj, storage_erase_filesystem);
+
+//| def disable_usb_drive() -> None:
+//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device.
+//| By default, the device is enabled and ``CIRCUITPY`` is visible.
+//| Can be called in ``boot.py``, before USB is connected."""
+//| ...
+//|
+STATIC mp_obj_t storage_disable_usb_drive(void) {
+ #if CIRCUITPY_USB_MSC
+ if (!common_hal_storage_disable_usb_drive()) {
+ #else
+ if (true) {
+ #endif
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive);
+
+//| def enable_usb_drive() -> None:
+//| """Enabled presenting ``CIRCUITPY`` as a USB mass storage device.
+//| By default, the device is enabled and ``CIRCUITPY`` is visible,
+//| so you do not normally need to call this function.
+//| Can be called in ``boot.py``, before USB is connected.
+//|
+//| If you enable too many devices at once, you will run out of USB endpoints.
+//| The number of available endpoints varies by microcontroller.
+//| CircuitPython will go into safe mode after running boot.py to inform you if
+//| not enough endpoints are available.
+//| """
+//| ...
+//|
+STATIC mp_obj_t storage_enable_usb_drive(void) {
+ #if CIRCUITPY_USB_MSC
+ if (!common_hal_storage_enable_usb_drive()) {
+ #else
+ if (true) {
+ #endif
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(storage_enable_usb_drive_obj, storage_enable_usb_drive);
+
+STATIC const mp_rom_map_elem_t storage_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_storage) },
+
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getmount), MP_ROM_PTR(&storage_getmount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable_usb_drive), MP_ROM_PTR(&storage_disable_usb_drive_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_usb_drive), MP_ROM_PTR(&storage_enable_usb_drive_obj) },
+
+//| class VfsFat:
+//| def __init__(self, block_device: str) -> None:
+//| """Create a new VfsFat filesystem around the given block device.
+//|
+//| :param block_device: Block device the the filesystem lives on"""
+//|
+//| label: str
+//| """The filesystem label, up to 11 case-insensitive bytes. Note that
+//| this property can only be set when the device is writable by the
+//| microcontroller."""
+//| ...
+//|
+//| def mkfs(self) -> None:
+//| """Format the block device, deleting any data that may have been there"""
+//| ...
+//|
+//| def open(self, path: str, mode: str) -> None:
+//| """Like builtin ``open()``"""
+//| ...
+//|
+//| def ilistdir(self, path: str) -> Iterator[Union[Tuple[AnyStr, int, int, int], Tuple[AnyStr, int, int]]]:
+//| """Return an iterator whose values describe files and folders within
+//| ``path``"""
+//| ...
+//|
+//| def mkdir(self, path: str) -> None:
+//| """Like `os.mkdir`"""
+//| ...
+//|
+//| def rmdir(self, path: str) -> None:
+//| """Like `os.rmdir`"""
+//| ...
+//|
+//| def stat(self, path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+//| """Like `os.stat`"""
+//| ...
+//|
+//| def statvfs(self, path: int) -> Tuple[int, int, int, int, int, int, int, int, int, int]:
+//| """Like `os.statvfs`"""
+//| ...
+//|
+//| def mount(self, readonly: bool, mkfs: VfsFat) -> None:
+//| """Don't call this directly, call `storage.mount`."""
+//| ...
+//|
+//| def umount(self) -> None:
+//| """Don't call this directly, call `storage.umount`."""
+//| ...
+//|
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(storage_module_globals, storage_module_globals_table);
+
+const mp_obj_module_t storage_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&storage_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_storage, storage_module, CIRCUITPY_STORAGE);
diff --git a/circuitpython/shared-bindings/storage/__init__.h b/circuitpython/shared-bindings/storage/__init__.h
new file mode 100644
index 0000000..fbf492e
--- /dev/null
+++ b/circuitpython/shared-bindings/storage/__init__.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_STORAGE___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_STORAGE___INIT___H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "shared-module/storage/__init__.h"
+
+void common_hal_storage_mount(mp_obj_t vfs_obj, const char *path, bool readonly);
+void common_hal_storage_umount_path(const char *path);
+void common_hal_storage_umount_object(mp_obj_t vfs_obj);
+void common_hal_storage_remount(const char *path, bool readonly, bool disable_concurrent_write_protection);
+mp_obj_t common_hal_storage_getmount(const char *path);
+void common_hal_storage_erase_filesystem(void);
+
+bool common_hal_storage_disable_usb_drive(void);
+bool common_hal_storage_enable_usb_drive(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_STORAGE___INIT___H
diff --git a/circuitpython/shared-bindings/struct/__init__.c b/circuitpython/shared-bindings/struct/__init__.c
new file mode 100644
index 0000000..c29c33c
--- /dev/null
+++ b/circuitpython/shared-bindings/struct/__init__.c
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2017 Michael McWethy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/builtin.h"
+#include "py/objtuple.h"
+#include "py/binary.h"
+#include "py/parsenum.h"
+#include "shared-bindings/struct/__init__.h"
+#include "shared-module/struct/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| """Manipulation of c-style data
+//|
+//| |see_cpython_module| :mod:`cpython:struct`.
+//|
+//| Supported size/byte order prefixes: *@*, *<*, *>*, *!*.
+//|
+//| Supported format codes: *b*, *B*, *x*, *h*, *H*, *i*, *I*, *l*, *L*, *q*, *Q*,
+//| *s*, *P*, *f*, *d* (the latter 2 depending on the floating-point support)."""
+//|
+
+
+//| def calcsize(fmt: str) -> int:
+//| """Return the number of bytes needed to store the given fmt."""
+//| ...
+//|
+
+STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
+
+ return MP_OBJ_NEW_SMALL_INT(shared_modules_struct_calcsize(fmt_in));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize);
+
+//| def pack(fmt: str, *values: Any) -> bytes:
+//| """Pack the values according to the format string fmt.
+//| The return value is a bytes object encoding the values."""
+//| ...
+//|
+
+STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) {
+ mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
+ vstr_t vstr;
+ vstr_init_len(&vstr, size);
+ byte *p = (byte *)vstr.buf;
+ memset(p, 0, size);
+ byte *end_p = &p[size];
+ shared_modules_struct_pack_into(args[0], p, end_p, n_args - 1, &args[1]);
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);
+
+//| def pack_into(fmt: str, buffer: WriteableBuffer, offset: int, *values: Any) -> None:
+//| """Pack the values according to the format string fmt into a buffer
+//| starting at offset. offset may be negative to count from the end of buffer."""
+//| ...
+//|
+
+STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ mp_int_t offset = mp_obj_get_int(args[2]);
+ if (offset < 0) {
+ // negative offsets are relative to the end of the buffer
+ offset = (mp_int_t)bufinfo.len + offset;
+ if (offset < 0) {
+ mp_raise_RuntimeError(translate("buffer too small"));
+ }
+ }
+ byte *p = (byte *)bufinfo.buf;
+ byte *end_p = &p[bufinfo.len];
+ p += offset;
+
+ shared_modules_struct_pack_into(args[0], p, end_p, n_args - 3, &args[3]);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_into_obj, 3, MP_OBJ_FUN_ARGS_MAX, struct_pack_into);
+
+//| def unpack(fmt: str, data: ReadableBuffer) -> Tuple[Any, ...]:
+//| """Unpack from the data according to the format string fmt. The return value
+//| is a tuple of the unpacked values. The buffer size must match the size
+//| required by the format."""
+//| ...
+//|
+
+STATIC mp_obj_t struct_unpack(size_t n_args, const mp_obj_t *args) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
+ byte *p = bufinfo.buf;
+ byte *end_p = &p[bufinfo.len];
+
+ // true means check the size must be exactly right.
+ return MP_OBJ_FROM_PTR(shared_modules_struct_unpack_from(args[0], p, end_p, true));
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_unpack_obj, 2, 3, struct_unpack);
+
+//| def unpack_from(fmt: str, data: ReadableBuffer, offset: int = 0) -> Tuple[Any, ...]:
+//| """Unpack from the data starting at offset according to the format string fmt.
+//| offset may be negative to count from the end of buffer. The return value is
+//| a tuple of the unpacked values. The buffer size must be at least as big
+//| as the size required by the form."""
+//| ...
+//|
+
+STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_format, ARG_buffer, ARG_offset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_format, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_offset, MP_ARG_INT, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+ byte *p = bufinfo.buf;
+ byte *end_p = &p[bufinfo.len];
+
+ mp_int_t offset = args[ARG_offset].u_int;
+ if (offset < 0) {
+ // negative offsets are relative to the end of the buffer
+ offset = bufinfo.len + offset;
+ if (offset < 0) {
+ mp_raise_RuntimeError(translate("buffer too small"));
+ }
+ }
+ p += offset;
+
+ // false means the size doesn't have to be exact. struct.unpack_from() only requires
+ // that be buffer be big enough.
+ return MP_OBJ_FROM_PTR(shared_modules_struct_unpack_from(args[ARG_format].u_obj, p, end_p, false));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(struct_unpack_from_obj, 0, struct_unpack_from);
+
+STATIC const mp_rom_map_elem_t mp_module_struct_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_struct) },
+ { MP_ROM_QSTR(MP_QSTR_calcsize), MP_ROM_PTR(&struct_calcsize_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&struct_pack_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&struct_pack_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&struct_unpack_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unpack_from), MP_ROM_PTR(&struct_unpack_from_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_struct_globals, mp_module_struct_globals_table);
+
+const mp_obj_module_t struct_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_struct_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_struct, struct_module, CIRCUITPY_STRUCT);
diff --git a/circuitpython/shared-bindings/struct/__init__.h b/circuitpython/shared-bindings/struct/__init__.h
new file mode 100644
index 0000000..4c7c65d
--- /dev/null
+++ b/circuitpython/shared-bindings/struct/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_STRUCT___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_STRUCT___INIT___H
+
+void shared_modules_struct_pack_into(mp_obj_t fmt_in, byte *p, byte *end_p, size_t n_args, const mp_obj_t *args);
+mp_uint_t shared_modules_struct_calcsize(mp_obj_t fmt_in);
+mp_obj_tuple_t *shared_modules_struct_unpack_from(mp_obj_t fmt_in, byte *p, byte *end_p, bool exact_size);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_RANDOM___INIT___H
diff --git a/circuitpython/shared-bindings/supervisor/RunReason.c b/circuitpython/shared-bindings/supervisor/RunReason.c
new file mode 100644
index 0000000..a2a5fe1
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/RunReason.c
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/enum.h"
+
+#include "shared-bindings/supervisor/RunReason.h"
+
+MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, STARTUP, RUN_REASON_STARTUP);
+MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, AUTO_RELOAD, RUN_REASON_AUTO_RELOAD);
+MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, SUPERVISOR_RELOAD, RUN_REASON_SUPERVISOR_RELOAD);
+MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, REPL_RELOAD, RUN_REASON_REPL_RELOAD);
+
+//| class RunReason:
+//| """The reason that CircuitPython started running."""
+//|
+//| STARTUP: object
+//| """CircuitPython started the microcontroller started up. See `microcontroller.Processor.reset_reason`
+//| for more detail on why the microcontroller was started."""
+//|
+//| AUTO_RELOAD: object
+//| """CircuitPython restarted due to an external write to the filesystem."""
+//|
+//| SUPERVISOR_RELOAD: object
+//| """CircuitPython restarted due to a call to `supervisor.reload()`."""
+//|
+//| REPL_RELOAD: object
+//| """CircuitPython started due to the user typing CTRL-D in the REPL."""
+//|
+MAKE_ENUM_MAP(supervisor_run_reason) {
+ MAKE_ENUM_MAP_ENTRY(run_reason, STARTUP),
+ MAKE_ENUM_MAP_ENTRY(run_reason, AUTO_RELOAD),
+ MAKE_ENUM_MAP_ENTRY(run_reason, SUPERVISOR_RELOAD),
+ MAKE_ENUM_MAP_ENTRY(run_reason, REPL_RELOAD),
+};
+STATIC MP_DEFINE_CONST_DICT(supervisor_run_reason_locals_dict, supervisor_run_reason_locals_table);
+
+MAKE_PRINTER(supervisor, supervisor_run_reason);
+
+MAKE_ENUM_TYPE(supervisor, RunReason, supervisor_run_reason);
diff --git a/circuitpython/shared-bindings/supervisor/RunReason.h b/circuitpython/shared-bindings/supervisor/RunReason.h
new file mode 100644
index 0000000..391e6d3
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/RunReason.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+typedef enum {
+ RUN_REASON_STARTUP,
+ RUN_REASON_AUTO_RELOAD,
+ RUN_REASON_SUPERVISOR_RELOAD,
+ RUN_REASON_REPL_RELOAD,
+} supervisor_run_reason_t;
+
+extern const mp_obj_type_t supervisor_run_reason_type;
diff --git a/circuitpython/shared-bindings/supervisor/Runtime.c b/circuitpython/shared-bindings/supervisor/Runtime.c
new file mode 100644
index 0000000..55217ec
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/Runtime.c
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Michael Schroeder
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "py/obj.h"
+#include "py/enum.h"
+#include "py/runtime.h"
+#include "py/objproperty.h"
+
+#include "shared-bindings/supervisor/RunReason.h"
+#include "shared-bindings/supervisor/Runtime.h"
+
+#if (CIRCUITPY_USB)
+#include "tusb.h"
+#endif
+
+STATIC supervisor_run_reason_t _run_reason;
+
+// TODO: add REPL to description once it is operational
+
+//| class Runtime:
+//| """Current status of runtime objects.
+//|
+//| Usage::
+//|
+//| import supervisor
+//| if supervisor.runtime.serial_connected:
+//| print("Hello World!")"""
+//|
+
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `supervisor.Runtime`.
+//| Use `supervisor.runtime` to access the sole instance available."""
+//| ...
+//|
+
+//| usb_connected: bool
+//| """Returns the USB enumeration status (read-only)."""
+//|
+STATIC mp_obj_t supervisor_runtime_get_usb_connected(mp_obj_t self) {
+ #if CIRCUITPY_USB
+ return mp_obj_new_bool(tud_ready());
+ #else
+ return mp_const_false;
+ #endif
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_usb_connected_obj, supervisor_runtime_get_usb_connected);
+
+MP_PROPERTY_GETTER(supervisor_runtime_usb_connected_obj,
+ (mp_obj_t)&supervisor_runtime_get_usb_connected_obj);
+
+//| serial_connected: bool
+//| """Returns the USB serial communication status (read-only)."""
+//|
+STATIC mp_obj_t supervisor_runtime_get_serial_connected(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_supervisor_runtime_get_serial_connected());
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_serial_connected_obj, supervisor_runtime_get_serial_connected);
+
+MP_PROPERTY_GETTER(supervisor_runtime_serial_connected_obj,
+ (mp_obj_t)&supervisor_runtime_get_serial_connected_obj);
+
+//| serial_bytes_available: int
+//| """Returns the whether any bytes are available to read
+//| on the USB serial input. Allows for polling to see whether
+//| to call the built-in input() or wait. (read-only)"""
+//|
+STATIC mp_obj_t supervisor_runtime_get_serial_bytes_available(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_supervisor_runtime_get_serial_bytes_available());
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_serial_bytes_available_obj, supervisor_runtime_get_serial_bytes_available);
+
+MP_PROPERTY_GETTER(supervisor_runtime_serial_bytes_available_obj,
+ (mp_obj_t)&supervisor_runtime_get_serial_bytes_available_obj);
+
+supervisor_run_reason_t supervisor_get_run_reason(void) {
+ return _run_reason;
+}
+
+void supervisor_set_run_reason(supervisor_run_reason_t run_reason) {
+ _run_reason = run_reason;
+}
+
+//| run_reason: RunReason
+//| """Returns why CircuitPython started running this particular time."""
+//|
+STATIC mp_obj_t supervisor_runtime_get_run_reason(mp_obj_t self) {
+ return cp_enum_find(&supervisor_run_reason_type, _run_reason);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_run_reason_obj, supervisor_runtime_get_run_reason);
+
+MP_PROPERTY_GETTER(supervisor_runtime_run_reason_obj,
+ (mp_obj_t)&supervisor_runtime_get_run_reason_obj);
+
+STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_usb_connected), MP_ROM_PTR(&supervisor_runtime_usb_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_runtime_serial_bytes_available_obj) },
+ { MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_runtime_run_reason_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(supervisor_runtime_locals_dict, supervisor_runtime_locals_dict_table);
+
+const mp_obj_type_t supervisor_runtime_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Runtime,
+ .locals_dict = (mp_obj_dict_t *)&supervisor_runtime_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/supervisor/Runtime.h b/circuitpython/shared-bindings/supervisor/Runtime.h
new file mode 100644
index 0000000..debc5ec
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/Runtime.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Michael Schroeder
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RUNTIME_STATUS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_RUNTIME_STATUS_H
+
+#include <stdbool.h>
+#include "py/obj.h"
+
+#include "shared-bindings/supervisor/RunReason.h"
+
+extern const mp_obj_type_t supervisor_runtime_type;
+
+supervisor_run_reason_t supervisor_get_run_reason(void);
+void supervisor_set_run_reason(supervisor_run_reason_t run_reason);
+
+bool common_hal_supervisor_runtime_get_serial_connected(void);
+
+bool common_hal_supervisor_runtime_get_serial_bytes_available(void);
+
+// TODO: placeholders for future functions
+// bool common_hal_get_supervisor_runtime_repl_active(void);
+// bool common_hal_get_supervisor_runtime_usb_enumerated(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR_RUNTIME_H
diff --git a/circuitpython/shared-bindings/supervisor/__init__.c b/circuitpython/shared-bindings/supervisor/__init__.c
new file mode 100644
index 0000000..0b86b7b
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/__init__.c
@@ -0,0 +1,337 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/objstr.h"
+
+#include "shared/runtime/interrupt_char.h"
+#include "supervisor/shared/bluetooth/bluetooth.h"
+#include "supervisor/shared/display.h"
+#include "supervisor/shared/status_leds.h"
+#include "supervisor/shared/reload.h"
+#include "supervisor/shared/stack.h"
+#include "supervisor/shared/traceback.h"
+#include "supervisor/shared/translate.h"
+#include "supervisor/shared/workflow.h"
+
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/supervisor/__init__.h"
+#include "shared-bindings/time/__init__.h"
+#include "shared-bindings/supervisor/Runtime.h"
+
+//| """Supervisor settings"""
+//|
+
+//| runtime: Runtime
+//| """Runtime information, such as ``runtime.serial_connected``
+//| (USB serial connection status).
+//| This object is the sole instance of `supervisor.Runtime`."""
+//|
+
+//| def enable_autoreload() -> None:
+//| """Enable autoreload based on USB file write activity."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_enable_autoreload(void) {
+ autoreload_enable();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_enable_autoreload_obj, supervisor_enable_autoreload);
+
+//| def disable_autoreload() -> None:
+//| """Disable autoreload based on USB file write activity until
+//| `enable_autoreload` is called."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_disable_autoreload(void) {
+ autoreload_disable();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_disable_autoreload_obj, supervisor_disable_autoreload);
+
+//| def set_rgb_status_brightness(brightness: int) -> None:
+//| """Set brightness of status RGB LED from 0-255. This will take effect
+//| after the current code finishes and the status LED is used to show
+//| the finish state."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_set_rgb_status_brightness(mp_obj_t lvl) {
+ // This must be int. If cast to uint8_t first, will never raise a ValueError.
+ int brightness_int = mp_obj_get_int(lvl);
+ mp_arg_validate_int_range(brightness_int, 0, 255, MP_QSTR_brightness);
+ set_status_brightness((uint8_t)brightness_int);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_set_rgb_status_brightness);
+
+//| def reload() -> None:
+//| """Reload the main Python code and run it (equivalent to hitting Ctrl-D at the REPL)."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_reload(void) {
+ reload_initiate(RUN_REASON_SUPERVISOR_RELOAD);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload);
+
+//| def set_next_stack_limit(size: int) -> None:
+//| """Set the size of the stack for the next vm run. If its too large, the default will be used."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_set_next_stack_limit(mp_obj_t size_obj) {
+ mp_int_t size = mp_obj_get_int(size_obj);
+
+ if (size < 256) {
+ mp_raise_ValueError(translate("Stack size must be at least 256"));
+ }
+ set_next_stack_size(size);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_next_stack_limit_obj, supervisor_set_next_stack_limit);
+
+//| def set_next_code_file(filename: Optional[str], *, reload_on_success : bool = False, reload_on_error: bool = False, sticky_on_success: bool = False, sticky_on_error: bool = False, sticky_on_reload: bool = False) -> None:
+//| """Set what file to run on the next vm run.
+//|
+//| When not ``None``, the given ``filename`` is inserted at the front of the usual ['code.py',
+//| 'main.py'] search sequence.
+//|
+//| The optional keyword arguments specify what happens after the specified file has run:
+//|
+//| ``sticky_on_…`` determine whether the newly set filename and options stay in effect: If
+//| True, further runs will continue to run that file (unless it says otherwise by calling
+//| ``set_next_code_filename()`` itself). If False, the settings will only affect one run and
+//| revert to the standard code.py/main.py afterwards.
+//|
+//| ``reload_on_…`` determine how to continue: If False, wait in the usual "Code done running.
+//| Waiting for reload. / Press any key to enter the REPL. Use CTRL-D to reload." state. If
+//| True, reload immediately as if CTRL-D was pressed.
+//|
+//| ``…_on_success`` take effect when the program runs to completion or calls ``sys.exit()``.
+//|
+//| ``…_on_error`` take effect when the program exits with an exception, including the
+//| KeyboardInterrupt caused by CTRL-C.
+//|
+//| ``…_on_reload`` take effect when the program is interrupted by files being written to the USB
+//| drive (auto-reload) or when it calls ``supervisor.reload()``.
+//|
+//| These settings are stored in RAM, not in persistent memory, and will therefore only affect
+//| soft reloads. Powering off or resetting the device will always revert to standard settings.
+//|
+//| When called multiple times in the same run, only the last call takes effect, replacing any
+//| settings made by previous ones. This is the main use of passing ``None`` as a filename: to
+//| reset to the standard search sequence."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_filename, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
+ { MP_QSTR_reload_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_reload_on_error, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_sticky_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_sticky_on_error, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_sticky_on_reload, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ };
+ struct {
+ mp_arg_val_t filename;
+ mp_arg_val_t reload_on_success;
+ mp_arg_val_t reload_on_error;
+ mp_arg_val_t sticky_on_success;
+ mp_arg_val_t sticky_on_error;
+ mp_arg_val_t sticky_on_reload;
+ } args;
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
+ if (!mp_obj_is_str_or_bytes(args.filename.u_obj) && args.filename.u_obj != mp_const_none) {
+ mp_raise_TypeError(translate("argument has wrong type"));
+ }
+ if (args.filename.u_obj == mp_const_none) {
+ args.filename.u_obj = mp_const_empty_bytes;
+ }
+ uint8_t options = 0;
+ if (args.reload_on_success.u_bool) {
+ options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS;
+ }
+ if (args.reload_on_error.u_bool) {
+ options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_ERROR;
+ }
+ if (args.sticky_on_success.u_bool) {
+ options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
+ }
+ if (args.sticky_on_error.u_bool) {
+ options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR;
+ }
+ if (args.sticky_on_reload.u_bool) {
+ options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
+ }
+ size_t len;
+ const char *filename = mp_obj_str_get_data(args.filename.u_obj, &len);
+ free_memory(next_code_allocation);
+ if (options != 0 || len != 0) {
+ next_code_allocation = allocate_memory(align32_size(sizeof(next_code_info_t) + len + 1), false, true);
+ if (next_code_allocation == NULL) {
+ m_malloc_fail(sizeof(next_code_info_t) + len + 1);
+ }
+ next_code_info_t *next_code = (next_code_info_t *)next_code_allocation->ptr;
+ next_code->options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
+ memcpy(&next_code->filename, filename, len);
+ next_code->filename[len] = '\0';
+ } else {
+ next_code_allocation = NULL;
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_next_code_file_obj, 0, supervisor_set_next_code_file);
+
+//| def ticks_ms() -> int:
+//| """Return the time in milliseconds since an unspecified reference point, wrapping after 2**29ms.
+//|
+//| The value is initialized so that the first overflow occurs about 65
+//| seconds after power-on, making it feasible to check that your program
+//| works properly around an overflow.
+//|
+//| The wrap value was chosen so that it is always possible to add
+//| or subtract two `ticks_ms` values without overflow on a board without
+//| long ints (or without allocating any long integer objects, on boards with
+//| long ints).
+//|
+//| This ticks value comes from a low-accuracy clock internal to the
+//| microcontroller, just like `time.monotonic`. Due to its low accuracy
+//| and the fact that it "wraps around" every few days, it is intended
+//| for working with short term events like advancing an LED animation,
+//| not for long term events like counting down the time until a holiday.
+//|
+//| Addition, subtraction, and comparison of ticks values can be done
+//| with routines like the following::
+//|
+//| _TICKS_PERIOD = const(1<<29)
+//| _TICKS_MAX = const(_TICKS_PERIOD-1)
+//| _TICKS_HALFPERIOD = const(_TICKS_PERIOD//2)
+//|
+//| def ticks_add(ticks, delta):
+//| "Add a delta to a base number of ticks, performing wraparound at 2**29ms."
+//| return (a + b) % _TICKS_PERIOD
+//|
+//| def ticks_diff(ticks1, ticks2):
+//| "Compute the signed difference between two ticks values, assuming that they are within 2**28 ticks"
+//| diff = (ticks1 - ticks2) & _TICKS_MAX
+//| diff = ((diff + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD
+//| return diff
+//|
+//| def ticks_less(ticks1, ticks2):
+//| "Return true iff ticks1 is less than ticks2, assuming that they are within 2**28 ticks"
+//| return ticks_diff(ticks1, ticks2) < 0
+//|
+//| """
+//| ...
+mp_obj_t supervisor_ticks_ms(void) {
+ uint64_t ticks_ms = common_hal_time_monotonic_ms();
+ return mp_obj_new_int((ticks_ms + 0x1fff0000) % (1 << 29));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_ticks_ms_obj, supervisor_ticks_ms);
+
+//| def get_previous_traceback() -> Optional[str]:
+//| """If the last vm run ended with an exception (including the KeyboardInterrupt caused by
+//| CTRL-C), returns the traceback as a string.
+//| Otherwise, returns ``None``.
+//|
+//| An exception traceback is only preserved over a soft reload, a hard reset clears it.
+//|
+//| Only code (main or boot) runs are considered, not REPL runs."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_get_previous_traceback(void) {
+ if (prev_traceback_allocation) {
+ size_t len = strlen((const char *)prev_traceback_allocation->ptr);
+ if (len > 0) {
+ mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
+ o->base.type = &mp_type_str;
+ o->len = len;
+ // callers probably aren't going to compare this string, so skip computing the hash
+ o->hash = 0;
+ o->data = (const byte *)prev_traceback_allocation->ptr;
+ return MP_OBJ_FROM_PTR(o);
+ }
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_get_previous_traceback_obj, supervisor_get_previous_traceback);
+
+//| def disable_ble_workflow() -> None:
+//| """Disable ble workflow until a reset. This prevents BLE advertising outside of the VM and
+//| the services used for it."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_disable_ble_workflow(void) {
+ #if !CIRCUITPY_BLE_FILE_SERVICE && !CIRCUITPY_SERIAL_BLE
+ mp_raise_NotImplementedError(NULL);
+ #else
+ supervisor_bluetooth_disable_workflow();
+ #endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(supervisor_disable_ble_workflow_obj, supervisor_disable_ble_workflow);
+
+//| def reset_terminal(x_pixels: int, y_pixels: int) -> None:
+//| """Reset the CircuitPython serial terminal with new dimensions."""
+//| ...
+//|
+STATIC mp_obj_t supervisor_reset_terminal(mp_obj_t x_pixels, mp_obj_t y_pixels) {
+ #if CIRCUITPY_DISPLAYIO
+ supervisor_stop_terminal();
+ supervisor_start_terminal(mp_obj_get_int(x_pixels), mp_obj_get_int(y_pixels));
+ #else
+ mp_raise_NotImplementedError(NULL);
+ #endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(supervisor_reset_terminal_obj, supervisor_reset_terminal);
+
+STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
+ { MP_ROM_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable_autoreload), MP_ROM_PTR(&supervisor_disable_autoreload_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_rgb_status_brightness), MP_ROM_PTR(&supervisor_set_rgb_status_brightness_obj) },
+ { MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) },
+ { MP_ROM_QSTR(MP_QSTR_RunReason), MP_ROM_PTR(&supervisor_run_reason_type) },
+ { MP_ROM_QSTR(MP_QSTR_set_next_stack_limit), MP_ROM_PTR(&supervisor_set_next_stack_limit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&supervisor_ticks_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable_ble_workflow), MP_ROM_PTR(&supervisor_disable_ble_workflow_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset_terminal), MP_ROM_PTR(&supervisor_reset_terminal_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(supervisor_module_globals, supervisor_module_globals_table);
+
+const mp_obj_module_t supervisor_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&supervisor_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_supervisor, supervisor_module, CIRCUITPY_SUPERVISOR);
diff --git a/circuitpython/shared-bindings/supervisor/__init__.h b/circuitpython/shared-bindings/supervisor/__init__.h
new file mode 100644
index 0000000..40a1e73
--- /dev/null
+++ b/circuitpython/shared-bindings/supervisor/__init__.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Michael Schroeder
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR___INIT___H
+
+// #include "py/mpconfig.h"
+#include "py/obj.h"
+
+#include "common-hal/supervisor/Runtime.h"
+
+extern const super_runtime_obj_t common_hal_supervisor_runtime_obj;
+extern mp_obj_t supervisor_ticks_ms(void);
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SUPERVISOR___INIT___H
diff --git a/circuitpython/shared-bindings/support_matrix.rst b/circuitpython/shared-bindings/support_matrix.rst
new file mode 100644
index 0000000..e007e27
--- /dev/null
+++ b/circuitpython/shared-bindings/support_matrix.rst
@@ -0,0 +1,34 @@
+.. _module-support-matrix:
+
+Module Support Matrix - Which Modules Are Available on Which Boards
+===================================================================
+
+The following table lists the available built-in modules for each CircuitPython
+capable board, as well as each :term:`frozen module` included on it.
+
+.. raw:: html
+
+ <p id="support-matrix-filter-block"><input placeholder="Filter the boards by available modules" id="support-matrix-filter" type="text"/><span id="support-matrix-filter-num">(all)</span></p>
+
+.. rst-class:: support-matrix-table
+.. list-table::
+ :header-rows: 1
+ :widths: 7, 50
+
+ * - Board
+ - Modules Available
+
+ {% for key, value in support_matrix|dictsort %}
+ {{ '.. _' ~ key|replace(" ", "-") ~ ':' }}
+ * - {{ key }}
+ - {{ ':py:mod:`' ~ value[0]|join("`, :py:mod:`") ~ '`' }}
+
+ {% for module in value[1] %}\
+ {% if loop.index == 1 %}**Frozen Modules:** {% endif %}\
+ {% if loop.index > 1 %}, {% endif %}\
+ {% if module[1] %}{{ '`' ~ module[0] ~ ' <' ~ module[1] ~ '>`__' }}\
+ {% else %}{{ '`' ~ module[0] ~ ' <#>`__' }}\
+ {% endif %}\
+ {% endfor %}
+
+ {% endfor %}
diff --git a/circuitpython/shared-bindings/synthio/MidiTrack.c b/circuitpython/shared-bindings/synthio/MidiTrack.c
new file mode 100644
index 0000000..7805c1a
--- /dev/null
+++ b/circuitpython/shared-bindings/synthio/MidiTrack.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Artyom Skrobov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/util.h"
+#include "shared-bindings/synthio/MidiTrack.h"
+#include "supervisor/shared/translate.h"
+
+//| class MidiTrack:
+//| """Simple square-wave MIDI synth"""
+//|
+//| def __init__(self, buffer: ReadableBuffer, tempo: int, *, sample_rate: int = 11025) -> None:
+//| """Create a MidiTrack from the given stream of MIDI events. Only "Note On" and "Note Off" events
+//| are supported; channel numbers and key velocities are ignored. Up to two notes may be on at the
+//| same time.
+//|
+//| :param ~circuitpython_typing.ReadableBuffer buffer: Stream of MIDI events, as stored in a MIDI file track chunk
+//| :param int tempo: Tempo of the streamed events, in MIDI ticks per second
+//| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory
+//|
+//| Simple melody::
+//|
+//| import audioio
+//| import board
+//| import synthio
+//|
+//| dac = audioio.AudioOut(board.SPEAKER)
+//| melody = synthio.MidiTrack(b"\\0\\x90H\\0*\\x80H\\0\\6\\x90J\\0*\\x80J\\0\\6\\x90L\\0*\\x80L\\0\\6\\x90J\\0" +
+//| b"*\\x80J\\0\\6\\x90H\\0*\\x80H\\0\\6\\x90J\\0*\\x80J\\0\\6\\x90L\\0T\\x80L\\0" +
+//| b"\\x0c\\x90H\\0T\\x80H\\0\\x0c\\x90H\\0T\\x80H\\0", tempo=640)
+//| dac.play(melody)
+//| print("playing")
+//| while dac.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t synthio_miditrack_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_buffer, ARG_tempo, ARG_sample_rate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_tempo, MP_ARG_INT | MP_ARG_REQUIRED },
+ { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ synthio_miditrack_obj_t *self = m_new_obj(synthio_miditrack_obj_t);
+ self->base.type = &synthio_miditrack_type;
+
+ common_hal_synthio_miditrack_construct(self,
+ (uint8_t *)bufinfo.buf, bufinfo.len,
+ args[ARG_tempo].u_int,
+ args[ARG_sample_rate].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the MidiTrack and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t synthio_miditrack_deinit(mp_obj_t self_in) {
+ synthio_miditrack_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_synthio_miditrack_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(synthio_miditrack_deinit_obj, synthio_miditrack_deinit);
+
+STATIC void check_for_deinit(synthio_miditrack_obj_t *self) {
+ if (common_hal_synthio_miditrack_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> MidiTrack:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t synthio_miditrack_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_synthio_miditrack_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(synthio_miditrack___exit___obj, 4, 4, synthio_miditrack_obj___exit__);
+
+//| sample_rate: Optional[int]
+//| """32 bit value that tells how quickly samples are played in Hertz (cycles per second)."""
+//|
+STATIC mp_obj_t synthio_miditrack_obj_get_sample_rate(mp_obj_t self_in) {
+ synthio_miditrack_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_synthio_miditrack_get_sample_rate(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(synthio_miditrack_get_sample_rate_obj, synthio_miditrack_obj_get_sample_rate);
+
+MP_PROPERTY_GETTER(synthio_miditrack_sample_rate_obj,
+ (mp_obj_t)&synthio_miditrack_get_sample_rate_obj);
+
+STATIC const mp_rom_map_elem_t synthio_miditrack_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&synthio_miditrack_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&synthio_miditrack___exit___obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&synthio_miditrack_sample_rate_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(synthio_miditrack_locals_dict, synthio_miditrack_locals_dict_table);
+
+STATIC const audiosample_p_t synthio_miditrack_proto = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample)
+ .sample_rate = (audiosample_sample_rate_fun)common_hal_synthio_miditrack_get_sample_rate,
+ .bits_per_sample = (audiosample_bits_per_sample_fun)common_hal_synthio_miditrack_get_bits_per_sample,
+ .channel_count = (audiosample_channel_count_fun)common_hal_synthio_miditrack_get_channel_count,
+ .reset_buffer = (audiosample_reset_buffer_fun)synthio_miditrack_reset_buffer,
+ .get_buffer = (audiosample_get_buffer_fun)synthio_miditrack_get_buffer,
+ .get_buffer_structure = (audiosample_get_buffer_structure_fun)synthio_miditrack_get_buffer_structure,
+};
+
+const mp_obj_type_t synthio_miditrack_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_MidiTrack,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = synthio_miditrack_make_new,
+ .locals_dict = (mp_obj_dict_t *)&synthio_miditrack_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &synthio_miditrack_proto,
+ ),
+};
diff --git a/circuitpython/shared-bindings/synthio/MidiTrack.h b/circuitpython/shared-bindings/synthio/MidiTrack.h
new file mode 100644
index 0000000..d44d4c3
--- /dev/null
+++ b/circuitpython/shared-bindings/synthio/MidiTrack.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Artyom Skrobov
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO_MIDITRACK_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO_MIDITRACK_H
+
+#include "shared-module/synthio/MidiTrack.h"
+
+extern const mp_obj_type_t synthio_miditrack_type;
+
+void common_hal_synthio_miditrack_construct(synthio_miditrack_obj_t *self,
+ const uint8_t *buffer, uint32_t len, uint32_t tempo, uint32_t sample_rate);
+
+void common_hal_synthio_miditrack_deinit(synthio_miditrack_obj_t *self);
+bool common_hal_synthio_miditrack_deinited(synthio_miditrack_obj_t *self);
+uint32_t common_hal_synthio_miditrack_get_sample_rate(synthio_miditrack_obj_t *self);
+uint8_t common_hal_synthio_miditrack_get_bits_per_sample(synthio_miditrack_obj_t *self);
+uint8_t common_hal_synthio_miditrack_get_channel_count(synthio_miditrack_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO_MIDITRACK_H
diff --git a/circuitpython/shared-bindings/synthio/__init__.c b/circuitpython/shared-bindings/synthio/__init__.c
new file mode 100644
index 0000000..72fe2eb
--- /dev/null
+++ b/circuitpython/shared-bindings/synthio/__init__.c
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Artyom Skrobov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/mperrno.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "extmod/vfs_fat.h"
+
+#include "shared-bindings/synthio/__init__.h"
+#include "shared-bindings/synthio/MidiTrack.h"
+
+//| """Support for MIDI synthesis"""
+//|
+//| def from_file(file: typing.BinaryIO, *, sample_rate: int = 11025) -> MidiTrack:
+//| """Create an AudioSample from an already opened MIDI file.
+//| Currently, only single-track MIDI (type 0) is supported.
+//|
+//| :param typing.BinaryIO file: Already opened MIDI file
+//| :param int sample_rate: The desired playback sample rate; higher sample rate requires more memory
+//|
+//|
+//| Playing a MIDI file from flash::
+//|
+//| import audioio
+//| import board
+//| import synthio
+//|
+//| data = open("single-track.midi", "rb")
+//| midi = synthio.from_file(data)
+//| a = audioio.AudioOut(board.A0)
+//|
+//| print("playing")
+//| a.play(midi)
+//| while a.playing:
+//| pass
+//| print("stopped")"""
+//| ...
+//|
+STATIC mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_file, ARG_sample_rate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 11025} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ if (!mp_obj_is_type(args[ARG_file].u_obj, &mp_type_fileio)) {
+ mp_raise_TypeError(translate("file must be a file opened in byte mode"));
+ }
+ pyb_file_obj_t *file = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
+
+ uint8_t chunk_header[14];
+ f_rewind(&file->fp);
+ UINT bytes_read;
+ if (f_read(&file->fp, chunk_header, sizeof(chunk_header), &bytes_read) != FR_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ if (bytes_read != sizeof(chunk_header) ||
+ memcmp(chunk_header, "MThd\0\0\0\6\0\0\0\1", 12)) {
+ mp_raise_ValueError(translate("Invalid MIDI file"));
+ // TODO: for a multi-track MIDI (type 1), return an AudioMixer
+ }
+
+ uint16_t tempo;
+ if (chunk_header[12] & 0x80) {
+ tempo = -(int8_t)chunk_header[12] * chunk_header[13];
+ } else {
+ tempo = 2 * ((chunk_header[12] << 8) | chunk_header[13]);
+ }
+
+ if (f_read(&file->fp, chunk_header, 8, &bytes_read) != FR_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ if (bytes_read != 8 || memcmp(chunk_header, "MTrk", 4)) {
+ mp_raise_ValueError(translate("Invalid MIDI file"));
+ }
+ uint32_t track_size = (chunk_header[4] << 24) |
+ (chunk_header[5] << 16) | (chunk_header[6] << 8) | chunk_header[7];
+ uint8_t *buffer = m_malloc(track_size, false);
+ if (f_read(&file->fp, buffer, track_size, &bytes_read) != FR_OK) {
+ mp_raise_OSError(MP_EIO);
+ }
+ if (bytes_read != track_size) {
+ mp_raise_ValueError(translate("Invalid MIDI file"));
+ }
+
+ synthio_miditrack_obj_t *result = m_new_obj(synthio_miditrack_obj_t);
+ result->base.type = &synthio_miditrack_type;
+
+ common_hal_synthio_miditrack_construct(result, buffer, track_size,
+ tempo, args[ARG_sample_rate].u_int);
+
+ m_free(buffer);
+
+ return MP_OBJ_FROM_PTR(result);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(synthio_from_file_obj, 1, synthio_from_file);
+
+
+STATIC const mp_rom_map_elem_t synthio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_synthio) },
+ { MP_ROM_QSTR(MP_QSTR_MidiTrack), MP_ROM_PTR(&synthio_miditrack_type) },
+ { MP_ROM_QSTR(MP_QSTR_from_file), MP_ROM_PTR(&synthio_from_file_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(synthio_module_globals, synthio_module_globals_table);
+
+const mp_obj_module_t synthio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&synthio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_synthio, synthio_module, CIRCUITPY_SYNTHIO);
diff --git a/circuitpython/shared-bindings/synthio/__init__.h b/circuitpython/shared-bindings/synthio/__init__.h
new file mode 100644
index 0000000..14af1a5
--- /dev/null
+++ b/circuitpython/shared-bindings/synthio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Artyom Skrobov
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_SYNTHIO___INIT___H
diff --git a/circuitpython/shared-bindings/terminalio/Terminal.c b/circuitpython/shared-bindings/terminalio/Terminal.c
new file mode 100644
index 0000000..cdeca59
--- /dev/null
+++ b/circuitpython/shared-bindings/terminalio/Terminal.c
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/terminalio/Terminal.h"
+#include "shared-bindings/util.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "shared-bindings/fontio/BuiltinFont.h"
+#include "supervisor/shared/translate.h"
+
+//| class Terminal:
+//| """Display a character stream with a TileGrid"""
+//|
+//| def __init__(self, tilegrid: displayio.TileGrid, font: fontio.BuiltinFont) -> None:
+//| """Terminal manages tile indices and cursor position based on VT100 commands. The font should be
+//| a `fontio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap."""
+//| ...
+//|
+
+STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_tilegrid, ARG_font };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_tilegrid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_font, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ displayio_tilegrid_t *tilegrid = mp_arg_validate_type(args[ARG_tilegrid].u_obj, &displayio_tilegrid_type, MP_QSTR_tilegrid);
+
+ fontio_builtinfont_t *font = mp_arg_validate_type(args[ARG_font].u_obj, &fontio_builtinfont_type, MP_QSTR_font);
+
+ terminalio_terminal_obj_t *self = m_new_obj(terminalio_terminal_obj_t);
+ self->base.type = &terminalio_terminal_type;
+
+ common_hal_terminalio_terminal_construct(self, tilegrid, font);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// These are standard stream methods. Code is in py/stream.c.
+//
+//| def write(self, buf: ReadableBuffer) -> Optional[int]:
+//| """Write the buffer of bytes to the bus.
+//|
+//| :return: the number of bytes written
+//| :rtype: int or None"""
+//| ...
+//|
+STATIC mp_uint_t terminalio_terminal_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ terminalio_terminal_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const byte *buf = buf_in;
+
+ return common_hal_terminalio_terminal_write(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t terminalio_terminal_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ terminalio_terminal_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_terminalio_terminal_ready_to_tx(self)) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_rom_map_elem_t terminalio_terminal_locals_dict_table[] = {
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(terminalio_terminal_locals_dict, terminalio_terminal_locals_dict_table);
+
+STATIC const mp_stream_p_t terminalio_terminal_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = NULL,
+ .write = terminalio_terminal_write,
+ .ioctl = terminalio_terminal_ioctl,
+ .is_text = true,
+};
+
+const mp_obj_type_t terminalio_terminal_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Terminal,
+ .make_new = terminalio_terminal_make_new,
+ .locals_dict = (mp_obj_dict_t *)&terminalio_terminal_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &terminalio_terminal_stream_p,
+ ),
+};
diff --git a/circuitpython/shared-bindings/terminalio/Terminal.h b/circuitpython/shared-bindings/terminalio/Terminal.h
new file mode 100644
index 0000000..f884edd
--- /dev/null
+++ b/circuitpython/shared-bindings/terminalio/Terminal.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO_TERMINAL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO_TERMINAL_H
+
+#include "shared-module/terminalio/Terminal.h"
+
+#include "shared-bindings/displayio/TileGrid.h"
+
+extern const mp_obj_type_t terminalio_terminal_type;
+
+extern void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
+ displayio_tilegrid_t *tilegrid, const fontio_builtinfont_t *font);
+
+// Write characters. len is in characters NOT bytes!
+extern size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self,
+ const uint8_t *data, size_t len, int *errcode);
+
+extern bool common_hal_terminalio_terminal_ready_to_tx(terminalio_terminal_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO_TERMINAL_H
diff --git a/circuitpython/shared-bindings/terminalio/__init__.c b/circuitpython/shared-bindings/terminalio/__init__.c
new file mode 100644
index 0000000..5fd1a27
--- /dev/null
+++ b/circuitpython/shared-bindings/terminalio/__init__.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/terminalio/__init__.h"
+#include "shared-bindings/terminalio/Terminal.h"
+#include "supervisor/shared/display.h"
+
+#include "py/runtime.h"
+
+//| """Displays text in a TileGrid
+//|
+//| The `terminalio` module contains classes to display a character stream on a display. The built
+//| in font is available as ``terminalio.FONT``.
+//|
+//| .. note:: This module does not give access to the
+//| `REPL <https://learn.adafruit.com/welcome-to-circuitpython/interacting-with-the-serial-console>`_.
+//|
+//| """
+//|
+//| FONT: fontio.BuiltinFont
+//| """The built in font"""
+//|
+STATIC const mp_rom_map_elem_t terminalio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_terminalio) },
+ { MP_ROM_QSTR(MP_QSTR_Terminal), MP_OBJ_FROM_PTR(&terminalio_terminal_type) },
+ { MP_ROM_QSTR(MP_QSTR_FONT), MP_ROM_PTR(&supervisor_terminal_font) },
+};
+
+
+STATIC MP_DEFINE_CONST_DICT(terminalio_module_globals, terminalio_module_globals_table);
+
+const mp_obj_module_t terminalio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&terminalio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_terminalio, terminalio_module, CIRCUITPY_DISPLAYIO && CIRCUITPY_TERMINALIO);
diff --git a/circuitpython/shared-bindings/terminalio/__init__.h b/circuitpython/shared-bindings/terminalio/__init__.h
new file mode 100644
index 0000000..4be14df
--- /dev/null
+++ b/circuitpython/shared-bindings/terminalio/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO___INIT___H
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TERMINALIO___INIT___H
diff --git a/circuitpython/shared-bindings/time/__init__.c b/circuitpython/shared-bindings/time/__init__.c
new file mode 100644
index 0000000..5b16ded
--- /dev/null
+++ b/circuitpython/shared-bindings/time/__init__.c
@@ -0,0 +1,348 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/objnamedtuple.h"
+#include "py/runtime.h"
+#include "shared/timeutils/timeutils.h"
+#include "shared-bindings/rtc/__init__.h"
+#include "shared-bindings/time/__init__.h"
+#include "supervisor/shared/translate.h"
+
+//| """time and timing related functions
+//|
+//| |see_cpython_module| :mod:`cpython:time`.
+//| """
+//|
+//| def monotonic() -> float:
+//| """Returns an always increasing value of time with an unknown reference
+//| point. Only use it to compare against other values from `time.monotonic()`.
+//|
+//| On most boards, `time.monotonic()` converts a 64-bit millisecond tick counter
+//| to a float. Floats on most boards are encoded in 30 bits internally, with
+//| effectively 22 bits of precision. The float returned by `time.monotonic()` will
+//| accurately represent time to millisecond precision only up to 2**22 milliseconds
+//| (about 1.165 hours).
+//| At that point it will start losing precision, and its value will change only
+//| every second millisecond. At 2**23 milliseconds it will change every fourth
+//| millisecond, and so forth.
+//|
+//| If you need more consistent precision, use `time.monotonic_ns()`, or `supervisor.ticks_ms()`.
+//| `time.monotonic_ns()` is not available on boards without long integer support.
+//| `supervisor.ticks_ms()` uses intervals of a millisecond, but wraps around, and is not
+//| CPython-compatible.
+//|
+//| :return: the current monotonic time
+//| :rtype: float"""
+//| ...
+//|
+STATIC mp_obj_t time_monotonic(void) {
+ uint64_t ticks_ms = common_hal_time_monotonic_ms();
+ return mp_obj_new_float(uint64_to_float(ticks_ms) / 1000.0f);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_obj, time_monotonic);
+
+//| def sleep(seconds: float) -> None:
+//| """Sleep for a given number of seconds.
+//|
+//| :param float seconds: the time to sleep in fractional seconds"""
+//| ...
+//|
+STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ mp_float_t seconds = mp_obj_get_float(seconds_o);
+ mp_float_t msecs = 1000.0f * seconds + 0.5f;
+ #else
+ mp_int_t seconds = mp_obj_get_int(seconds_o);
+ mp_int_t msecs = 1000 * seconds;
+ #endif
+ if (seconds < 0) {
+ mp_raise_ValueError(translate("sleep length must be non-negative"));
+ }
+ common_hal_time_delay_ms(msecs);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
+
+#if MICROPY_PY_COLLECTIONS
+STATIC mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ size_t len;
+ mp_obj_t *items;
+ mp_obj_get_array(args[0], &len, &items);
+ if (len != 9) {
+ mp_raise_TypeError(translate("time.struct_time() takes a 9-sequence"));
+ }
+ return namedtuple_make_new(type, len, 0, items);
+}
+
+//| class struct_time:
+//| def __init__(self, time_tuple: Sequence[int]) -> None:
+//| """Structure used to capture a date and time. Can be constructed from a `struct_time`, `tuple`, `list`, or `namedtuple` with 9 elements.
+//|
+//| :param Sequence time_tuple: Sequence of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)``
+//|
+//| * ``tm_year``: the year, 2017 for example
+//| * ``tm_mon``: the month, range [1, 12]
+//| * ``tm_mday``: the day of the month, range [1, 31]
+//| * ``tm_hour``: the hour, range [0, 23]
+//| * ``tm_min``: the minute, range [0, 59]
+//| * ``tm_sec``: the second, range [0, 61]
+//| * ``tm_wday``: the day of the week, range [0, 6], Monday is 0
+//| * ``tm_yday``: the day of the year, range [1, 366], -1 indicates not known
+//| * ``tm_isdst``: 1 when in daylight savings, 0 when not, -1 if unknown."""
+//| ...
+//|
+const mp_obj_namedtuple_type_t struct_time_type_obj = {
+ .base = {
+ .base = {
+ .type = &mp_type_type
+ },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_struct_time,
+ .print = namedtuple_print,
+ .parent = &mp_type_tuple,
+ .make_new = struct_time_make_new,
+ .attr = namedtuple_attr,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_obj_tuple_unary_op,
+ .binary_op = mp_obj_tuple_binary_op,
+ .subscr = mp_obj_tuple_subscr,
+ .getiter = mp_obj_tuple_getiter,
+ ),
+ },
+ .n_fields = 9,
+ .fields = {
+ MP_QSTR_tm_year,
+ MP_QSTR_tm_mon,
+ MP_QSTR_tm_mday,
+ MP_QSTR_tm_hour,
+ MP_QSTR_tm_min,
+ MP_QSTR_tm_sec,
+ MP_QSTR_tm_wday,
+ MP_QSTR_tm_yday,
+ MP_QSTR_tm_isdst
+ },
+};
+
+mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm) {
+ timeutils_struct_time_t tmp;
+ mp_uint_t secs = timeutils_seconds_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ timeutils_seconds_since_epoch_to_struct_time(secs, &tmp);
+ tm->tm_wday = tmp.tm_wday;
+ tm->tm_yday = tmp.tm_yday;
+
+ mp_obj_t elems[9] = {
+ mp_obj_new_int(tm->tm_year),
+ mp_obj_new_int(tm->tm_mon),
+ mp_obj_new_int(tm->tm_mday),
+ mp_obj_new_int(tm->tm_hour),
+ mp_obj_new_int(tm->tm_min),
+ mp_obj_new_int(tm->tm_sec),
+ mp_obj_new_int(tm->tm_wday),
+ mp_obj_new_int(tm->tm_yday),
+ mp_obj_new_int(-1), // tm_isdst is not supported
+ };
+
+ return namedtuple_make_new((const mp_obj_type_t *)&struct_time_type_obj, 9, 0, elems);
+};
+
+void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm) {
+ mp_obj_t *elems;
+ size_t len;
+
+ if (!mp_obj_is_type(t, &mp_type_tuple) && !mp_obj_is_type(t, &struct_time_type_obj.base)) {
+ mp_raise_TypeError(translate("Tuple or struct_time argument required"));
+ }
+
+ mp_obj_tuple_get(t, &len, &elems);
+ if (len != 9) {
+ mp_raise_TypeError(translate("function takes exactly 9 arguments"));
+ }
+
+ tm->tm_year = mp_obj_get_int(elems[0]);
+ tm->tm_mon = mp_obj_get_int(elems[1]);
+ tm->tm_mday = mp_obj_get_int(elems[2]);
+ tm->tm_hour = mp_obj_get_int(elems[3]);
+ tm->tm_min = mp_obj_get_int(elems[4]);
+ tm->tm_sec = mp_obj_get_int(elems[5]);
+ tm->tm_wday = mp_obj_get_int(elems[6]);
+ tm->tm_yday = mp_obj_get_int(elems[7]);
+ // elems[8] tm_isdst is not supported
+}
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+// Function to return a NotImplementedError on platforms that don't
+// support long integers
+STATIC mp_obj_t time_not_implemented(void) {
+ mp_raise_NotImplementedError(translate("No long integer support"));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_not_implemented_obj, time_not_implemented);
+#endif
+
+#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+mp_obj_t MP_WEAK rtc_get_time_source_time(void) {
+ mp_raise_RuntimeError(translate("RTC is not supported on this board"));
+}
+
+//| def time() -> int:
+//| """Return the current time in seconds since since Jan 1, 1970.
+//|
+//| :return: the current time
+//| :rtype: int"""
+//| ...
+//|
+STATIC mp_obj_t time_time(void) {
+ timeutils_struct_time_t tm;
+ struct_time_to_tm(rtc_get_time_source_time(), &tm);
+ mp_uint_t secs = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ return mp_obj_new_int_from_uint(secs);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
+
+//| def monotonic_ns() -> int:
+//| """Return the time of the monotonic clock, which cannot go backward, in nanoseconds.
+//| Not available on boards without long integer support.
+//|
+//| :return: the current time
+//| :rtype: int"""
+//| ...
+//|
+STATIC mp_obj_t time_monotonic_ns(void) {
+ uint64_t time64 = common_hal_time_monotonic_ns();
+ return mp_obj_new_int_from_ll((long long)time64);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns);
+
+//| def localtime(secs: int) -> struct_time:
+//| """Convert a time expressed in seconds since Jan 1, 1970 to a struct_time in
+//| local time. If secs is not provided or None, the current time as returned
+//| by time() is used.
+//| The earliest date for which it can generate a time is Jan 1, 2000.
+//|
+//| :return: the current time
+//| :rtype: time.struct_time"""
+//| ...
+//|
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0 || args[0] == mp_const_none) {
+ return rtc_get_time_source_time();
+ }
+
+ mp_obj_t arg = args[0];
+ if (mp_obj_is_float(arg)) {
+ arg = mp_obj_new_int_from_float(mp_obj_get_float(arg));
+ }
+
+ mp_int_t secs = mp_obj_get_int(arg);
+
+ #if MICROPY_EPOCH_IS_1970
+ if (secs < 0 || (mp_uint_t)secs < TIMEUTILS_SECONDS_1970_TO_2000) {
+ #else
+ if (secs < 0) {
+ #endif
+ mp_raise_msg(&mp_type_OverflowError, translate("timestamp out of range for platform time_t"));
+ }
+
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_epoch_to_struct_time(secs, &tm);
+
+ return struct_time_from_tm(&tm);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
+
+//| def mktime(t: struct_time) -> int:
+//| """This is the inverse function of localtime(). Its argument is the
+//| struct_time or full 9-tuple (since the dst flag is needed; use -1 as the
+//| dst flag if it is unknown) which expresses the time in local time, not UTC.
+//| The earliest date for which it can generate a time is Jan 1, 2000.
+//|
+//| :return: seconds
+//| :rtype: int"""
+//| ...
+//|
+STATIC mp_obj_t time_mktime(mp_obj_t t) {
+ mp_obj_t *elem;
+ size_t len;
+
+ if (!mp_obj_is_type(t, &mp_type_tuple) && !mp_obj_is_type(t, &struct_time_type_obj.base)) {
+ mp_raise_TypeError(translate("Tuple or struct_time argument required"));
+ }
+
+ mp_obj_tuple_get(t, &len, &elem);
+ if (len != 9) {
+ mp_raise_TypeError_varg(translate("function takes %d positional arguments but %d were given"), 9, len);
+ }
+
+ if (mp_obj_get_int(elem[0]) < 2000) {
+ mp_raise_msg(&mp_type_OverflowError, translate("timestamp out of range for platform time_t"));
+ }
+
+ mp_uint_t secs = timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]),
+ mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]));
+ return mp_obj_new_int_from_uint(secs);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
+#endif // MICROPY_LONGINT_IMPL
+#endif // MICROPY_PY_COLLECTIONS
+
+STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) },
+
+ { MP_ROM_QSTR(MP_QSTR_monotonic), MP_ROM_PTR(&time_monotonic_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&time_sleep_obj) },
+ #if MICROPY_PY_COLLECTIONS
+ { MP_ROM_QSTR(MP_QSTR_struct_time), MP_ROM_PTR(&struct_time_type_obj) },
+ #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+ { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
+ #endif // MICROPY_LONGINT_IMPL
+ #endif // MICROPY_PY_COLLECTIONS
+ #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
+ { MP_ROM_QSTR(MP_QSTR_monotonic_ns), MP_ROM_PTR(&time_monotonic_ns_obj) },
+ #endif
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
+ { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_not_implemented_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_not_implemented_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_not_implemented_obj) },
+ { MP_ROM_QSTR(MP_QSTR_monotonic_ns), MP_ROM_PTR(&time_not_implemented_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
+
+const mp_obj_module_t time_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&time_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_time, time_module, CIRCUITPY_TIME);
diff --git a/circuitpython/shared-bindings/time/__init__.h b/circuitpython/shared-bindings/time/__init__.h
new file mode 100644
index 0000000..dba8229
--- /dev/null
+++ b/circuitpython/shared-bindings/time/__init__.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_TIME___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_TIME___INIT___H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "shared/timeutils/timeutils.h"
+
+extern mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm);
+extern void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm);
+
+extern uint64_t common_hal_time_monotonic_ms(void);
+extern uint64_t common_hal_time_monotonic_ns(void);
+extern void common_hal_time_delay_ms(uint32_t);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TIME___INIT___H
diff --git a/circuitpython/shared-bindings/touchio/TouchIn.c b/circuitpython/shared-bindings/touchio/TouchIn.c
new file mode 100644
index 0000000..23b3525
--- /dev/null
+++ b/circuitpython/shared-bindings/touchio/TouchIn.c
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/mphal.h"
+#include "py/nlr.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/touchio/TouchIn.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| class TouchIn:
+//| """Read the state of a capacitive touch sensor
+//|
+//| Usage::
+//|
+//| import touchio
+//| from board import *
+//|
+//| touch = touchio.TouchIn(A1)
+//| while True:
+//| if touch.value:
+//| print("touched!")"""
+//|
+
+//| def __init__(self, pin: microcontroller.Pin) -> None:
+//| """Use the TouchIn on the given pin.
+//|
+//| :param ~microcontroller.Pin pin: the pin to read from"""
+//| ...
+//|
+STATIC mp_obj_t touchio_touchin_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // 1st argument is the pin
+ const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[0]);
+
+ touchio_touchin_obj_t *self = m_new_obj(touchio_touchin_obj_t);
+ self->base.type = &touchio_touchin_type;
+ common_hal_touchio_touchin_construct(self, pin);
+
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Deinitialises the TouchIn and releases any hardware resources for reuse."""
+//| ...
+//|
+STATIC mp_obj_t touchio_touchin_deinit(mp_obj_t self_in) {
+ touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_touchio_touchin_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_deinit_obj, touchio_touchin_deinit);
+
+STATIC void check_for_deinit(touchio_touchin_obj_t *self) {
+ if (common_hal_touchio_touchin_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def __enter__(self) -> TouchIn:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t touchio_touchin_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_touchio_touchin_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(touchio_touchin___exit___obj, 4, 4, touchio_touchin_obj___exit__);
+
+//| value: bool
+//| """Whether the touch pad is being touched or not. (read-only)
+//|
+//| True when `raw_value` > `threshold`."""
+//|
+STATIC mp_obj_t touchio_touchin_obj_get_value(mp_obj_t self_in) {
+ touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_touchio_touchin_get_value(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_get_value_obj, touchio_touchin_obj_get_value);
+
+MP_PROPERTY_GETTER(touchio_touchin_value_obj,
+ (mp_obj_t)&touchio_touchin_get_value_obj);
+
+
+//| raw_value: int
+//| """The raw touch measurement as an `int`. (read-only)"""
+//|
+STATIC mp_obj_t touchio_touchin_obj_get_raw_value(mp_obj_t self_in) {
+ touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_touchio_touchin_get_raw_value(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_get_raw_value_obj, touchio_touchin_obj_get_raw_value);
+
+MP_PROPERTY_GETTER(touchio_touchin_raw_value_obj,
+ (mp_obj_t)&touchio_touchin_get_raw_value_obj);
+
+
+//| threshold: Optional[int]
+//| """Minimum `raw_value` needed to detect a touch (and for `value` to be `True`).
+//|
+//| When the **TouchIn** object is created, an initial `raw_value` is read from the pin,
+//| and then `threshold` is set to be 100 + that value.
+//|
+//| You can adjust `threshold` to make the pin more or less sensitive::
+//|
+//| import board
+//| import touchio
+//|
+//| touch = touchio.TouchIn(board.A1)
+//| touch.threshold = 7300"""
+//|
+STATIC mp_obj_t touchio_touchin_obj_get_threshold(mp_obj_t self_in) {
+ touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_touchio_touchin_get_threshold(self));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_get_threshold_obj, touchio_touchin_obj_get_threshold);
+
+STATIC mp_obj_t touchio_touchin_obj_set_threshold(mp_obj_t self_in, mp_obj_t threshold_obj) {
+ touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ uint32_t new_threshold = mp_obj_get_int(threshold_obj);
+ if (new_threshold < 0 || new_threshold > UINT16_MAX) {
+ // I would use MP_STRINGIFY(UINT16_MAX), but that prints "0xffff" instead of 65536.
+ mp_raise_ValueError(translate("threshold must be in the range 0-65536"));
+ }
+ common_hal_touchio_touchin_set_threshold(self, new_threshold);
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_2(touchio_touchin_set_threshold_obj, touchio_touchin_obj_set_threshold);
+
+MP_PROPERTY_GETSET(touchio_touchin_threshold_obj,
+ (mp_obj_t)&touchio_touchin_get_threshold_obj,
+ (mp_obj_t)&touchio_touchin_set_threshold_obj);
+
+
+STATIC const mp_rom_map_elem_t touchio_touchin_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&touchio_touchin___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&touchio_touchin_deinit_obj) },
+
+ { MP_OBJ_NEW_QSTR(MP_QSTR_value), MP_ROM_PTR(&touchio_touchin_value_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_raw_value), MP_ROM_PTR(&touchio_touchin_raw_value_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_threshold), MP_ROM_PTR(&touchio_touchin_threshold_obj)},
+};
+
+STATIC MP_DEFINE_CONST_DICT(touchio_touchin_locals_dict, touchio_touchin_locals_dict_table);
+
+const mp_obj_type_t touchio_touchin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_TouchIn,
+ .make_new = touchio_touchin_make_new,
+ .locals_dict = (mp_obj_t)&touchio_touchin_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/touchio/TouchIn.h b/circuitpython/shared-bindings/touchio/TouchIn.h
new file mode 100644
index 0000000..1da2cf1
--- /dev/null
+++ b/circuitpython/shared-bindings/touchio/TouchIn.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO_TOUCHIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO_TOUCHIN_H
+
+#include "common-hal/microcontroller/Pin.h"
+
+#if CIRCUITPY_TOUCHIO_USE_NATIVE
+#include "common-hal/touchio/TouchIn.h"
+#else
+#include "shared-module/touchio/TouchIn.h"
+#endif
+
+extern const mp_obj_type_t touchio_touchin_type;
+
+void common_hal_touchio_touchin_construct(touchio_touchin_obj_t *self, const mcu_pin_obj_t *pin);
+void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t *self);
+bool common_hal_touchio_touchin_deinited(touchio_touchin_obj_t *self);
+bool common_hal_touchio_touchin_get_value(touchio_touchin_obj_t *self);
+uint16_t common_hal_touchio_touchin_get_raw_value(touchio_touchin_obj_t *self);
+uint16_t common_hal_touchio_touchin_get_threshold(touchio_touchin_obj_t *self);
+void common_hal_touchio_touchin_set_threshold(touchio_touchin_obj_t *self, uint16_t new_threshold);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO_TOUCHIN_H
diff --git a/circuitpython/shared-bindings/touchio/__init__.c b/circuitpython/shared-bindings/touchio/__init__.c
new file mode 100644
index 0000000..e2a6ad9
--- /dev/null
+++ b/circuitpython/shared-bindings/touchio/__init__.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/touchio/__init__.h"
+#include "shared-bindings/touchio/TouchIn.h"
+
+#include "py/runtime.h"
+
+//| """Touch related IO
+//|
+//| The `touchio` module contains classes to provide access to touch IO typically
+//| accelerated by hardware on the onboard microcontroller.
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| For example::
+//|
+//| import touchio
+//| from board import *
+//|
+//| touch_pin = touchio.TouchIn(D6)
+//| print(touch_pin.value)
+//|
+//| This example will initialize the the device, and print the
+//| :py:data:`~touchio.TouchIn.value`."""
+//|
+
+STATIC const mp_rom_map_elem_t touchio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_touchio) },
+ { MP_ROM_QSTR(MP_QSTR_TouchIn), MP_ROM_PTR(&touchio_touchin_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(touchio_module_globals, touchio_module_globals_table);
+
+const mp_obj_module_t touchio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&touchio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_touchio, touchio_module, CIRCUITPY_TOUCHIO);
diff --git a/circuitpython/shared-bindings/touchio/__init__.h b/circuitpython/shared-bindings/touchio/__init__.h
new file mode 100644
index 0000000..f1d3501
--- /dev/null
+++ b/circuitpython/shared-bindings/touchio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO___INIT___H
diff --git a/circuitpython/shared-bindings/traceback/__init__.c b/circuitpython/shared-bindings/traceback/__init__.c
new file mode 100644
index 0000000..880fe08
--- /dev/null
+++ b/circuitpython/shared-bindings/traceback/__init__.c
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/stream.h"
+#include "py/runtime.h"
+
+#include "shared-module/traceback/__init__.h"
+
+//| """Traceback Module
+//|
+//| This module provides a standard interface to print stack traces of programs.
+//| This is useful when you want to print stack traces under program control.
+//|
+//| |see_cpython_module| :mod:`cpython:traceback`.
+//| """
+//| ...
+//|
+
+STATIC void traceback_exception_common(mp_print_t *print, mp_obj_t value, mp_obj_t tb_obj, mp_obj_t limit_obj) {
+ if (!mp_obj_is_exception_instance(value)) {
+ mp_raise_TypeError(translate("invalid exception"));
+ }
+
+ mp_int_t limit = 0;
+ bool print_tb = true;
+ if (limit_obj != mp_const_none) {
+ limit = mp_obj_get_int(limit_obj);
+ print_tb = (limit != 0);
+ }
+
+ mp_obj_exception_t *exc = mp_obj_exception_get_native(value);
+ mp_obj_traceback_t *trace_backup = exc->traceback;
+
+ if (tb_obj != mp_const_none && print_tb) {
+ exc->traceback = mp_arg_validate_type(tb_obj, &mp_type_traceback, MP_QSTR_tb);
+ } else {
+ exc->traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj;
+ }
+
+ shared_module_traceback_print_exception(MP_OBJ_TO_PTR(value), print, limit);
+ exc->traceback = trace_backup;
+}
+
+//| def format_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType,
+//| limit: Optional[int] = None, chain: Optional[bool] = True) -> None:
+//| """Format a stack trace and the exception information.
+//|
+//| The arguments have the same meaning as the corresponding arguments
+//| to print_exception(). The return value is a list of strings, each
+//| ending in a newline and some containing internal newlines. When
+//| these lines are concatenated and printed, exactly the same text is
+//| printed as does print_exception().
+//|
+//| .. note:: Setting ``chain`` will have no effect as chained exceptions are not yet implemented.
+//|
+//| :param Type[BaseException] etype: This is ignored and inferred from the type of ``value``.
+//| :param BaseException value: The exception. Must be an instance of `BaseException`.
+//| :param TracebackType tb: The traceback object. If `None`, the traceback will not be printed.
+//| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive.
+//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed.
+//| :param bool chain: If `True` then chained exceptions will be printed (note: not yet implemented).
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t traceback_format_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_chain };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_etype, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_value, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_tb, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_limit, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_chain, MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_print_t print;
+ vstr_t vstr;
+ vstr_init_print(&vstr, 0, &print);
+ traceback_exception_common(&print, args[ARG_value].u_obj, args[ARG_tb].u_obj, args[ARG_limit].u_obj);
+ return mp_obj_new_str_from_vstr(&mp_type_str, &vstr);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_format_exception);
+
+//| def print_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType,
+//| limit: Optional[int] = None, file: Optional[io.FileIO] = None, chain: Optional[bool] = True) -> None:
+//|
+//| """Prints exception information and stack trace entries.
+//|
+//| .. note:: Setting ``chain`` will have no effect as chained exceptions are not yet implemented.
+//|
+//| :param Type[BaseException] etype: This is ignored and inferred from the type of ``value``.
+//| :param BaseException value: The exception. Must be an instance of `BaseException`.
+//| :param TracebackType tb: The traceback object. If `None`, the traceback will not be printed.
+//| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive.
+//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed.
+//| :param io.FileIO file: If file is omitted or `None`, the output goes to `sys.stderr`; otherwise it should be an open
+//| file or file-like object to receive the output.
+//| :param bool chain: If `True` then chained exceptions will be printed (note: not yet implemented).
+//|
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_file, ARG_chain };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_etype, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_value, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_tb, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_limit, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_file, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_chain, MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_print_t print = mp_plat_print;
+ if (args[ARG_file].u_obj != mp_const_none) {
+ #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES
+ mp_get_stream_raise(args[ARG_file].u_obj, MP_STREAM_OP_WRITE);
+ print.data = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
+ print.print_strn = mp_stream_write_adaptor;
+ #else
+ mp_raise_NotImplementedError(translate("file write is not available"));
+ #endif
+ }
+
+ traceback_exception_common(&print, args[ARG_value].u_obj, args[ARG_tb].u_obj, args[ARG_limit].u_obj);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_print_exception_obj, 0, traceback_print_exception);
+
+STATIC const mp_rom_map_elem_t traceback_module_globals_table[] = {
+ // module name
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_traceback) },
+ // module functions
+ { MP_ROM_QSTR(MP_QSTR_format_exception), MP_ROM_PTR(&traceback_format_exception_obj) },
+ { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&traceback_print_exception_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(traceback_module_globals, traceback_module_globals_table);
+
+const mp_obj_module_t traceback_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&traceback_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_traceback, traceback_module, CIRCUITPY_TRACEBACK);
diff --git a/circuitpython/shared-bindings/uheap/__init__.c b/circuitpython/shared-bindings/uheap/__init__.c
new file mode 100644
index 0000000..40aa869
--- /dev/null
+++ b/circuitpython/shared-bindings/uheap/__init__.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/uheap/__init__.h"
+
+//| """Heap size analysis"""
+//|
+
+//| def info(object: object) -> int:
+//| """Prints memory debugging info for the given object and returns the
+//| estimated size."""
+//| ...
+//|
+STATIC mp_obj_t uheap_info(mp_obj_t obj) {
+ uint32_t size = shared_module_uheap_info(obj);
+
+ return MP_OBJ_NEW_SMALL_INT(size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(uheap_info_obj, uheap_info);
+
+STATIC const mp_rom_map_elem_t uheap_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheap) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&uheap_info_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(uheap_module_globals, uheap_module_globals_table);
+
+const mp_obj_module_t uheap_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&uheap_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_uheap, uheap_module, CIRCUITPY_UHEAP);
diff --git a/circuitpython/shared-bindings/uheap/__init__.h b/circuitpython/shared-bindings/uheap/__init__.h
new file mode 100644
index 0000000..53afb41
--- /dev/null
+++ b/circuitpython/shared-bindings/uheap/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H
+
+#include "py/obj.h"
+
+extern uint32_t shared_module_uheap_info(mp_obj_t obj);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H
diff --git a/circuitpython/shared-bindings/usb/__init__.c b/circuitpython/shared-bindings/usb/__init__.c
new file mode 100644
index 0000000..bae72da
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/__init__.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb/__init__.h"
+#include "shared-bindings/usb/core/__init__.h"
+
+//| """PyUSB-compatible USB host API
+//|
+//| The `usb` is a subset of PyUSB that allows you to communicate to USB devices.
+//| """
+//|
+
+STATIC mp_rom_map_elem_t usb_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb) },
+ { MP_ROM_QSTR(MP_QSTR_core), MP_OBJ_FROM_PTR(&usb_core_module) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_module_globals, usb_module_globals_table);
+
+const mp_obj_module_t usb_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb, usb_module, CIRCUITPY_USB_HOST);
diff --git a/circuitpython/shared-bindings/usb/__init__.h b/circuitpython/shared-bindings/usb/__init__.h
new file mode 100644
index 0000000..d672285
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/usb/core/Device.c b/circuitpython/shared-bindings/usb/core/Device.c
new file mode 100644
index 0000000..3a9e9bb
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/core/Device.c
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// This file uses method signatures and comments derived from the PyUSB code
+// that has the below BSD-3 license.
+/* Copyright 2009-2017 Wander Lairson Costa
+ * Copyright 2009-2021 PyUSB contributors
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "py/objproperty.h"
+#include "shared-bindings/usb/core/Device.h"
+#include "py/runtime.h"
+
+//| class Device:
+//|
+//| def __init__(self) -> None:
+//| """User code cannot create Device objects. Instead, get them from
+//| `usb.core.find`.
+//| """
+//| ...
+//|
+
+//| idVendor: int
+//| """The USB vendor ID of the device"""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_idVendor(mp_obj_t self_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idVendor(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idVendor_obj, usb_core_device_obj_get_idVendor);
+
+MP_PROPERTY_GETTER(usb_core_device_idVendor_obj,
+ (mp_obj_t)&usb_core_device_get_idVendor_obj);
+
+//| idProduct: int
+//| """The USB product ID of the device"""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_idProduct(mp_obj_t self_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_get_idProduct(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_idProduct_obj, usb_core_device_obj_get_idProduct);
+
+MP_PROPERTY_GETTER(usb_core_device_idProduct_obj,
+ (mp_obj_t)&usb_core_device_get_idProduct_obj);
+
+//| serial_number: str
+//| """The USB device's serial number string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_serial_number(mp_obj_t self_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_usb_core_device_get_serial_number(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_serial_number_obj, usb_core_device_obj_get_serial_number);
+
+MP_PROPERTY_GETTER(usb_core_device_serial_number_obj,
+ (mp_obj_t)&usb_core_device_get_serial_number_obj);
+
+//| product: str
+//| """The USB device's product string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_product(mp_obj_t self_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_usb_core_device_get_product(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_product_obj, usb_core_device_obj_get_product);
+
+MP_PROPERTY_GETTER(usb_core_device_product_obj,
+ (mp_obj_t)&usb_core_device_get_product_obj);
+
+//| manufacturer: str
+//| """The USB device's manufacturer string."""
+//|
+STATIC mp_obj_t usb_core_device_obj_get_manufacturer(mp_obj_t self_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_usb_core_device_get_manufacturer(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_core_device_get_manufacturer_obj, usb_core_device_obj_get_manufacturer);
+
+MP_PROPERTY_GETTER(usb_core_device_manufacturer_obj,
+ (mp_obj_t)&usb_core_device_get_manufacturer_obj);
+
+//| def write(self, endpoint: int, data: ReadableBuffer, timeout = None) -> int:
+//| """Write data to a specific endpoint on the device.
+//|
+//| :param int endpoint: the bEndpointAddress you want to communicate with.
+//| :param ReadableBuffer data: the data to send
+//| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
+//| :returns: the number of bytes written
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_core_device_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_endpoint, ARG_data, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+ };
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_write(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write);
+
+
+//| def read(self, endpoint: int, size_or_buffer: array.array, timeout = None) -> int:
+//| """Read data from the endpoint.
+//|
+//| :param int endpoint: the bEndpointAddress you want to communicate with.
+//| :param array.array size_or_buffer: the array to read data into. PyUSB also allows size but CircuitPython only support array to force deliberate memory use.
+//| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!)
+//| :returns: the number of bytes read
+//| """
+//| ...
+STATIC mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+ };
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_size_or_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int));
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_read_obj, 2, usb_core_device_read);
+
+//| def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
+//| data_or_wLength: array.array = None, timeout = None) -> int:
+//| """Do a control transfer on the endpoint 0. The parameters bmRequestType,
+//| bRequest, wValue and wIndex are the same of the USB Standard Control
+//| Request format.
+//|
+//| Control requests may or may not have a data payload to write/read.
+//| In cases which it has, the direction bit of the bmRequestType
+//| field is used to infer the desired request direction.
+//|
+//| For host to device requests (OUT), data_or_wLength parameter is
+//| the data payload to send, and it must be a sequence type convertible
+//| to an array object. In this case, the return value is the number
+//| of bytes written in the data payload.
+//|
+//| For device to host requests (IN), data_or_wLength is an array
+//| object which the data will be read to, and the return value is the
+//| number of bytes read.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_core_device_ctrl_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bmRequestType, ARG_bRequest, ARG_wValue, ARG_wIndex, ARG_data_or_wLength, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bmRequestType, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_bRequest, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_wValue, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_wIndex, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_data_or_wLength, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} },
+ };
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ // check request type
+ if ((args[ARG_bmRequestType].u_int & 0x80) != 0) {
+ mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_WRITE);
+ } else {
+ mp_get_buffer_raise(args[ARG_data_or_wLength].u_obj, &bufinfo, MP_BUFFER_READ);
+ }
+
+ mp_int_t result = common_hal_usb_core_device_ctrl_transfer(self,
+ args[ARG_bmRequestType].u_int, args[ARG_bRequest].u_int,
+ args[ARG_wValue].u_int, args[ARG_wIndex].u_int,
+ bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int);
+
+ return MP_OBJ_NEW_SMALL_INT(result);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_ctrl_transfer_obj, 2, usb_core_device_ctrl_transfer);
+
+//| def is_kernel_driver_active(self, interface: int) -> bool:
+//| """Determine if CircuitPython is using the interface. If it is, the
+//| object will be unable to perform I/O.
+//|
+//| :param int interface: the device interface number to check
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_core_device_is_kernel_driver_active(mp_obj_t self_in, mp_obj_t interface_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t interface = mp_obj_get_int(interface_in);
+ bool active = common_hal_usb_core_device_is_kernel_driver_active(self, interface);
+ return mp_obj_new_bool(active);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_is_kernel_driver_active_obj, usb_core_device_is_kernel_driver_active);
+
+//| def detach_kernel_driver(self, interface: int):
+//| """Stop CircuitPython from using the interface. If successful, you
+//| will then be able to perform I/O. CircuitPython will automatically
+//| re-start using the interface on reload.
+//|
+//| :param int interface: the device interface number to stop CircuitPython on
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_core_device_detach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t interface = mp_obj_get_int(interface_in);
+ common_hal_usb_core_device_detach_kernel_driver(self, interface);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_detach_kernel_driver_obj, usb_core_device_detach_kernel_driver);
+
+//| def attach_kernel_driver(self, interface: int):
+//| """Allow CircuitPython to use the interface if it wants to.
+//|
+//| :param int interface: the device interface number to allow CircuitPython to use
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_core_device_attach_kernel_driver(mp_obj_t self_in, mp_obj_t interface_in) {
+ usb_core_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t interface = mp_obj_get_int(interface_in);
+ common_hal_usb_core_device_attach_kernel_driver(self, interface);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_core_device_attach_kernel_driver_obj, usb_core_device_attach_kernel_driver);
+
+
+STATIC const mp_rom_map_elem_t usb_core_device_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_idVendor), MP_ROM_PTR(&usb_core_device_idVendor_obj) },
+ { MP_ROM_QSTR(MP_QSTR_idProduct), MP_ROM_PTR(&usb_core_device_idProduct_obj) },
+ { MP_ROM_QSTR(MP_QSTR_serial_number), MP_ROM_PTR(&usb_core_device_serial_number_obj) },
+ { MP_ROM_QSTR(MP_QSTR_product), MP_ROM_PTR(&usb_core_device_product_obj) },
+ { MP_ROM_QSTR(MP_QSTR_manufacturer), MP_ROM_PTR(&usb_core_device_manufacturer_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&usb_core_device_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&usb_core_device_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ctrl_transfer), MP_ROM_PTR(&usb_core_device_ctrl_transfer_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_is_kernel_driver_active), MP_ROM_PTR(&usb_core_device_is_kernel_driver_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_detach_kernel_driver), MP_ROM_PTR(&usb_core_device_detach_kernel_driver_obj) },
+ { MP_ROM_QSTR(MP_QSTR_attach_kernel_driver), MP_ROM_PTR(&usb_core_device_attach_kernel_driver_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_core_device_locals_dict, usb_core_device_locals_dict_table);
+
+const mp_obj_type_t usb_core_device_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Device,
+ .locals_dict = (mp_obj_t)&usb_core_device_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/usb/core/Device.h b/circuitpython/shared-bindings/usb/core/Device.h
new file mode 100644
index 0000000..c7086e9
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/core/Device.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
+
+#include "py/objarray.h"
+
+#include "shared-module/usb/core/Device.h"
+
+extern const mp_obj_type_t usb_core_device_type;
+
+bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t device_number);
+uint16_t common_hal_usb_core_device_get_idVendor(usb_core_device_obj_t *self);
+uint16_t common_hal_usb_core_device_get_idProduct(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_serial_number(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_product(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_get_manufacturer(usb_core_device_obj_t *self);
+mp_obj_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+mp_obj_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
+ mp_int_t bmRequestType, mp_int_t bRequest,
+ mp_int_t wValue, mp_int_t wIndex,
+ uint8_t *buffer, mp_int_t len, mp_int_t timeout);
+
+bool common_hal_usb_core_device_is_kernel_driver_active(usb_core_device_obj_t *self, mp_int_t interface);
+void common_hal_usb_core_device_detach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
+void common_hal_usb_core_device_attach_kernel_driver(usb_core_device_obj_t *self, mp_int_t interface);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CORE_DEVICE_H
diff --git a/circuitpython/shared-bindings/usb/core/__init__.c b/circuitpython/shared-bindings/usb/core/__init__.c
new file mode 100644
index 0000000..0e0d409
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/core/__init__.c
@@ -0,0 +1,193 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/objexcept.h"
+#include "py/misc.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb/core/__init__.h"
+#include "shared-bindings/usb/core/Device.h"
+
+//| """USB Core
+//|
+//| This is a subset of the PyUSB core module.
+//| """
+//|
+
+//| class USBError(OSError):
+//| """Catchall exception for USB related errors."""
+//| ...
+MP_DEFINE_USB_CORE_EXCEPTION(USBError, OSError)
+NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_usb_core_USBError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+//| class USBTimeoutError(USBError):
+//| """Raised when a USB transfer times out."""
+//| ...
+//|
+MP_DEFINE_USB_CORE_EXCEPTION(USBTimeoutError, usb_core_USBError)
+NORETURN void mp_raise_usb_core_USBTimeoutError(void) {
+ mp_raise_type(&mp_type_usb_core_USBTimeoutError);
+}
+
+
+//| def find(find_all=False, *, idVendor=None, idProduct=None):
+//| """Find the first device that matches the given requirements or, if
+//| find_all is True, return a generator of all matching devices.
+//|
+//| Returns None if no device matches.
+//| """
+//|
+typedef struct {
+ mp_obj_base_t base;
+ mp_int_t vid;
+ mp_int_t pid;
+ mp_int_t next_index;
+} usb_core_devices_obj_t;
+
+// This is an internal iterator type to use with find.
+STATIC mp_obj_t _next_device(usb_core_devices_obj_t *iter) {
+ // Brute force check all possible device numbers for one that matches.
+ usb_core_device_obj_t temp_device;
+ for (size_t i = iter->next_index; i < 256; i++) {
+ if (!common_hal_usb_core_device_construct(&temp_device, i)) {
+ continue;
+ }
+ if (iter->vid < 0x10000 && iter->vid != common_hal_usb_core_device_get_idVendor(&temp_device)) {
+ continue;
+ }
+ if (iter->pid < 0x10000 && iter->pid != common_hal_usb_core_device_get_idProduct(&temp_device)) {
+ continue;
+ }
+
+ // We passed the filters. Now make a properly allocated object to
+ // return to the user.
+ usb_core_device_obj_t *self = m_new_obj(usb_core_device_obj_t);
+ self->base.type = &usb_core_device_type;
+
+ common_hal_usb_core_device_construct(self, i);
+ iter->next_index = i + 1;
+ return MP_OBJ_FROM_PTR(self);
+ }
+ // Iter is done.
+ iter->next_index = 256;
+ return mp_const_none;
+}
+
+STATIC mp_obj_t usb_core_devices_iternext(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &usb_core_devices_type));
+ usb_core_devices_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t device = _next_device(self);
+ if (device != mp_const_none) {
+ return device;
+ }
+ return MP_OBJ_STOP_ITERATION;
+}
+
+const mp_obj_type_t usb_core_devices_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_USBDevices,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = usb_core_devices_iternext,
+ ),
+};
+
+STATIC mp_obj_t usb_core_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_find_all, ARG_idVendor, ARG_idProduct };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_find_all, MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_idVendor, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_idProduct, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const bool find_all = args[ARG_find_all].u_bool;
+ usb_core_devices_obj_t temp_iter;
+ temp_iter.base.type = &usb_core_devices_type;
+ temp_iter.next_index = 1;
+ if (!mp_obj_get_int_maybe(args[ARG_idVendor].u_obj, &temp_iter.vid)) {
+ temp_iter.vid = 0x10000;
+ }
+ if (!mp_obj_get_int_maybe(args[ARG_idProduct].u_obj, &temp_iter.pid)) {
+ temp_iter.pid = 0x10000;
+ }
+ if (find_all) {
+ // Copy the temp iter contents to a heap object before we return it.
+ // We could do this up front but GCC falsely detects that we may return
+ // the stack copy.
+ usb_core_devices_obj_t *iter = m_new_obj(usb_core_devices_obj_t);
+ memcpy(iter, &temp_iter, sizeof(usb_core_devices_obj_t));
+ return MP_OBJ_FROM_PTR(iter);
+ }
+ return _next_device(&temp_iter);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_find_obj, 0, usb_core_find);
+
+
+STATIC mp_rom_map_elem_t usb_core_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_dot_core) },
+ // Functions
+ { MP_ROM_QSTR(MP_QSTR_find), MP_OBJ_FROM_PTR(&usb_core_find_obj) },
+
+ // Classes
+ { MP_ROM_QSTR(MP_QSTR_Device), MP_OBJ_FROM_PTR(&usb_core_device_type) },
+
+ // Errors
+ { MP_ROM_QSTR(MP_QSTR_USBError), MP_OBJ_FROM_PTR(&mp_type_usb_core_USBError) },
+ { MP_ROM_QSTR(MP_QSTR_USBTimeoutError), MP_OBJ_FROM_PTR(&mp_type_usb_core_USBTimeoutError) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_core_module_globals, usb_core_module_globals_table);
+
+void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
+ bool is_subclass = kind & PRINT_EXC_SUBCLASS;
+ if (!is_subclass && (k == PRINT_EXC)) {
+ mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(usb_core_module_globals_table[0].value)));
+ mp_print_str(print, ".");
+ }
+ mp_obj_exception_print(print, o_in, kind);
+}
+
+const mp_obj_module_t usb_core_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_core_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb_dot_core, usb_core_module, CIRCUITPY_USB_HOST);
diff --git a/circuitpython/shared-bindings/usb/core/__init__.h b/circuitpython/shared-bindings/usb/core/__init__.h
new file mode 100644
index 0000000..2067c4c
--- /dev/null
+++ b/circuitpython/shared-bindings/usb/core/__init__.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#include "py/obj.h"
+
+extern const mp_obj_module_t usb_core_module;
+
+void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
+
+#define MP_DEFINE_USB_CORE_EXCEPTION(exc_name, base_name) \
+ const mp_obj_type_t mp_type_usb_core_##exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_##exc_name, \
+ .print = usb_core_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .attr = mp_obj_exception_attr, \
+ .parent = &mp_type_##base_name, \
+ };
+
+extern const mp_obj_type_t mp_type_usb_core_USBError;
+extern const mp_obj_type_t mp_type_usb_core_USBTimeoutError;
+
+NORETURN void mp_raise_usb_core_USBError(const compressed_string_t *fmt, ...);
+NORETURN void mp_raise_usb_core_USBTimeoutError(void);
+
+// Find is all Python object oriented so we don't need a separate common-hal API
+// for it. It uses the device common-hal instead.
diff --git a/circuitpython/shared-bindings/usb_cdc/Serial.c b/circuitpython/shared-bindings/usb_cdc/Serial.c
new file mode 100644
index 0000000..760efb6
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_cdc/Serial.c
@@ -0,0 +1,303 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/usb_cdc/Serial.h"
+#include "shared-bindings/util.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "supervisor/shared/translate.h"
+
+//| class Serial:
+//| """Receives cdc commands over USB"""
+//|
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `usb_cdc.Serial`.
+//| The available instances are in the ``usb_cdc.serials`` tuple."""
+//| ...
+//|
+//| def read(self, size: int = 1) -> bytes:
+//| """Read at most ``size`` bytes. If ``size`` exceeds the internal buffer size
+//| only the bytes in the buffer will be read. If `timeout` is > 0 or ``None``,
+//| and fewer than ``size`` bytes are available, keep waiting until the timeout
+//| expires or ``size`` bytes are available.
+//|
+//| :return: Data read
+//| :rtype: bytes"""
+//| ...
+//|
+//| def readinto(self, buf: WriteableBuffer) -> int:
+//| """Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
+//| that many bytes, subject to `timeout`. Otherwise, read at most ``len(buf)`` bytes.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: bytes"""
+//| ...
+//|
+//| def readline(self, size: int = -1) -> Optional[bytes]:
+//| r"""Read a line ending in a newline character ("\\n"), including the newline.
+//| Return everything readable if no newline is found and ``timeout`` is 0.
+//| Return ``None`` in case of error.
+//|
+//| This is a binary stream: the newline character "\\n" cannot be changed.
+//| If the host computer transmits "\\r" it will also be included as part of the line.
+//|
+//| :param int size: maximum number of characters to read. ``-1`` means as many as possible.
+//| :return: the line read
+//| :rtype: bytes or None"""
+//| ...
+//|
+//| def readlines(self) -> List[Optional[bytes]]:
+//| """Read multiple lines as a list, using `readline()`.
+//|
+//| .. warning:: If ``timeout`` is ``None``,
+//| `readlines()` will never return, because there is no way to indicate end of stream.
+//|
+//| :return: a list of the line read
+//| :rtype: list"""
+//| ...
+//|
+//| def write(self, buf: ReadableBuffer) -> int:
+//| """Write as many bytes as possible from the buffer of bytes.
+//|
+//| :return: the number of bytes written
+//| :rtype: int"""
+//| ...
+//|
+//| def flush(self) -> None:
+//| """Force out any unwritten bytes, waiting until they are written."""
+//| ...
+//|
+
+// These three methods are used by the shared stream methods.
+STATIC mp_uint_t usb_cdc_serial_read_stream(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ byte *buf = buf_in;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ return common_hal_usb_cdc_serial_read(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_cdc_serial_write_stream(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const byte *buf = buf_in;
+
+ return common_hal_usb_cdc_serial_write(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret = 0;
+ switch (request) {
+ case MP_IOCTL_POLL: {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_cdc_serial_get_in_waiting(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_cdc_serial_get_out_waiting(self) == 0) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ break;
+ }
+
+ case MP_STREAM_FLUSH:
+ common_hal_usb_cdc_serial_flush(self);
+ break;
+
+ default:
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+//| connected: bool
+//| """True if this Serial is connected to a host. (read-only)
+//|
+//| .. note:: The host is considered to be connected if it is asserting DTR (Data Terminal Ready).
+//| Most terminal programs and ``pyserial`` assert DTR when opening a serial connection.
+//| However, the C# ``SerialPort`` API does not. You must set ``SerialPort.DtrEnable``.
+//| """
+//|
+STATIC mp_obj_t usb_cdc_serial_get_connected(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_usb_cdc_serial_get_connected(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_connected_obj, usb_cdc_serial_get_connected);
+
+MP_PROPERTY_GETTER(usb_cdc_serial_connected_obj,
+ (mp_obj_t)&usb_cdc_serial_get_connected_obj);
+
+//| in_waiting: int
+//| """Returns the number of bytes waiting to be read on the USB serial input. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_in_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_in_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_in_waiting_obj, usb_cdc_serial_get_in_waiting);
+
+MP_PROPERTY_GETTER(usb_cdc_serial_in_waiting_obj,
+ (mp_obj_t)&usb_cdc_serial_get_in_waiting_obj);
+
+//| out_waiting: int
+//| """Returns the number of bytes waiting to be written on the USB serial output. (read-only)"""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_out_waiting(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_usb_cdc_serial_get_out_waiting(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_out_waiting_obj, usb_cdc_serial_get_out_waiting);
+
+MP_PROPERTY_GETTER(usb_cdc_serial_out_waiting_obj,
+ (mp_obj_t)&usb_cdc_serial_get_out_waiting_obj);
+
+//| def reset_input_buffer(self) -> None:
+//| """Clears any unread bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_input_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_input_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_input_buffer_obj, usb_cdc_serial_reset_input_buffer);
+
+//| def reset_output_buffer(self) -> None:
+//| """Clears any unwritten bytes."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_serial_reset_output_buffer(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_reset_output_buffer(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_output_buffer_obj, usb_cdc_serial_reset_output_buffer);
+
+//| timeout: Optional[float]
+//| """The initial value of `timeout` is ``None``. If ``None``, wait indefinitely to satisfy
+//| the conditions of a read operation. If 0, do not wait. If > 0, wait only ``timeout`` seconds."""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_timeout(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_float_t timeout = common_hal_usb_cdc_serial_get_timeout(self);
+ return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->timeout);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_timeout_obj, usb_cdc_serial_get_timeout);
+
+STATIC mp_obj_t usb_cdc_serial_set_timeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_set_timeout(self,
+ timeout_in == mp_const_none ? -1.0f : mp_obj_get_float(timeout_in));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_cdc_serial_set_timeout_obj, usb_cdc_serial_set_timeout);
+
+MP_PROPERTY_GETSET(usb_cdc_serial_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_get_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_set_timeout_obj);
+
+//| write_timeout: Optional[float]
+//| """The initial value of `write_timeout` is ``None``. If ``None``, wait indefinitely to finish
+//| writing all the bytes passed to ``write()``.If 0, do not wait.
+//| If > 0, wait only ``write_timeout`` seconds."""
+//|
+STATIC mp_obj_t usb_cdc_serial_get_write_timeout(mp_obj_t self_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_float_t write_timeout = common_hal_usb_cdc_serial_get_write_timeout(self);
+ return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->write_timeout);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_write_timeout_obj, usb_cdc_serial_get_write_timeout);
+
+STATIC mp_obj_t usb_cdc_serial_set_write_timeout(mp_obj_t self_in, mp_obj_t write_timeout_in) {
+ usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_cdc_serial_set_write_timeout(self,
+ write_timeout_in == mp_const_none ? -1.0f : mp_obj_get_float(write_timeout_in));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(usb_cdc_serial_set_write_timeout_obj, usb_cdc_serial_set_write_timeout);
+
+MP_PROPERTY_GETSET(usb_cdc_serial_write_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_get_write_timeout_obj,
+ (mp_obj_t)&usb_cdc_serial_set_write_timeout_obj);
+
+
+STATIC const mp_rom_map_elem_t usb_cdc_serial_locals_dict_table[] = {
+ // Standard stream methods.
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)},
+ { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)},
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+
+ // Other pyserial-inspired attributes.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&usb_cdc_serial_in_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_out_waiting), MP_ROM_PTR(&usb_cdc_serial_out_waiting_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_input_buffer_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_reset_output_buffer), MP_ROM_PTR(&usb_cdc_serial_reset_output_buffer_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&usb_cdc_serial_timeout_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write_timeout), MP_ROM_PTR(&usb_cdc_serial_write_timeout_obj) },
+
+ // Not in pyserial protocol.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_cdc_serial_connected_obj) },
+
+
+
+};
+STATIC MP_DEFINE_CONST_DICT(usb_cdc_serial_locals_dict, usb_cdc_serial_locals_dict_table);
+
+STATIC const mp_stream_p_t usb_cdc_serial_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = usb_cdc_serial_read_stream,
+ .write = usb_cdc_serial_write_stream,
+ .ioctl = usb_cdc_serial_ioctl_stream,
+ .is_text = false,
+ .pyserial_read_compatibility = true,
+ .pyserial_readinto_compatibility = true,
+ .pyserial_dont_return_none_compatibility = true,
+};
+
+const mp_obj_type_t usb_cdc_serial_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Serial,
+ .locals_dict = (mp_obj_dict_t *)&usb_cdc_serial_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &usb_cdc_serial_stream_p,
+ ),
+};
diff --git a/circuitpython/shared-bindings/usb_cdc/Serial.h b/circuitpython/shared-bindings/usb_cdc/Serial.h
new file mode 100644
index 0000000..cdf5c3a
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_cdc/Serial.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
+
+#include "shared-module/usb_cdc/Serial.h"
+
+extern const mp_obj_type_t usb_cdc_serial_type;
+
+extern size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode);
+extern size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode);
+
+extern uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self);
+
+extern void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self);
+extern uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self);
+
+extern uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self);
+
+extern bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self);
+
+extern mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self);
+extern void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout);
+
+extern mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self);
+extern void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC_SERIAL_H
diff --git a/circuitpython/shared-bindings/usb_cdc/__init__.c b/circuitpython/shared-bindings/usb_cdc/__init__.c
new file mode 100644
index 0000000..eabe26a
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_cdc/__init__.c
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbertfor Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_cdc/__init__.h"
+#include "shared-bindings/usb_cdc/Serial.h"
+
+#include "py/runtime.h"
+
+//| """USB CDC Serial streams
+//|
+//| The `usb_cdc` module allows access to USB CDC (serial) communications.
+//|
+//| On Windows, each `Serial` is visible as a separate COM port. The ports will often
+//| be assigned consecutively, `console` first, but this is not always true.
+//|
+//| On Linux, the ports are typically ``/dev/ttyACM0`` and ``/dev/ttyACM1``.
+//| The `console` port will usually be first.
+//|
+//| On MacOS, the ports are typically ``/dev/cu.usbmodem<something>``. The something
+//| varies based on the USB bus and port used. The `console` port will usually be first.
+//| """
+//|
+//| console: Optional[Serial]
+//| """The `console` `Serial` object is used for the REPL, and for `sys.stdin` and `sys.stdout`.
+//| `console` is ``None`` if disabled.
+//|
+//| However, note that `sys.stdin` and `sys.stdout` are text-based streams,
+//| and the `console` object is a binary stream.
+//| You do not normally need to write to `console` unless you want to write binary data.
+//| """
+//|
+//| data: Optional[Serial]
+//| """A `Serial` object that can be used to send and receive binary data to and from
+//| the host.
+//| Note that `data` is *disabled* by default. ``data`` is ``None`` if disabled."""
+
+//| def disable() -> None:
+//| """Do not present any USB CDC device to the host.
+//| Can be called in ``boot.py``, before USB is connected.
+//| Equivalent to ``usb_cdc.enable(console=False, data=False)``."""
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_disable(void) {
+ if (!common_hal_usb_cdc_disable()) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(usb_cdc_disable_obj, usb_cdc_disable);
+
+//| def enable(*, console: bool = True, data: bool = False) -> None:
+//| """Enable or disable each CDC device. Can be called in ``boot.py``, before USB is connected.
+//|
+//| :param console bool: Enable or disable the `console` USB serial device.
+//| True to enable; False to disable. Enabled by default.
+//| :param data bool: Enable or disable the `data` USB serial device.
+//| True to enable; False to disable. *Disabled* by default.
+//|
+//| If you enable too many devices at once, you will run out of USB endpoints.
+//| The number of available endpoints varies by microcontroller.
+//| CircuitPython will go into safe mode after running boot.py to inform you if
+//| not enough endpoints are available.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_cdc_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_console, ARG_data };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_console, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true } },
+ { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false } },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (!common_hal_usb_cdc_enable(args[ARG_console].u_bool, args[ARG_data].u_bool)) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_cdc_enable_obj, 0, usb_cdc_enable);
+
+// The usb_cdc module dict is mutable so that .console and .data may
+// be set to a Serial or to None depending on whether they are enabled or not.
+static mp_map_elem_t usb_cdc_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_cdc) },
+ { MP_ROM_QSTR(MP_QSTR_Serial), MP_OBJ_FROM_PTR(&usb_cdc_serial_type) },
+ { MP_ROM_QSTR(MP_QSTR_console), mp_const_none },
+ { MP_ROM_QSTR(MP_QSTR_data), mp_const_none },
+ { MP_ROM_QSTR(MP_QSTR_disable), MP_OBJ_FROM_PTR(&usb_cdc_disable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_cdc_enable_obj) },
+};
+
+static MP_DEFINE_MUTABLE_DICT(usb_cdc_module_globals, usb_cdc_module_globals_table);
+
+const mp_obj_module_t usb_cdc_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_cdc_module_globals,
+};
+
+static void set_module_dict_entry(mp_obj_t key_qstr, mp_obj_t serial_obj) {
+ mp_map_elem_t *elem = mp_map_lookup(&usb_cdc_module_globals.map, key_qstr, MP_MAP_LOOKUP);
+ if (elem) {
+ elem->value = serial_obj;
+ }
+}
+
+void usb_cdc_set_console(mp_obj_t serial_obj) {
+ set_module_dict_entry(MP_ROM_QSTR(MP_QSTR_console), serial_obj);
+}
+
+void usb_cdc_set_data(mp_obj_t serial_obj) {
+ set_module_dict_entry(MP_ROM_QSTR(MP_QSTR_data), serial_obj);
+}
+
+MP_REGISTER_MODULE(MP_QSTR_usb_cdc, usb_cdc_module, CIRCUITPY_USB_CDC);
diff --git a/circuitpython/shared-bindings/usb_cdc/__init__.h b/circuitpython/shared-bindings/usb_cdc/__init__.h
new file mode 100644
index 0000000..0a517f4
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_cdc/__init__.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
+
+#include "shared-module/usb_cdc/__init__.h"
+
+// Set the module dict entries.
+void usb_cdc_set_console(mp_obj_t serial_obj);
+void usb_cdc_set_data(mp_obj_t serial_obj);
+
+extern bool common_hal_usb_cdc_disable(void);
+extern bool common_hal_usb_cdc_enable(bool console, bool data);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_CDC___INIT___H
diff --git a/circuitpython/shared-bindings/usb_hid/Device.c b/circuitpython/shared-bindings/usb_hid/Device.c
new file mode 100644
index 0000000..2741013
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_hid/Device.c
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "shared-bindings/usb_hid/Device.h"
+#include "py/runtime.h"
+
+//| class Device:
+//| """HID Device specification"""
+//|
+//| def __init__(self, *, report_descriptor: ReadableBuffer, usage_page: int, usage: int, report_ids: Sequence[int], in_report_lengths: Sequence[int], out_report_lengths: Sequence[int]) -> None:
+//| """Create a description of a USB HID device. The actual device is created when you
+//| pass a `Device` to `usb_hid.enable()`.
+//|
+//| :param ReadableBuffer report_descriptor: The USB HID Report descriptor bytes. The descriptor is not
+//| not verified for correctness; it is up to you to make sure it is not malformed.
+//| :param int usage_page: The Usage Page value from the descriptor. Must match what is in the descriptor.
+//| :param int usage: The Usage value from the descriptor. Must match what is in the descriptor.
+//| :param Sequence[int] report_ids: Sequence of report ids used by the descriptor.
+//| If the ``report_descriptor`` does not specify any report IDs, use ``(0,)``.
+//| :param Sequence[int] in_report_lengths: Sequence of sizes in bytes of the HID reports sent to the host.
+//| The sizes are in order of the ``report_ids``.
+//| Use a size of ``0`` for a report that is not an IN report.
+//| "IN" is with respect to the host.
+//| :param int out_report_lengths: Sequence of sizes in bytes of the HID reports received from the host.
+//| The sizes are in order of the ``report_ids``.
+//| Use a size of ``0`` for a report that is not an OUT report.
+//| "OUT" is with respect to the host.
+//|
+//| ``report_ids``, ``in_report_lengths``, and ``out_report_lengths`` must all have the
+//| same number of elements.
+//|
+//| Here is an example of a `Device` with a descriptor that specifies two report IDs, 3 and 4.
+//| Report ID 3 sends an IN report of length 5, and receives an OUT report of length 6.
+//| Report ID 4 sends an IN report of length 2, and does not receive an OUT report::
+//|
+//| device = usb_hid.Device(
+//| descriptor=b"...", # Omitted for brevity.
+//| report_ids=(3, 4),
+//| in_report_lengths=(5, 2),
+//| out_report_lengths=(6, 0),
+//| )
+//| """
+//| ...
+//|
+//| KEYBOARD: Device
+//| """Standard keyboard device supporting keycodes 0x00-0xDD, modifiers 0xE-0xE7, and five LED indicators.
+//| Uses Report ID 1 for its IN and OUT reports.
+//| """
+//|
+//| MOUSE: Device
+//| """Standard mouse device supporting five mouse buttons, X and Y relative movements from -127 to 127
+//| in each report, and a relative mouse wheel change from -127 to 127 in each report.
+//| Uses Report ID 2 for its IN report.
+//| """
+//|
+//| CONSUMER_CONTROL: Device
+//| """Consumer Control device supporting sent values from 1-652, with no rollover.
+//| Uses Report ID 3 for its IN report."""
+//|
+
+STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ usb_hid_device_obj_t *self = m_new_obj(usb_hid_device_obj_t);
+ self->base.type = &usb_hid_device_type;
+ enum { ARG_report_descriptor, ARG_usage_page, ARG_usage, ARG_report_ids, ARG_in_report_lengths, ARG_out_report_lengths };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_report_descriptor, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_usage_page, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_usage, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_report_ids, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_in_report_lengths, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_out_report_lengths, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t descriptor_bufinfo;
+ mp_get_buffer_raise(args[ARG_report_descriptor].u_obj, &descriptor_bufinfo, MP_BUFFER_READ);
+ mp_obj_t descriptor = mp_obj_new_bytearray(descriptor_bufinfo.len, descriptor_bufinfo.buf);
+
+ const mp_int_t usage_page_arg = args[ARG_usage_page].u_int;
+ mp_arg_validate_int_range(usage_page_arg, 1, 0xFFFF, MP_QSTR_usage_page);
+ const uint16_t usage_page = usage_page_arg;
+
+ const mp_int_t usage_arg = args[ARG_usage].u_int;
+ mp_arg_validate_int_range(usage_arg, 1, 0xFFFF, MP_QSTR_usage);
+ const uint16_t usage = usage_arg;
+
+ mp_obj_t report_ids = args[ARG_report_ids].u_obj;
+ mp_obj_t in_report_lengths = args[ARG_in_report_lengths].u_obj;
+ mp_obj_t out_report_lengths = args[ARG_out_report_lengths].u_obj;
+
+ size_t report_ids_count = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(report_ids));
+ if (report_ids_count < 1) {
+ mp_raise_ValueError_varg(translate("%q length must be >= 1"), MP_QSTR_report_ids);
+ }
+
+ if ((size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(in_report_lengths)) != report_ids_count ||
+ (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(out_report_lengths)) != report_ids_count) {
+ mp_raise_ValueError_varg(translate("%q, %q, and %q must all be the same length"),
+ MP_QSTR_report_ids, MP_QSTR_in_report_lengths, MP_QSTR_out_report_lengths);
+ }
+
+ uint8_t report_ids_array[report_ids_count];
+ uint8_t in_report_lengths_array[report_ids_count];
+ uint8_t out_report_lengths_array[report_ids_count];
+
+ // Validate the ids and lengths are all integers in range.
+ for (size_t i = 0; i < report_ids_count; i++) {
+ mp_obj_t i_obj = MP_OBJ_NEW_SMALL_INT(i);
+
+ report_ids_array[i] = (uint8_t)mp_arg_validate_int_range(
+ // It's not the actual argument that's out of range, but its elements.
+ // But the error message is close enough.
+ MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(report_ids, i_obj, MP_OBJ_SENTINEL)),
+ 0, 255, MP_QSTR_report_ids);
+
+ in_report_lengths_array[i] = (uint8_t)mp_arg_validate_int_range(
+ MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(in_report_lengths, i_obj, MP_OBJ_SENTINEL)),
+ 0, 255, MP_QSTR_in_report_lengths);
+
+ out_report_lengths_array[i] = (uint8_t)mp_arg_validate_int_range(
+ MP_OBJ_SMALL_INT_VALUE(mp_obj_subscr(out_report_lengths, i_obj, MP_OBJ_SENTINEL)),
+ 0, 255, MP_QSTR_out_report_lengths);
+ }
+
+ if (report_ids_array[0] == 0 && report_ids_count > 1) {
+ mp_raise_ValueError_varg(translate("%q with a report ID of 0 must be of length 1"), MP_QSTR_report_ids);
+ }
+
+ common_hal_usb_hid_device_construct(
+ self, descriptor, usage_page, usage, report_ids_count, report_ids_array, in_report_lengths_array, out_report_lengths_array);
+ return (mp_obj_t)self;
+}
+
+
+//| def send_report(self, buf: ReadableBuffer, report_id: Optional[int] = None) -> None:
+//| """Send an HID report. If the device descriptor specifies zero or one report id's,
+//| you can supply `None` (the default) as the value of ``report_id``.
+//| Otherwise you must specify which report id to use when sending the report.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_hid_device_send_report(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_buf, ARG_report_id };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_report_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ // -1 asks common_hal to determine the report id if possible.
+ mp_int_t report_id_arg = -1;
+ if (args[ARG_report_id].u_obj != mp_const_none) {
+ report_id_arg = mp_obj_int_get_checked(args[ARG_report_id].u_obj);
+ }
+ const uint8_t report_id = common_hal_usb_hid_device_validate_report_id(self, report_id_arg);
+
+ common_hal_usb_hid_device_send_report(self, ((uint8_t *)bufinfo.buf), bufinfo.len, report_id);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_device_send_report_obj, 1, usb_hid_device_send_report);
+
+//| def get_last_received_report(self, report_id: Optional[int] = None) -> bytes:
+//| """Get the last received HID OUT or feature report for the given report ID.
+//| The report ID may be omitted if there is no report ID, or only one report ID.
+//| Return `None` if nothing received.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_hid_device_get_last_received_report(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_report_id };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_report_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t report_id_arg = -1;
+ if (args[ARG_report_id].u_obj != mp_const_none) {
+ report_id_arg = mp_obj_int_get_checked(args[ARG_report_id].u_obj);
+ }
+ const uint8_t report_id = common_hal_usb_hid_device_validate_report_id(self, report_id_arg);
+
+ return common_hal_usb_hid_device_get_last_received_report(self, report_id);
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_device_get_last_received_report_obj, 1, usb_hid_device_get_last_received_report);
+
+//| last_received_report: bytes
+//| """The HID OUT report as a `bytes` (read-only). `None` if nothing received.
+//| Same as `get_last_received_report()` with no argument.
+//|
+//| Deprecated: will be removed in CircutPython 8.0.0. Use `get_last_received_report()` instead.
+//| """
+//|
+STATIC mp_obj_t usb_hid_device_obj_get_last_received_report_property(mp_obj_t self_in) {
+ usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // Get the sole report_id, if there is one.
+ const uint8_t report_id = common_hal_usb_hid_device_validate_report_id(self, -1);
+ return common_hal_usb_hid_device_get_last_received_report(self, report_id);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_last_received_report_property_obj, usb_hid_device_obj_get_last_received_report_property);
+
+MP_PROPERTY_GETTER(usb_hid_device_last_received_report_obj,
+ (mp_obj_t)&usb_hid_device_get_last_received_report_property_obj);
+
+//| usage_page: int
+//| """The device usage page identifier, which designates a category of device. (read-only)"""
+//|
+STATIC mp_obj_t usb_hid_device_obj_get_usage_page(mp_obj_t self_in) {
+ usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_hid_device_get_usage_page(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_usage_page_obj, usb_hid_device_obj_get_usage_page);
+
+MP_PROPERTY_GETTER(usb_hid_device_usage_page_obj,
+ (mp_obj_t)&usb_hid_device_get_usage_page_obj);
+
+//| usage: int
+//| """The device usage identifier, which designates a specific kind of device. (read-only)
+//|
+//| For example, Keyboard is 0x06 within the generic desktop usage page 0x01.
+//| Mouse is 0x02 within the same usage page."""
+//|
+STATIC mp_obj_t usb_hid_device_obj_get_usage(mp_obj_t self_in) {
+ usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_hid_device_get_usage(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_usage_obj,
+ usb_hid_device_obj_get_usage);
+
+MP_PROPERTY_GETTER(usb_hid_device_usage_obj,
+ (mp_obj_t)&usb_hid_device_get_usage_obj);
+
+STATIC const mp_rom_map_elem_t usb_hid_device_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_send_report), MP_ROM_PTR(&usb_hid_device_send_report_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_last_received_report), MP_ROM_PTR(&usb_hid_device_get_last_received_report_obj) },
+ { MP_ROM_QSTR(MP_QSTR_last_received_report), MP_ROM_PTR(&usb_hid_device_last_received_report_obj) },
+ { MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj) },
+ { MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&usb_hid_device_keyboard_obj) },
+ { MP_ROM_QSTR(MP_QSTR_MOUSE), MP_ROM_PTR(&usb_hid_device_mouse_obj) },
+ { MP_ROM_QSTR(MP_QSTR_CONSUMER_CONTROL), MP_ROM_PTR(&usb_hid_device_consumer_control_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_hid_device_locals_dict, usb_hid_device_locals_dict_table);
+
+const mp_obj_type_t usb_hid_device_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Device,
+ .make_new = usb_hid_device_make_new,
+ .locals_dict = (mp_obj_t)&usb_hid_device_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/usb_hid/Device.h b/circuitpython/shared-bindings/usb_hid/Device.h
new file mode 100644
index 0000000..dde66e2
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_hid/Device.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H
+
+#include "py/objarray.h"
+
+#include "shared-module/usb_hid/Device.h"
+
+extern const mp_obj_type_t usb_hid_device_type;
+
+void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, mp_obj_t report_descriptor, uint16_t usage_page, uint16_t usage, size_t report_ids_count,uint8_t *report_ids, uint8_t *in_report_lengths, uint8_t *out_report_lengths);
+void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len, uint8_t report_id);
+mp_obj_t common_hal_usb_hid_device_get_last_received_report(usb_hid_device_obj_t *self, uint8_t report_id);
+uint16_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self);
+uint16_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self);
+uint8_t common_hal_usb_hid_device_validate_report_id(usb_hid_device_obj_t *self, mp_int_t report_id);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H
diff --git a/circuitpython/shared-bindings/usb_hid/__init__.c b/circuitpython/shared-bindings/usb_hid/__init__.c
new file mode 100644
index 0000000..3922ded
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_hid/__init__.c
@@ -0,0 +1,186 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_hid/__init__.h"
+#include "shared-bindings/usb_hid/Device.h"
+
+//| """USB Human Interface Device
+//|
+//| The `usb_hid` module allows you to output data as a HID device."""
+//|
+
+//| devices: Tuple[Device, ...]
+//| """Tuple of all active HID device interfaces.
+//| The default set of devices is ``Device.KEYBOARD, Device.MOUSE, Device.CONSUMER_CONTROL``,
+//| On boards where `usb_hid` is disabled by default, `devices` is an empty tuple.
+//|
+//| If a boot device is enabled by `usb_hid.enable()`, *and* the host has requested a boot device,
+//| the `devices` tuple is **replaced** when ``code.py`` starts with a single-element tuple
+//| containing a `Device` that describes the boot device chosen (keyboard or mouse).
+//| The request for a boot device overrides any other HID devices.
+//| """
+//|
+
+//| def disable() -> None:
+//| """Do not present any USB HID devices to the host computer.
+//| Can be called in ``boot.py``, before USB is connected.
+//| The HID composite device is normally enabled by default,
+//| but on some boards with limited endpoints, including STM32F4,
+//| it is disabled by default. You must turn off another USB device such
+//| as `usb_cdc` or `storage` to free up endpoints for use by `usb_hid`.
+//| """
+//|
+STATIC mp_obj_t usb_hid_disable(void) {
+ if (!common_hal_usb_hid_disable()) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(usb_hid_disable_obj, usb_hid_disable);
+
+//| def enable(devices: Optional[Sequence[Device]], boot_device: int = 0) -> None:
+//| """Specify which USB HID devices that will be available.
+//| Can be called in ``boot.py``, before USB is connected.
+//|
+//| :param Sequence devices: `Device` objects.
+//| If `devices` is empty, HID is disabled. The order of the ``Devices``
+//| may matter to the host. For instance, for MacOS, put the mouse device
+//| before any Gamepad or Digitizer HID device or else it will not work.
+//| :param int boot_device: If non-zero, inform the host that support for a
+//| a boot HID device is available.
+//| If ``boot_device=1``, a boot keyboard is available.
+//| If ``boot_device=2``, a boot mouse is available. No other values are allowed.
+//| See below.
+//|
+//| If you enable too many devices at once, you will run out of USB endpoints.
+//| The number of available endpoints varies by microcontroller.
+//| CircuitPython will go into safe mode after running ``boot.py`` to inform you if
+//| not enough endpoints are available.
+//|
+//| **Boot Devices**
+//|
+//| Boot devices implement a fixed, predefined report descriptor, defined in
+//| https://www.usb.org/sites/default/files/hid1_12.pdf, Appendix B. A USB host
+//| can request to use the boot device if the USB device says it is available.
+//| Usually only a BIOS or other kind of limited-functionality
+//| host needs boot keyboard support.
+//|
+//| For example, to make a boot keyboard available, you can use this code::
+//|
+//| usb_hid.enable((Device.KEYBOARD), boot_device=1) # 1 for a keyboard
+//|
+//| If the host requests the boot keyboard, the report descriptor provided by `Device.KEYBOARD`
+//| will be ignored, and the predefined report descriptor will be used.
+//| But if the host does not request the boot keyboard,
+//| the descriptor provided by `Device.KEYBOARD` will be used.
+//|
+//| The HID boot device must usually be the first or only device presented by CircuitPython.
+//| The HID device will be USB interface number 0.
+//| To make sure it is the first device, disable other USB devices, including CDC and MSC (CIRCUITPY).
+//| If you specify a non-zero ``boot_device``, and it is not the first device, CircuitPython
+//| will enter safe mode to report this error.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_hid_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_devices, ARG_boot_device };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_devices, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_boot_device, MP_ARG_INT, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t devices = args[ARG_devices].u_obj;
+ const mp_int_t len = mp_obj_get_int(mp_obj_len(devices));
+ for (mp_int_t i = 0; i < len; i++) {
+ mp_obj_t item = mp_obj_subscr(devices, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL);
+ if (!mp_obj_is_type(item, &usb_hid_device_type)) {
+ mp_raise_ValueError_varg(translate("non-Device in %q"), MP_QSTR_devices);
+ }
+ }
+
+ uint8_t boot_device =
+ (uint8_t)mp_arg_validate_int_range(args[ARG_boot_device].u_int, 0, 2, MP_QSTR_boot_device);
+
+ if (!common_hal_usb_hid_enable(devices, boot_device)) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(usb_hid_enable_obj, 1, usb_hid_enable);
+
+//| def get_boot_device() -> int:
+//| """
+//| :return: the boot device requested by the host, if any.
+//| Returns 0 if the host did not request a boot device, or if `usb_hid.enable()`
+//| was called with ``boot_device=0``, the default, which disables boot device support.
+//| If the host did request a boot device,
+//| returns the value of ``boot_device`` set in `usb_hid.enable()`:
+//| ``1`` for a boot keyboard, or ``2`` for boot mouse.
+//| However, the standard devices provided by CircuitPython, `Device.KEYBOARD` and `Device.MOUSE`,
+//| describe reports that match the boot device reports, so you don't need to check this
+//| if you are using those devices.
+//| :rtype int:
+//| """
+//|
+STATIC mp_obj_t usb_hid_get_boot_device(void) {
+ return MP_OBJ_NEW_SMALL_INT(common_hal_usb_hid_get_boot_device());
+}
+MP_DEFINE_CONST_FUN_OBJ_0(usb_hid_get_boot_device_obj, usb_hid_get_boot_device);
+
+// usb_hid.devices is set once the usb devices are determined, after boot.py runs.
+STATIC mp_map_elem_t usb_hid_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid) },
+ { MP_ROM_QSTR(MP_QSTR_Device), MP_OBJ_FROM_PTR(&usb_hid_device_type) },
+ { MP_ROM_QSTR(MP_QSTR_devices), mp_const_none },
+ { MP_ROM_QSTR(MP_QSTR_disable), MP_OBJ_FROM_PTR(&usb_hid_disable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_hid_enable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_boot_device), MP_OBJ_FROM_PTR(&usb_hid_get_boot_device_obj) },
+};
+
+STATIC MP_DEFINE_MUTABLE_DICT(usb_hid_module_globals, usb_hid_module_globals_table);
+
+const mp_obj_module_t usb_hid_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_hid_module_globals,
+};
+
+void usb_hid_set_devices(mp_obj_t devices) {
+ mp_map_elem_t *elem =
+ mp_map_lookup(&usb_hid_module_globals.map, MP_ROM_QSTR(MP_QSTR_devices), MP_MAP_LOOKUP);
+ if (elem) {
+ elem->value = devices;
+ }
+}
+
+MP_REGISTER_MODULE(MP_QSTR_usb_hid, usb_hid_module, CIRCUITPY_USB_HID);
diff --git a/circuitpython/shared-bindings/usb_hid/__init__.h b/circuitpython/shared-bindings/usb_hid/__init__.h
new file mode 100644
index 0000000..feaeed2
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_hid/__init__.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_BINDINGS_USB_HID_H
+#define SHARED_BINDINGS_USB_HID_H
+
+#include "py/obj.h"
+#include "py/objtuple.h"
+#include "shared-module/usb_hid/__init__.h"
+
+extern mp_obj_tuple_t common_hal_usb_hid_devices;
+
+void usb_hid_set_devices(mp_obj_t devices);
+
+bool common_hal_usb_hid_disable(void);
+bool common_hal_usb_hid_enable(const mp_obj_t devices_seq, uint8_t boot_device);
+uint8_t common_hal_usb_hid_get_boot_device(void);
+
+#endif // SHARED_BINDINGS_USB_HID_H
diff --git a/circuitpython/shared-bindings/usb_host/Port.c b/circuitpython/shared-bindings/usb_host/Port.c
new file mode 100644
index 0000000..8f54246
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_host/Port.c
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "shared-bindings/usb_host/Port.h"
+#include "shared-bindings/util.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+//| class Port:
+//| """USB host port. Also known as a root hub port."""
+//|
+//| def __init__(self, dp: microcontroller.Pin, dm: microcontroller.Pin) -> None:
+//| """Create a USB host port on the given pins. Access attached devices
+//| through the `usb` module. Keep this object referenced while
+//| interacting with devices, otherwise they will be disconnected.
+//|
+//| :param ~microcontroller.Pin dp: The data plus pin
+//| :param ~microcontroller.Pin dm: The data minus pin
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_host_port_make_new(const mp_obj_type_t *type,
+ size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 2, 2, false);
+
+ const mcu_pin_obj_t *dp = validate_obj_is_free_pin(args[0]);
+ const mcu_pin_obj_t *dm = validate_obj_is_free_pin(args[1]);
+
+ usb_host_port_obj_t *self = m_new_obj(usb_host_port_obj_t);
+ self->base.type = &usb_host_port_type;
+ common_hal_usb_host_port_construct(self, dp, dm);
+
+ return (mp_obj_t)self;
+}
+
+//| def deinit(self) -> None:
+//| """Turn off the USB host port and release the pins for other use."""
+//| ...
+//|
+STATIC mp_obj_t usb_host_port_obj_deinit(mp_obj_t self_in) {
+ usb_host_port_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_usb_host_port_deinit(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(usb_host_port_deinit_obj, usb_host_port_obj_deinit);
+
+//| def __enter__(self) -> Port:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t usb_host_port_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_usb_host_port_deinit(MP_OBJ_TO_PTR(args[0]));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(usb_host_port_obj___exit___obj, 4, 4, usb_host_port_obj___exit__);
+
+STATIC const mp_rom_map_elem_t usb_host_port_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_host_port_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&usb_host_port_obj___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_host_port_locals_dict, usb_host_port_locals_dict_table);
+
+const mp_obj_type_t usb_host_port_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Port,
+ .make_new = usb_host_port_make_new,
+ .locals_dict = (mp_obj_t)&usb_host_port_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/usb_host/Port.h b/circuitpython/shared-bindings/usb_host/Port.h
new file mode 100644
index 0000000..68645d1
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_host/Port.h
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
+
+#include "py/objarray.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+
+#include "common-hal/usb_host/Port.h"
+
+extern const mp_obj_type_t usb_host_port_type;
+
+void common_hal_usb_host_port_construct(usb_host_port_obj_t *self, const mcu_pin_obj_t *dp, const mcu_pin_obj_t *dm);
+void common_hal_usb_host_port_deinit(usb_host_port_obj_t *self);
+bool common_hal_usb_host_port_deinited(usb_host_port_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_HOST_PORT_H
diff --git a/circuitpython/shared-bindings/usb_host/__init__.c b/circuitpython/shared-bindings/usb_host/__init__.c
new file mode 100644
index 0000000..c689a25
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_host/__init__.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/mphal.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_host/__init__.h"
+#include "shared-bindings/usb_host/Port.h"
+
+//| """USB Host
+//|
+//| The `usb_host` module allows you to manage USB host ports. To communicate
+//| with devices use the `usb` module that is a subset of PyUSB's API.
+//| """
+//|
+
+STATIC mp_map_elem_t usb_host_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usb_host) },
+ { MP_ROM_QSTR(MP_QSTR_Port), MP_OBJ_FROM_PTR(&usb_host_port_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(usb_host_module_globals, usb_host_module_globals_table);
+
+const mp_obj_module_t usb_host_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_host_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb_host, usb_host_module, CIRCUITPY_USB_HOST);
diff --git a/circuitpython/shared-bindings/usb_host/__init__.h b/circuitpython/shared-bindings/usb_host/__init__.h
new file mode 100644
index 0000000..d672285
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_host/__init__.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
diff --git a/circuitpython/shared-bindings/usb_midi/PortIn.c b/circuitpython/shared-bindings/usb_midi/PortIn.c
new file mode 100644
index 0000000..0056a08
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/PortIn.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/usb_midi/PortIn.h"
+#include "shared-bindings/util.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "supervisor/shared/translate.h"
+
+//| class PortIn:
+//| """Receives midi commands over USB"""
+//|
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `usb_midi.PortIn`.
+//|
+//| PortIn objects are constructed for every corresponding entry in the USB
+//| descriptor and added to the ``usb_midi.ports`` tuple."""
+//| ...
+//|
+
+// These are standard stream methods. Code is in py/stream.c.
+//
+//| def read(self, nbytes: Optional[int] = None) -> Optional[bytes]:
+//| """Read characters. If ``nbytes`` is specified then read at most that many
+//| bytes. Otherwise, read everything that arrives until the connection
+//| times out. Providing the number of bytes expected is highly recommended
+//| because it will be faster.
+//|
+//| :return: Data read
+//| :rtype: bytes or None"""
+//| ...
+//|
+//| def readinto(self, buf: WriteableBuffer, nbytes: Optional[int] = None) -> Optional[bytes]:
+//| """Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
+//| that many bytes. Otherwise, read at most ``len(buf)`` bytes.
+//|
+//| :return: number of bytes read and stored into ``buf``
+//| :rtype: bytes or None"""
+//| ...
+//|
+
+// These three methods are used by the shared stream methods.
+STATIC mp_uint_t usb_midi_portin_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
+ usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ byte *buf = buf_in;
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ return common_hal_usb_midi_portin_read(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_RD) && common_hal_usb_midi_portin_bytes_available(self) > 0) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_rom_map_elem_t usb_midi_portin_locals_dict_table[] = {
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(usb_midi_portin_locals_dict, usb_midi_portin_locals_dict_table);
+
+STATIC const mp_stream_p_t usb_midi_portin_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = usb_midi_portin_read,
+ .write = NULL,
+ .ioctl = usb_midi_portin_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t usb_midi_portin_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_PortIn,
+ .locals_dict = (mp_obj_dict_t *)&usb_midi_portin_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &usb_midi_portin_stream_p,
+ ),
+};
diff --git a/circuitpython/shared-bindings/usb_midi/PortIn.h b/circuitpython/shared-bindings/usb_midi/PortIn.h
new file mode 100644
index 0000000..58d017f
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/PortIn.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H
+
+#include "shared-module/usb_midi/PortIn.h"
+
+extern const mp_obj_type_t usb_midi_portin_type;
+
+// Read characters.
+extern size_t common_hal_usb_midi_portin_read(usb_midi_portin_obj_t *self,
+ uint8_t *data, size_t len, int *errcode);
+
+extern uint32_t common_hal_usb_midi_portin_bytes_available(usb_midi_portin_obj_t *self);
+extern void common_hal_usb_midi_portin_clear_buffer(usb_midi_portin_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTIN_H
diff --git a/circuitpython/shared-bindings/usb_midi/PortOut.c b/circuitpython/shared-bindings/usb_midi/PortOut.c
new file mode 100644
index 0000000..c468401
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/PortOut.c
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "shared-bindings/usb_midi/PortOut.h"
+#include "shared-bindings/util.h"
+
+#include "py/ioctl.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "supervisor/shared/translate.h"
+
+//| class PortOut:
+//| """Sends midi messages to a computer over USB"""
+//|
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `usb_midi.PortOut`.
+//|
+//| PortOut objects are constructed for every corresponding entry in the USB
+//| descriptor and added to the ``usb_midi.ports`` tuple."""
+//|
+
+// These are standard stream methods. Code is in py/stream.c.
+//
+//| def write(self, buf: ReadableBuffer) -> Optional[int]:
+//| """Write the buffer of bytes to the bus.
+//|
+//| :return: the number of bytes written
+//| :rtype: int or None"""
+//| ...
+//|
+
+STATIC mp_uint_t usb_midi_portout_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
+ usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const byte *buf = buf_in;
+
+ return common_hal_usb_midi_portout_write(self, buf, size, errcode);
+}
+
+STATIC mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_IOCTL_POLL_WR) && common_hal_usb_midi_portout_ready_to_tx(self)) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_rom_map_elem_t usb_midi_portout_locals_dict_table[] = {
+ // Standard stream methods.
+ { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(usb_midi_portout_locals_dict, usb_midi_portout_locals_dict_table);
+
+STATIC const mp_stream_p_t usb_midi_portout_stream_p = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream)
+ .read = NULL,
+ .write = usb_midi_portout_write,
+ .ioctl = usb_midi_portout_ioctl,
+ .is_text = false,
+};
+
+const mp_obj_type_t usb_midi_portout_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_PortOut,
+ .locals_dict = (mp_obj_dict_t *)&usb_midi_portout_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &usb_midi_portout_stream_p,
+ ),
+};
diff --git a/circuitpython/shared-bindings/usb_midi/PortOut.h b/circuitpython/shared-bindings/usb_midi/PortOut.h
new file mode 100644
index 0000000..7d8a014
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/PortOut.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H
+
+#include "shared-module/usb_midi/PortOut.h"
+
+extern const mp_obj_type_t usb_midi_portout_type;
+
+// Write characters. len is in characters NOT bytes!
+extern size_t common_hal_usb_midi_portout_write(usb_midi_portout_obj_t *self,
+ const uint8_t *data, size_t len, int *errcode);
+
+extern bool common_hal_usb_midi_portout_ready_to_tx(usb_midi_portout_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI_PORTOUT_H
diff --git a/circuitpython/shared-bindings/usb_midi/__init__.c b/circuitpython/shared-bindings/usb_midi/__init__.c
new file mode 100644
index 0000000..ec065d1
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/__init__.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/usb_midi/__init__.h"
+#include "shared-bindings/usb_midi/PortIn.h"
+#include "shared-bindings/usb_midi/PortOut.h"
+
+#include "py/runtime.h"
+
+//| """MIDI over USB
+//|
+//| The `usb_midi` module contains classes to transmit and receive MIDI messages over USB."""
+//|
+//| ports: Tuple[Union[PortIn, PortOut], ...]
+//| """Tuple of all MIDI ports. Each item is ether `PortIn` or `PortOut`."""
+//|
+
+//| def disable() -> None:
+//| """Disable presenting a USB MIDI device to the host.
+//| The device is normally enabled by default, but on some boards with limited endpoints
+//| including ESP32-S2 and certain STM boards, it is disabled by default.
+//| Can be called in ``boot.py``, before USB is connected."""
+//| ...
+//|
+STATIC mp_obj_t usb_midi_disable(void) {
+ if (!common_hal_usb_midi_disable()) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(usb_midi_disable_obj, usb_midi_disable);
+
+//| def enable() -> None:
+//| """Enable presenting a USB MIDI device to the host.
+//| The device is enabled by default, so you do not normally need to call this function.
+//| Can be called in ``boot.py``, before USB is connected.
+//|
+//| If you enable too many devices at once, you will run out of USB endpoints.
+//| The number of available endpoints varies by microcontroller.
+//| CircuitPython will go into safe mode after running boot.py to inform you if
+//| not enough endpoints are available.
+//| """
+//| ...
+//|
+STATIC mp_obj_t usb_midi_enable(void) {
+ if (!common_hal_usb_midi_enable()) {
+ mp_raise_RuntimeError(translate("Cannot change USB devices now"));
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(usb_midi_enable_obj, usb_midi_enable);
+
+mp_map_elem_t usb_midi_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_midi) },
+ { MP_ROM_QSTR(MP_QSTR_disable), MP_OBJ_FROM_PTR(&usb_midi_disable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_midi_enable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ports), mp_const_empty_tuple },
+ { MP_ROM_QSTR(MP_QSTR_PortIn), MP_OBJ_FROM_PTR(&usb_midi_portin_type) },
+ { MP_ROM_QSTR(MP_QSTR_PortOut), MP_OBJ_FROM_PTR(&usb_midi_portout_type) },
+};
+
+// This isn't const so we can set ports dynamically.
+MP_DEFINE_MUTABLE_DICT(usb_midi_module_globals, usb_midi_module_globals_table);
+
+const mp_obj_module_t usb_midi_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&usb_midi_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_usb_midi, usb_midi_module, CIRCUITPY_USB_MIDI);
diff --git a/circuitpython/shared-bindings/usb_midi/__init__.h b/circuitpython/shared-bindings/usb_midi/__init__.h
new file mode 100644
index 0000000..b657cfe
--- /dev/null
+++ b/circuitpython/shared-bindings/usb_midi/__init__.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H
+
+#include "py/obj.h"
+#include "shared-module/usb_midi/__init__.h"
+
+extern mp_obj_dict_t usb_midi_module_globals;
+
+bool common_hal_usb_midi_disable(void);
+bool common_hal_usb_midi_enable(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USB_MIDI___INIT___H
diff --git a/circuitpython/shared-bindings/ustack/__init__.c b/circuitpython/shared-bindings/ustack/__init__.c
new file mode 100644
index 0000000..17bdcbb
--- /dev/null
+++ b/circuitpython/shared-bindings/ustack/__init__.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/ustack/__init__.h"
+
+
+
+
+//| """Stack information and analysis"""
+//|
+
+#if MICROPY_MAX_STACK_USAGE
+//| def max_stack_usage() -> int:
+//| """Return the maximum excursion of the stack so far."""
+//| ...
+//|
+STATIC mp_obj_t max_stack_usage(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_max_stack_usage());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(max_stack_usage_obj, max_stack_usage);
+
+#endif // MICROPY_MAX_STACK_USAGE
+
+//| def stack_size() -> int:
+//| """Return the size of the entire stack.
+//| Same as in micropython.mem_info(), but returns a value instead
+//| of just printing it."""
+//| ...
+//|
+STATIC mp_obj_t stack_size(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_stack_size());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(stack_size_obj, stack_size);
+
+//| def stack_usage() -> int:
+//| """Return how much stack is currently in use.
+//| Same as micropython.stack_use(); duplicated here for convenience."""
+//| ...
+//|
+STATIC mp_obj_t stack_usage(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_stack_usage());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(stack_usage_obj, stack_usage);
+
+STATIC const mp_rom_map_elem_t ustack_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ustack) },
+ #if MICROPY_MAX_STACK_USAGE
+ { MP_ROM_QSTR(MP_QSTR_max_stack_usage), MP_ROM_PTR(&max_stack_usage_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&stack_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stack_usage), MP_ROM_PTR(&stack_usage_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ustack_module_globals, ustack_module_globals_table);
+
+const mp_obj_module_t ustack_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&ustack_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_ustack, ustack_module, CIRCUITPY_USTACK);
diff --git a/circuitpython/shared-bindings/ustack/__init__.h b/circuitpython/shared-bindings/ustack/__init__.h
new file mode 100644
index 0000000..561d581
--- /dev/null
+++ b/circuitpython/shared-bindings/ustack/__init__.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USTACK___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_USTACK___INIT___H
+
+#include "py/obj.h"
+
+#if MICROPY_MAX_STACK_USAGE
+extern uint32_t shared_module_ustack_max_stack_usage(void);
+#endif
+extern uint32_t shared_module_ustack_stack_size(void);
+extern uint32_t shared_module_ustack_stack_usage(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_USTACK___INIT___H
diff --git a/circuitpython/shared-bindings/util.c b/circuitpython/shared-bindings/util.c
new file mode 100644
index 0000000..c1ca01e
--- /dev/null
+++ b/circuitpython/shared-bindings/util.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_UTIL_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_UTIL_H
+
+#include "py/runtime.h"
+
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+// If so, deinit() has already been called on the object, so complain.
+void raise_deinited_error(void) {
+ mp_raise_ValueError(translate("Object has been deinitialized and can no longer be used. Create a new object."));
+}
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_UTIL_H
diff --git a/circuitpython/shared-bindings/util.h b/circuitpython/shared-bindings/util.h
new file mode 100644
index 0000000..33454f1
--- /dev/null
+++ b/circuitpython/shared-bindings/util.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H
+
+void raise_deinited_error(void);
+
+
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H
diff --git a/circuitpython/shared-bindings/vectorio/Circle.c b/circuitpython/shared-bindings/vectorio/Circle.c
new file mode 100644
index 0000000..ded1861
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Circle.c
@@ -0,0 +1,141 @@
+#include "shared-bindings/vectorio/__init__.h"
+#include "shared-bindings/vectorio/Circle.h"
+#include "shared-bindings/vectorio/VectorShape.h"
+
+
+#include <stdint.h>
+
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class Circle:
+//|
+//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], radius: int, x: int, y: int) -> None:
+//| """Circle is positioned on screen by its center point.
+//|
+//| :param Union[~displayio.ColorConverter,~displayio.Palette] pixel_shader: The pixel shader that produces colors from values
+//| :param int radius: The radius of the circle in pixels
+//| :param int x: Initial x position of the axis.
+//| :param int y: Initial y position of the axis.
+//| :param int color_index: Initial color_index to use when selecting color from the palette."""
+//|
+static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pixel_shader, ARG_radius, ARG_x, ARG_y, ARG_color_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t radius = args[ARG_radius].u_int;
+ if (radius < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_radius);
+ }
+
+ vectorio_circle_t *self = m_new_obj(vectorio_circle_t);
+ self->base.type = &vectorio_circle_type;
+ uint16_t color_index = args[ARG_color_index].u_int;
+ common_hal_vectorio_circle_construct(self, radius, color_index);
+
+ // VectorShape parts
+ mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
+ int32_t x = args[ARG_x].u_int;
+ int32_t y = args[ARG_y].u_int;
+ mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y);
+ self->draw_protocol_instance = vector_shape;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const vectorio_draw_protocol_t circle_draw_protocol = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw)
+ .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_circle_get_draw_protocol,
+ .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl
+};
+
+
+//| radius : int
+//| """The radius of the circle in pixels."""
+//|
+STATIC mp_obj_t vectorio_circle_obj_get_radius(mp_obj_t self_in) {
+ vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_circle_get_radius(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_circle_get_radius_obj, vectorio_circle_obj_get_radius);
+
+STATIC mp_obj_t vectorio_circle_obj_set_radius(mp_obj_t self_in, mp_obj_t radius) {
+ vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_circle_set_radius(self, mp_obj_get_int(radius));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_circle_set_radius_obj, vectorio_circle_obj_set_radius);
+
+MP_PROPERTY_GETSET(vectorio_circle_radius_obj,
+ (mp_obj_t)&vectorio_circle_get_radius_obj,
+ (mp_obj_t)&vectorio_circle_set_radius_obj);
+
+//| color_index : int
+//| """The color_index of the circle as 0 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_circle_obj_get_color_index(mp_obj_t self_in) {
+ vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_circle_get_color_index(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_circle_get_color_index_obj, vectorio_circle_obj_get_color_index);
+
+STATIC mp_obj_t vectorio_circle_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
+ vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_circle_set_color_index(self, mp_obj_get_int(color_index));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_circle_set_color_index_obj, vectorio_circle_obj_set_color_index);
+
+MP_PROPERTY_GETSET(vectorio_circle_color_index_obj,
+ (mp_obj_t)&vectorio_circle_get_color_index_obj,
+ (mp_obj_t)&vectorio_circle_set_color_index_obj);
+
+
+// Documentation for properties inherited from VectorShape.
+
+//| x : int
+//| """X position of the center point of the circle in the parent."""
+//|
+//| y : int
+//| """Y position of the center point of the circle in the parent."""
+//|
+//| location : Tuple[int,int]
+//| """(X,Y) position of the center point of the circle in the parent."""
+//|
+//| pixel_shader : Union[displayio.ColorConverter,displayio.Palette]
+//| """The pixel shader of the circle."""
+//|
+
+STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = {
+ // Functions
+ { MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_circle_color_index_obj) },
+ { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(vectorio_circle_locals_dict, vectorio_circle_locals_dict_table);
+
+const mp_obj_type_t vectorio_circle_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Circle,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = vectorio_circle_make_new,
+ .locals_dict = (mp_obj_dict_t *)&vectorio_circle_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &circle_draw_protocol,
+ ),
+};
diff --git a/circuitpython/shared-bindings/vectorio/Circle.h b/circuitpython/shared-bindings/vectorio/Circle.h
new file mode 100644
index 0000000..8f16979
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Circle.h
@@ -0,0 +1,27 @@
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H
+
+#include "shared-module/vectorio/__init__.h"
+#include "shared-module/vectorio/Circle.h"
+#include "shared-module/displayio/area.h"
+
+extern const mp_obj_type_t vectorio_circle_type;
+
+void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius, uint16_t color_index);
+
+void common_hal_vectorio_circle_set_on_dirty(vectorio_circle_t *self, vectorio_event_t notification);
+
+uint32_t common_hal_vectorio_circle_get_pixel(void *circle, int16_t x, int16_t y);
+
+void common_hal_vectorio_circle_get_area(void *circle, displayio_area_t *out_area);
+
+
+int16_t common_hal_vectorio_circle_get_radius(void *circle);
+void common_hal_vectorio_circle_set_radius(void *circle, int16_t radius);
+
+uint16_t common_hal_vectorio_circle_get_color_index(void *obj);
+void common_hal_vectorio_circle_set_color_index(void *obj, uint16_t color_index);
+
+mp_obj_t common_hal_vectorio_circle_get_draw_protocol(void *circle);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H
diff --git a/circuitpython/shared-bindings/vectorio/Polygon.c b/circuitpython/shared-bindings/vectorio/Polygon.c
new file mode 100644
index 0000000..ae9d7a0
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Polygon.c
@@ -0,0 +1,147 @@
+#include "shared-bindings/vectorio/__init__.h"
+#include "shared-module/vectorio/__init__.h"
+#include "shared-bindings/vectorio/Polygon.h"
+#include "shared-bindings/vectorio/VectorShape.h"
+
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+
+#define VECTORIO_POLYGON_DEBUG(...) (void)0
+// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
+
+
+//| class Polygon:
+//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], points: List[Tuple[int, int]], x: int, y: int) -> None:
+//| """Represents a closed shape by ordered vertices. The path will be treated as
+//| 'closed', the last point will connect to the first point.
+//|
+//| :param Union[~displayio.ColorConverter,~displayio.Palette] pixel_shader: The pixel
+//| shader that produces colors from values
+//| :param List[Tuple[int,int]] points: Vertices for the polygon
+//| :param int x: Initial screen x position of the 0,0 origin in the points list.
+//| :param int y: Initial screen y position of the 0,0 origin in the points list.
+//| :param int color_index: Initial color_index to use when selecting color from the palette."""
+//|
+static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pixel_shader, ARG_points_list, ARG_x, ARG_y, ARG_color_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t points_list = mp_arg_validate_type(args[ARG_points_list].u_obj, &mp_type_list, MP_QSTR_points);
+
+ vectorio_polygon_t *self = m_new_obj(vectorio_polygon_t);
+ self->base.type = &vectorio_polygon_type;
+
+ uint16_t color_index = args[ARG_color_index].u_int;
+ common_hal_vectorio_polygon_construct(self, points_list, color_index);
+
+ // VectorShape parts
+ mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
+ int32_t x = args[ARG_x].u_int;
+ int32_t y = args[ARG_y].u_int;
+ mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y);
+ self->draw_protocol_instance = vector_shape;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const vectorio_draw_protocol_t polygon_draw_protocol = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw)
+ .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_polygon_get_draw_protocol,
+ .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl
+};
+
+
+//| points: List[Tuple[int, int]]
+//| """Vertices for the polygon."""
+//|
+STATIC mp_obj_t vectorio_polygon_obj_get_points(mp_obj_t self_in) {
+ vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_vectorio_polygon_get_points(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_get_points);
+
+STATIC mp_obj_t vectorio_polygon_obj_set_points(mp_obj_t self_in, mp_obj_t points) {
+ vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_vectorio_polygon_set_points(self, points);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_polygon_set_points_obj, vectorio_polygon_obj_set_points);
+
+MP_PROPERTY_GETSET(vectorio_polygon_points_obj,
+ (mp_obj_t)&vectorio_polygon_get_points_obj,
+ (mp_obj_t)&vectorio_polygon_set_points_obj);
+
+//| color_index : int
+//| """The color_index of the polygon as 0 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_polygon_obj_get_color_index(mp_obj_t self_in) {
+ vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_polygon_get_color_index(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_color_index_obj, vectorio_polygon_obj_get_color_index);
+
+STATIC mp_obj_t vectorio_polygon_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
+ vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_polygon_set_color_index(self, mp_obj_get_int(color_index));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_polygon_set_color_index_obj, vectorio_polygon_obj_set_color_index);
+
+MP_PROPERTY_GETSET(vectorio_polygon_color_index_obj,
+ (mp_obj_t)&vectorio_polygon_get_color_index_obj,
+ (mp_obj_t)&vectorio_polygon_set_color_index_obj);
+
+
+// Documentation for properties inherited from VectorShape.
+
+//| x : int
+//| """X position of the 0,0 origin in the points list."""
+//|
+//| y : int
+//| """Y position of the 0,0 origin in the points list."""
+//|
+//| location : Tuple[int,int]
+//| """(X,Y) position of the 0,0 origin in the points list."""
+//|
+//| pixel_shader : Union[displayio.ColorConverter,displayio.Palette]
+//| """The pixel shader of the polygon."""
+//|
+
+STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = {
+ // Functions
+ { MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) },
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_polygon_color_index_obj) },
+ { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(vectorio_polygon_locals_dict, vectorio_polygon_locals_dict_table);
+
+const mp_obj_type_t vectorio_polygon_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Polygon,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = vectorio_polygon_make_new,
+ .locals_dict = (mp_obj_dict_t *)&vectorio_polygon_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &polygon_draw_protocol,
+ ),
+};
diff --git a/circuitpython/shared-bindings/vectorio/Polygon.h b/circuitpython/shared-bindings/vectorio/Polygon.h
new file mode 100644
index 0000000..9d3ce2d
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Polygon.h
@@ -0,0 +1,29 @@
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H
+
+#include "shared-module/vectorio/Polygon.h"
+#include "shared-module/displayio/area.h"
+#include "shared-module/vectorio/__init__.h"
+
+extern const mp_obj_type_t vectorio_polygon_type;
+
+void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list, uint16_t color_index);
+void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio_event_t notification);
+
+
+uint32_t common_hal_vectorio_polygon_get_pixel(void *polygon, int16_t x, int16_t y);
+
+void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *out_area);
+
+
+
+mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self);
+void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list);
+
+uint16_t common_hal_vectorio_polygon_get_color_index(void *obj);
+void common_hal_vectorio_polygon_set_color_index(void *obj, uint16_t color_index);
+
+mp_obj_t common_hal_vectorio_polygon_get_draw_protocol(void *polygon);
+
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H
diff --git a/circuitpython/shared-bindings/vectorio/Rectangle.c b/circuitpython/shared-bindings/vectorio/Rectangle.c
new file mode 100644
index 0000000..739a1ba
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Rectangle.c
@@ -0,0 +1,173 @@
+#include "shared-bindings/vectorio/__init__.h"
+#include "shared-bindings/vectorio/Rectangle.h"
+#include "shared-module/vectorio/VectorShape.h"
+#include "shared-bindings/vectorio/VectorShape.h"
+
+#include <stdint.h>
+
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+//| class Rectangle:
+//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], width: int, height: int, x: int, y: int) -> None:
+//| """Represents a rectangle by defining its bounds
+//|
+//| :param Union[~displayio.ColorConverter,~displayio.Palette] pixel_shader: The pixel shader that produces colors from values
+//| :param int width: The number of pixels wide
+//| :param int height: The number of pixels high
+//| :param int x: Initial x position of the top left corner.
+//| :param int y: Initial y position of the top left corner.
+//| :param int color_index: Initial color_index to use when selecting color from the palette."""
+//|
+static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y, ARG_color_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED },
+ { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ { MP_QSTR_color_index, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_int_t width = args[ARG_width].u_int;
+ if (width < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_width);
+ }
+ mp_int_t height = args[ARG_height].u_int;
+ if (height < 1) {
+ mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_height);
+ }
+
+ vectorio_rectangle_t *self = m_new_obj(vectorio_rectangle_t);
+ self->base.type = &vectorio_rectangle_type;
+ uint16_t color_index = args[ARG_color_index].u_int;
+ common_hal_vectorio_rectangle_construct(self, width, height, color_index);
+
+ // VectorShape parts
+ mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj;
+ int32_t x = args[ARG_x].u_int;
+ int32_t y = args[ARG_y].u_int;
+ mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y);
+ self->draw_protocol_instance = vector_shape;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const vectorio_draw_protocol_t rectangle_draw_protocol = {
+ MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw)
+ .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_rectangle_get_draw_protocol,
+ .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl
+};
+
+//| width : int
+//| """The width of the rectangle in pixels."""
+//|
+STATIC mp_obj_t vectorio_rectangle_obj_get_width(mp_obj_t self_in) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_rectangle_get_width(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_width_obj, vectorio_rectangle_obj_get_width);
+
+STATIC mp_obj_t vectorio_rectangle_obj_set_width(mp_obj_t self_in, mp_obj_t width) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_rectangle_set_width(self, mp_obj_get_int(width));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_width_obj, vectorio_rectangle_obj_set_width);
+
+const mp_obj_property_t vectorio_rectangle_width_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&vectorio_rectangle_get_width_obj,
+ (mp_obj_t)&vectorio_rectangle_set_width_obj,
+ MP_ROM_NONE},
+};
+
+//| height : int
+//| """The height of the rectangle in pixels."""
+//|
+STATIC mp_obj_t vectorio_rectangle_obj_get_height(mp_obj_t self_in) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_rectangle_get_height(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_height_obj, vectorio_rectangle_obj_get_height);
+
+STATIC mp_obj_t vectorio_rectangle_obj_set_height(mp_obj_t self_in, mp_obj_t height) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_rectangle_set_height(self, mp_obj_get_int(height));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_height_obj, vectorio_rectangle_obj_set_height);
+
+const mp_obj_property_t vectorio_rectangle_height_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&vectorio_rectangle_get_height_obj,
+ (mp_obj_t)&vectorio_rectangle_set_height_obj,
+ MP_ROM_NONE},
+};
+
+//| color_index : int
+//| """The color_index of the rectangle in 1 based index of the palette."""
+//|
+STATIC mp_obj_t vectorio_rectangle_obj_get_color_index(mp_obj_t self_in) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_int(common_hal_vectorio_rectangle_get_color_index(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_rectangle_get_color_index_obj, vectorio_rectangle_obj_get_color_index);
+
+STATIC mp_obj_t vectorio_rectangle_obj_set_color_index(mp_obj_t self_in, mp_obj_t color_index) {
+ vectorio_rectangle_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_vectorio_rectangle_set_color_index(self, mp_obj_get_int(color_index));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_rectangle_set_color_index_obj, vectorio_rectangle_obj_set_color_index);
+
+const mp_obj_property_t vectorio_rectangle_color_index_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&vectorio_rectangle_get_color_index_obj,
+ (mp_obj_t)&vectorio_rectangle_set_color_index_obj,
+ MP_ROM_NONE},
+};
+
+// Documentation for properties inherited from VectorShape.
+
+//| x : int
+//| """X position of the top left corner of the rectangle in the parent."""
+//|
+//| y : int
+//| """Y position of the top left corner of the rectangle in the parent."""
+//|
+//| location : Tuple[int,int]
+//| """(X,Y) position of the top left corner of the rectangle in the parent."""
+//|
+//| pixel_shader : Union[displayio.ColorConverter,displayio.Palette]
+//| """The pixel shader of the rectangle."""
+//|
+
+STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = {
+ // Functions
+ { MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
+ { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
+ { MP_ROM_QSTR(MP_QSTR_color_index), MP_ROM_PTR(&vectorio_rectangle_color_index_obj) },
+ { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&vectorio_rectangle_width_obj) },
+ { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&vectorio_rectangle_height_obj) },
+ { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(vectorio_rectangle_locals_dict, vectorio_rectangle_locals_dict_table);
+
+const mp_obj_type_t vectorio_rectangle_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Rectangle,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .make_new = vectorio_rectangle_make_new,
+ .locals_dict = (mp_obj_dict_t *)&vectorio_rectangle_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .protocol = &rectangle_draw_protocol,
+ ),
+};
diff --git a/circuitpython/shared-bindings/vectorio/Rectangle.h b/circuitpython/shared-bindings/vectorio/Rectangle.h
new file mode 100644
index 0000000..907ae68
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/Rectangle.h
@@ -0,0 +1,28 @@
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H
+
+#include "shared-module/vectorio/Rectangle.h"
+#include "shared-module/displayio/area.h"
+#include "shared-module/vectorio/__init__.h"
+
+extern const mp_obj_type_t vectorio_rectangle_type;
+
+void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height, uint16_t color_index);
+void common_hal_vectorio_rectangle_set_on_dirty(vectorio_rectangle_t *self, vectorio_event_t on_dirty);
+
+uint32_t common_hal_vectorio_rectangle_get_pixel(void *rectangle, int16_t x, int16_t y);
+
+void common_hal_vectorio_rectangle_get_area(void *rectangle, displayio_area_t *out_area);
+
+mp_obj_t common_hal_vectorio_rectangle_get_draw_protocol(void *rectangle);
+
+int16_t common_hal_vectorio_rectangle_get_width(void *obj);
+void common_hal_vectorio_rectangle_set_width(void *obj, int16_t width);
+
+uint16_t common_hal_vectorio_rectangle_get_color_index(void *obj);
+void common_hal_vectorio_rectangle_set_color_index(void *obj, uint16_t color_index);
+
+int16_t common_hal_vectorio_rectangle_get_height(void *obj);
+void common_hal_vectorio_rectangle_set_height(void *obj, int16_t height);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H
diff --git a/circuitpython/shared-bindings/vectorio/VectorShape.c b/circuitpython/shared-bindings/vectorio/VectorShape.c
new file mode 100644
index 0000000..fe6be55
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/VectorShape.c
@@ -0,0 +1,223 @@
+
+#include "shared-module/vectorio/__init__.h"
+#include "shared-bindings/vectorio/VectorShape.h"
+#include "shared-bindings/vectorio/Circle.h"
+#include "shared-bindings/vectorio/Polygon.h"
+#include "shared-bindings/vectorio/Rectangle.h"
+
+#include "shared-bindings/displayio/ColorConverter.h"
+#include "shared-bindings/displayio/Palette.h"
+
+#include <stdint.h>
+
+#include "shared/runtime/context_manager_helpers.h"
+
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/objtype.h"
+#include "py/runtime.h"
+#include "supervisor/shared/translate.h"
+
+
+// shape: The shape implementation to draw.
+// pixel_shader: The pixel shader that produces colors from values. The shader can be a displayio.Palette(1); it will be asked to color pixel value 0.
+// x: Initial x position of the center axis of the shape within the parent.
+// y: Initial y position of the center axis of the shape within the parent."""
+mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pixel_shader, int32_t x, int32_t y) {
+ if (!mp_obj_is_type(pixel_shader, &displayio_colorconverter_type) &&
+ !mp_obj_is_type(pixel_shader, &displayio_palette_type)) {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader);
+ }
+
+ vectorio_ishape_t ishape;
+ // Wire up shape functions
+ if (mp_obj_is_type(shape, &vectorio_polygon_type)) {
+ ishape.shape = shape;
+ ishape.get_area = &common_hal_vectorio_polygon_get_area;
+ ishape.get_pixel = &common_hal_vectorio_polygon_get_pixel;
+ } else if (mp_obj_is_type(shape, &vectorio_rectangle_type)) {
+ ishape.shape = shape;
+ ishape.get_area = &common_hal_vectorio_rectangle_get_area;
+ ishape.get_pixel = &common_hal_vectorio_rectangle_get_pixel;
+ } else if (mp_obj_is_type(shape, &vectorio_circle_type)) {
+ ishape.shape = shape;
+ ishape.get_area = &common_hal_vectorio_circle_get_area;
+ ishape.get_pixel = &common_hal_vectorio_circle_get_pixel;
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_shape);
+ }
+
+ vectorio_vector_shape_t *self = m_new_obj(vectorio_vector_shape_t);
+ self->base.type = &vectorio_vector_shape_type;
+ common_hal_vectorio_vector_shape_construct(self,
+ ishape, pixel_shader, x, y
+ );
+
+ // Wire up event callbacks
+ vectorio_event_t on_dirty = {
+ .obj = self,
+ .event = &common_hal_vectorio_vector_shape_set_dirty
+ };
+
+ if (mp_obj_is_type(shape, &vectorio_polygon_type)) {
+ common_hal_vectorio_polygon_set_on_dirty(self->ishape.shape, on_dirty);
+ } else if (mp_obj_is_type(shape, &vectorio_rectangle_type)) {
+ common_hal_vectorio_rectangle_set_on_dirty(self->ishape.shape, on_dirty);
+ } else if (mp_obj_is_type(shape, &vectorio_circle_type)) {
+ common_hal_vectorio_circle_set_on_dirty(self->ishape.shape, on_dirty);
+ } else {
+ mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_shape);
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl = {
+ .draw_fill_area = (draw_fill_area_fun)vectorio_vector_shape_fill_area,
+ .draw_get_dirty_area = (draw_get_dirty_area_fun)vectorio_vector_shape_get_dirty_area,
+ .draw_update_transform = (draw_update_transform_fun)vectorio_vector_shape_update_transform,
+ .draw_finish_refresh = (draw_finish_refresh_fun)vectorio_vector_shape_finish_refresh,
+ .draw_get_refresh_areas = (draw_get_refresh_areas_fun)vectorio_vector_shape_get_refresh_areas,
+};
+
+// Stub checker does not approve of these shared properties.
+// x: int
+// y: int
+// """true if x,y lies inside the shape."""
+//
+STATIC mp_obj_t vectorio_vector_shape_obj_contains(mp_obj_t wrapper_shape, mp_obj_t x_obj, mp_obj_t y_obj) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ mp_int_t y = mp_obj_get_int(y_obj);
+ return mp_obj_new_bool(common_hal_vectorio_vector_shape_contains(self, x, y));
+}
+MP_DEFINE_CONST_FUN_OBJ_3(vectorio_vector_shape_contains_obj, vectorio_vector_shape_obj_contains);
+
+// Stub checker does not approve of these shared properties.
+// x: int
+// """X position of the center point of the shape in the parent."""
+//
+STATIC mp_obj_t vectorio_vector_shape_obj_get_x(mp_obj_t wrapper_shape) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_vectorio_vector_shape_get_x(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_x_obj, vectorio_vector_shape_obj_get_x);
+
+STATIC mp_obj_t vectorio_vector_shape_obj_set_x(mp_obj_t wrapper_shape, mp_obj_t x_obj) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ mp_int_t x = mp_obj_get_int(x_obj);
+ common_hal_vectorio_vector_shape_set_x(self, x);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_x_obj, vectorio_vector_shape_obj_set_x);
+
+MP_PROPERTY_GETSET(vectorio_vector_shape_x_obj,
+ (mp_obj_t)&vectorio_vector_shape_get_x_obj,
+ (mp_obj_t)&vectorio_vector_shape_set_x_obj);
+
+
+// y: int
+// """Y position of the center point of the shape in the parent."""
+//
+STATIC mp_obj_t vectorio_vector_shape_obj_get_y(mp_obj_t wrapper_shape) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_vectorio_vector_shape_get_y(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_y_obj, vectorio_vector_shape_obj_get_y);
+
+STATIC mp_obj_t vectorio_vector_shape_obj_set_y(mp_obj_t wrapper_shape, mp_obj_t y_obj) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ mp_int_t y = mp_obj_get_int(y_obj);
+ common_hal_vectorio_vector_shape_set_y(self, y);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_y_obj, vectorio_vector_shape_obj_set_y);
+
+MP_PROPERTY_GETSET(vectorio_vector_shape_y_obj,
+ (mp_obj_t)&vectorio_vector_shape_get_y_obj,
+ (mp_obj_t)&vectorio_vector_shape_set_y_obj);
+
+
+// location: Tuple[int, int]
+// """location of the center point of the shape in the parent."""
+//
+STATIC mp_obj_t vectorio_vector_shape_obj_get_location(mp_obj_t wrapper_shape) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ return MP_OBJ_TO_PTR(common_hal_vectorio_vector_shape_get_location(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_location_obj, vectorio_vector_shape_obj_get_location);
+
+STATIC mp_obj_t vectorio_vector_shape_obj_set_location(mp_obj_t wrapper_shape, mp_obj_t location_obj) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ common_hal_vectorio_vector_shape_set_location(self, location_obj);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_location_obj, vectorio_vector_shape_obj_set_location);
+
+MP_PROPERTY_GETSET(vectorio_vector_shape_location_obj,
+ (mp_obj_t)&vectorio_vector_shape_get_location_obj,
+ (mp_obj_t)&vectorio_vector_shape_set_location_obj);
+
+
+// pixel_shader: Union[ColorConverter, Palette]
+// """The pixel shader of the shape."""
+//
+STATIC mp_obj_t vectorio_vector_shape_obj_get_pixel_shader(mp_obj_t wrapper_shape) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ return common_hal_vectorio_vector_shape_get_pixel_shader(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_pixel_shader_obj, vectorio_vector_shape_obj_get_pixel_shader);
+
+STATIC mp_obj_t vectorio_vector_shape_obj_set_pixel_shader(mp_obj_t wrapper_shape, mp_obj_t pixel_shader) {
+ // Relies on the fact that only vector_shape impl gets matched with a VectorShape.
+ const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
+ vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
+
+ if (!mp_obj_is_type(pixel_shader, &displayio_palette_type) && !mp_obj_is_type(pixel_shader, &displayio_colorconverter_type)) {
+ mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter"));
+ }
+
+ common_hal_vectorio_vector_shape_set_pixel_shader(self, pixel_shader);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_pixel_shader_obj, vectorio_vector_shape_obj_set_pixel_shader);
+
+MP_PROPERTY_GETSET(vectorio_vector_shape_pixel_shader_obj,
+ (mp_obj_t)&vectorio_vector_shape_get_pixel_shader_obj,
+ (mp_obj_t)&vectorio_vector_shape_set_pixel_shader_obj);
+
+
+STATIC const mp_rom_map_elem_t vectorio_vector_shape_locals_dict_table[] = {
+};
+STATIC MP_DEFINE_CONST_DICT(vectorio_vector_shape_locals_dict, vectorio_vector_shape_locals_dict_table);
+
+const mp_obj_type_t vectorio_vector_shape_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_VectorShape,
+ .locals_dict = (mp_obj_dict_t *)&vectorio_vector_shape_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/vectorio/VectorShape.h b/circuitpython/shared-bindings/vectorio/VectorShape.h
new file mode 100644
index 0000000..13f6292
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/VectorShape.h
@@ -0,0 +1,47 @@
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H
+
+#include "py/objproperty.h"
+#include "py/objtuple.h"
+
+#include "shared-bindings/vectorio/__init__.h"
+#include "shared-module/vectorio/VectorShape.h"
+#include "shared-module/displayio/area.h"
+
+extern const mp_obj_type_t vectorio_vector_shape_type;
+
+// Python shared bindings constructor
+mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pixel_shader, int32_t x, int32_t y);
+
+// C data constructor
+void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self,
+ vectorio_ishape_t ishape,
+ mp_obj_t pixel_shader, int32_t x, int32_t y);
+
+bool common_hal_vectorio_vector_shape_contains(vectorio_vector_shape_t *self, mp_int_t x, mp_int_t y);
+
+void common_hal_vectorio_vector_shape_set_dirty(void *self);
+
+mp_int_t common_hal_vectorio_vector_shape_get_x(vectorio_vector_shape_t *self);
+void common_hal_vectorio_vector_shape_set_x(vectorio_vector_shape_t *self, mp_int_t x);
+
+mp_obj_tuple_t *common_hal_vectorio_vector_shape_get_location(vectorio_vector_shape_t *self);
+void common_hal_vectorio_vector_shape_set_location(vectorio_vector_shape_t *self, mp_obj_t xy);
+
+mp_int_t common_hal_vectorio_vector_shape_get_y(vectorio_vector_shape_t *self);
+void common_hal_vectorio_vector_shape_set_y(vectorio_vector_shape_t *self, mp_int_t y);
+
+mp_obj_t common_hal_vectorio_vector_shape_get_pixel_shader(vectorio_vector_shape_t *self);
+void common_hal_vectorio_vector_shape_set_pixel_shader(vectorio_vector_shape_t *self, mp_obj_t pixel_shader);
+
+void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displayio_buffer_transform_t *group_transform);
+
+// Composable property definition for shapes that use VectorShape
+extern vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl;
+extern const mp_obj_property_getset_t vectorio_vector_shape_x_obj;
+extern const mp_obj_property_getset_t vectorio_vector_shape_y_obj;
+extern const mp_obj_property_getset_t vectorio_vector_shape_location_obj;
+extern const mp_obj_property_getset_t vectorio_vector_shape_pixel_shader_obj;
+extern const mp_obj_fun_builtin_fixed_t vectorio_vector_shape_contains_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H
diff --git a/circuitpython/shared-bindings/vectorio/__init__.c b/circuitpython/shared-bindings/vectorio/__init__.c
new file mode 100644
index 0000000..6e39f26
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/__init__.c
@@ -0,0 +1,49 @@
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/vectorio/Circle.h"
+#include "shared-bindings/vectorio/Polygon.h"
+#include "shared-bindings/vectorio/Rectangle.h"
+
+//| """Lightweight 2D shapes for displays
+//|
+//| The :py:attr:`vectorio` module provide simple filled drawing primitives for
+//| use with `displayio`.
+//|
+//| .. code-block:: python
+//|
+//| group = displayio.Group()
+//|
+//| palette = displayio.Palette(1)
+//| palette[0] = 0x125690
+//|
+//| circle = vectorio.Circle(pixel_shader=palette, radius=25, x=70, y=40)
+//| group.append(circle)
+//|
+//| rectangle = vectorio.Rectangle(pixel_shader=palette, width=40, height=30, x=55, y=45)
+//| group.append(rectangle)
+//|
+//| points=[(5, 5), (100, 20), (20, 20), (20, 100)]
+//| polygon = vectorio.Polygon(pixel_shader=palette, points=points, x=0, y=0)
+//| group.append(polygon)
+//|
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t vectorio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_vectorio) },
+ { MP_ROM_QSTR(MP_QSTR_Circle), MP_ROM_PTR(&vectorio_circle_type) },
+ { MP_ROM_QSTR(MP_QSTR_Polygon), MP_ROM_PTR(&vectorio_polygon_type) },
+ { MP_ROM_QSTR(MP_QSTR_Rectangle), MP_ROM_PTR(&vectorio_rectangle_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(vectorio_module_globals, vectorio_module_globals_table);
+
+const mp_obj_module_t vectorio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&vectorio_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_vectorio, vectorio_module, CIRCUITPY_VECTORIO);
diff --git a/circuitpython/shared-bindings/vectorio/__init__.h b/circuitpython/shared-bindings/vectorio/__init__.h
new file mode 100644
index 0000000..a34195d
--- /dev/null
+++ b/circuitpython/shared-bindings/vectorio/__init__.h
@@ -0,0 +1,41 @@
+#ifndef SHARED_MODULE_VECTORIO__INIT__H
+#define SHARED_MODULE_VECTORIO__INIT__H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "py/obj.h"
+#include "py/proto.h"
+
+#include "shared-module/displayio/area.h"
+#include "shared-module/displayio/Palette.h"
+
+// Returns the object on which the rest of the draw protocol methods are invoked.
+typedef mp_obj_t (*draw_get_protocol_self_fun)(mp_obj_t protocol_container);
+
+typedef bool (*draw_fill_area_fun)(mp_obj_t draw_protocol_self, const _displayio_colorspace_t *colorspace, const displayio_area_t *area, uint32_t *mask, uint32_t *buffer);
+typedef bool (*draw_get_dirty_area_fun)(mp_obj_t draw_protocol_self, displayio_area_t *current_dirty_area);
+typedef void (*draw_update_transform_fun)(mp_obj_t draw_protocol_self, displayio_buffer_transform_t *group_transform);
+typedef void (*draw_finish_refresh_fun)(mp_obj_t draw_protocol_self);
+typedef displayio_area_t *(*draw_get_refresh_areas_fun)(mp_obj_t draw_protocol_self, displayio_area_t *tail);
+
+typedef struct _vectorio_draw_protocol_impl_t {
+ draw_fill_area_fun draw_fill_area;
+ draw_get_dirty_area_fun draw_get_dirty_area;
+ draw_update_transform_fun draw_update_transform;
+ draw_finish_refresh_fun draw_finish_refresh;
+ draw_get_refresh_areas_fun draw_get_refresh_areas;
+} vectorio_draw_protocol_impl_t;
+
+// Draw protocol
+typedef struct _vectorio_draw_protocol_t {
+ MP_PROTOCOL_HEAD // MP_QSTR_protocol_draw
+
+ // Instance of the draw protocol
+ draw_get_protocol_self_fun draw_get_protocol_self;
+
+ // Implementation functions for the draw protocol
+ vectorio_draw_protocol_impl_t *draw_protocol_impl;
+} vectorio_draw_protocol_t;
+
+#endif
diff --git a/circuitpython/shared-bindings/watchdog/WatchDogMode.c b/circuitpython/shared-bindings/watchdog/WatchDogMode.c
new file mode 100644
index 0000000..beea4d0
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/WatchDogMode.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Sean Cross for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/watchdog/WatchDogMode.h"
+
+//| class WatchDogMode:
+//| """run state of the watchdog timer"""
+//|
+//| def __init__(self) -> None:
+//| """Enum-like class to define the run mode of the watchdog timer."""
+//|
+//| RAISE: WatchDogMode
+//| """Raise an exception when the WatchDogTimer expires.
+//|
+//| :type WatchDogMode:"""
+//|
+//| RESET: WatchDogMode
+//| """Reset the system if the WatchDogTimer expires.
+//|
+//| :type WatchDogMode:"""
+//|
+const mp_obj_type_t watchdog_watchdogmode_type;
+
+const watchdog_watchdogmode_obj_t watchdog_watchdogmode_raise_obj = {
+ { &watchdog_watchdogmode_type },
+};
+
+const watchdog_watchdogmode_obj_t watchdog_watchdogmode_reset_obj = {
+ { &watchdog_watchdogmode_type },
+};
+
+watchdog_watchdogmode_t watchdog_watchdogmode_obj_to_type(mp_obj_t obj) {
+ if (obj == MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)) {
+ return WATCHDOGMODE_RAISE;
+ } else if (obj == MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)) {
+ return WATCHDOGMODE_RESET;
+ }
+ return WATCHDOGMODE_NONE;
+}
+
+mp_obj_t watchdog_watchdogmode_type_to_obj(watchdog_watchdogmode_t mode) {
+ switch (mode) {
+ case WATCHDOGMODE_RAISE:
+ return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_raise_obj);
+ case WATCHDOGMODE_RESET:
+ return (mp_obj_t)MP_ROM_PTR(&watchdog_watchdogmode_reset_obj);
+ case WATCHDOGMODE_NONE:
+ default:
+ return MP_ROM_NONE;
+ }
+}
+
+STATIC const mp_rom_map_elem_t watchdog_watchdogmode_locals_dict_table[] = {
+ {MP_ROM_QSTR(MP_QSTR_RAISE), MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)},
+ {MP_ROM_QSTR(MP_QSTR_RESET), MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)},
+};
+STATIC MP_DEFINE_CONST_DICT(watchdog_watchdogmode_locals_dict, watchdog_watchdogmode_locals_dict_table);
+
+STATIC void watchdog_watchdogmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ qstr runmode = MP_QSTR_None;
+ if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&watchdog_watchdogmode_raise_obj)) {
+ runmode = MP_QSTR_RAISE;
+ } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&watchdog_watchdogmode_reset_obj)) {
+ runmode = MP_QSTR_RESET;
+ }
+ mp_printf(print, "%q.%q.%q", MP_QSTR_watchdog, MP_QSTR_WatchDogMode,
+ runmode);
+}
+
+const mp_obj_type_t watchdog_watchdogmode_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WatchDogMode,
+ .print = watchdog_watchdogmode_print,
+ .locals_dict = (mp_obj_t)&watchdog_watchdogmode_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/watchdog/WatchDogMode.h b/circuitpython/shared-bindings/watchdog/WatchDogMode.h
new file mode 100644
index 0000000..fb09445
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/WatchDogMode.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Sean Cross for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H
+
+#include "py/obj.h"
+
+typedef enum {
+ WATCHDOGMODE_NONE,
+ WATCHDOGMODE_RAISE,
+ WATCHDOGMODE_RESET,
+} watchdog_watchdogmode_t;
+
+extern const mp_obj_type_t watchdog_watchdogmode_type;
+
+watchdog_watchdogmode_t watchdog_watchdogmode_obj_to_type(mp_obj_t obj);
+mp_obj_t watchdog_watchdogmode_type_to_obj(watchdog_watchdogmode_t mode);
+
+typedef struct {
+ mp_obj_base_t base;
+} watchdog_watchdogmode_obj_t;
+extern const watchdog_watchdogmode_obj_t watchdog_watchdogmode_raise_obj;
+extern const watchdog_watchdogmode_obj_t watchdog_watchdogmode_reset_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGMODE_H
diff --git a/circuitpython/shared-bindings/watchdog/WatchDogTimer.c b/circuitpython/shared-bindings/watchdog/WatchDogTimer.c
new file mode 100644
index 0000000..e00b288
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/WatchDogTimer.c
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Nick Moore for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "common-hal/watchdog/WatchDogTimer.h"
+
+#include "shared-bindings/microcontroller/__init__.h"
+#include "shared-bindings/watchdog/__init__.h"
+#include "shared-bindings/watchdog/WatchDogTimer.h"
+
+#include "supervisor/port.h"
+
+//| class WatchDogTimer:
+//| """Timer that is used to detect code lock ups and automatically reset the microcontroller
+//| when one is detected.
+//|
+//| A lock up is detected when the watchdog hasn't been fed after a given duration. So, make
+//| sure to call `feed` within the timeout.
+//| """
+//|
+
+//| def __init__(self) -> None:
+//| """Not currently dynamically supported. Access the sole instance through `microcontroller.watchdog`."""
+//| ...
+//|
+
+//| def feed(self) -> None:
+//| """Feed the watchdog timer. This must be called regularly, otherwise
+//| the timer will expire."""
+//| ...
+//|
+STATIC mp_obj_t watchdog_watchdogtimer_feed(mp_obj_t self_in) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ watchdog_watchdogmode_t current_mode = common_hal_watchdog_get_mode(self);
+
+ if (current_mode == WATCHDOGMODE_NONE) {
+ mp_raise_ValueError(translate("WatchDogTimer is not currently running"));
+ }
+
+ common_hal_watchdog_feed(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_feed_obj, watchdog_watchdogtimer_feed);
+
+//| def deinit(self) -> None:
+//| """Stop the watchdog timer. This may raise an error if the watchdog
+//| timer cannot be disabled on this platform."""
+//| ...
+//|
+STATIC mp_obj_t watchdog_watchdogtimer_deinit(mp_obj_t self_in) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_watchdog_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_deinit_obj, watchdog_watchdogtimer_deinit);
+
+//| timeout: float
+//| """The maximum number of seconds that can elapse between calls
+//| to feed()"""
+//|
+STATIC mp_obj_t watchdog_watchdogtimer_obj_get_timeout(mp_obj_t self_in) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_float(common_hal_watchdog_get_timeout(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_timeout_obj, watchdog_watchdogtimer_obj_get_timeout);
+
+STATIC mp_obj_t watchdog_watchdogtimer_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout_obj) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_float_t timeout = mp_obj_get_float(timeout_obj);
+
+ if (timeout <= 0) {
+ mp_raise_ValueError(translate("watchdog timeout must be greater than 0"));
+ }
+
+ common_hal_watchdog_set_timeout(self, timeout);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(watchdog_watchdogtimer_set_timeout_obj, watchdog_watchdogtimer_obj_set_timeout);
+
+MP_PROPERTY_GETSET(watchdog_watchdogtimer_timeout_obj,
+ (mp_obj_t)&watchdog_watchdogtimer_get_timeout_obj,
+ (mp_obj_t)&watchdog_watchdogtimer_set_timeout_obj);
+
+//| mode: WatchDogMode
+//| """The current operating mode of the WatchDogTimer `watchdog.WatchDogMode`.
+//|
+//| Setting a WatchDogMode activates the WatchDog::
+//|
+//| import microcontroller
+//| import watchdog
+//|
+//| w = microcontroller.watchdog
+//| w.timeout = 5
+//| w.mode = watchdog.WatchDogMode.RAISE
+//|
+//|
+//| Once set, the WatchDogTimer will perform the specified action if the timer expires."""
+//|
+STATIC mp_obj_t watchdog_watchdogtimer_obj_get_mode(mp_obj_t self_in) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return watchdog_watchdogmode_type_to_obj(common_hal_watchdog_get_mode(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_get_mode_obj, watchdog_watchdogtimer_obj_get_mode);
+
+STATIC mp_obj_t watchdog_watchdogtimer_obj_set_mode(mp_obj_t self_in, mp_obj_t mode_obj) {
+ watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ watchdog_watchdogmode_t current_mode = common_hal_watchdog_get_mode(self);
+ watchdog_watchdogmode_t new_mode = watchdog_watchdogmode_obj_to_type(mode_obj);
+ mp_float_t current_timeout = common_hal_watchdog_get_timeout(self);
+
+ // When setting the mode, the timeout value must be greater than zero
+ if (new_mode == WATCHDOGMODE_RESET || new_mode == WATCHDOGMODE_RAISE) {
+ if (current_timeout <= 0) {
+ mp_raise_ValueError(translate("WatchDogTimer.timeout must be greater than 0"));
+ }
+ }
+
+ // Don't allow changing the mode once the watchdog timer has been started
+ if (current_mode == WATCHDOGMODE_RESET && new_mode != WATCHDOGMODE_RESET) {
+ mp_raise_TypeError(translate("WatchDogTimer.mode cannot be changed once set to WatchDogMode.RESET"));
+ }
+
+ common_hal_watchdog_set_mode(self, new_mode);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(watchdog_watchdogtimer_set_mode_obj, watchdog_watchdogtimer_obj_set_mode);
+
+MP_PROPERTY_GETSET(watchdog_watchdogtimer_mode_obj,
+ (mp_obj_t)&watchdog_watchdogtimer_get_mode_obj,
+ (mp_obj_t)&watchdog_watchdogtimer_set_mode_obj);
+
+STATIC const mp_rom_map_elem_t watchdog_watchdogtimer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&watchdog_watchdogtimer_feed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&watchdog_watchdogtimer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&watchdog_watchdogtimer_timeout_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&watchdog_watchdogtimer_mode_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(watchdog_watchdogtimer_locals_dict, watchdog_watchdogtimer_locals_dict_table);
+
+const mp_obj_type_t watchdog_watchdogtimer_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WatchDogTimer,
+ // .make_new = watchdog_watchdogtimer_make_new,
+ .locals_dict = (mp_obj_dict_t *)&watchdog_watchdogtimer_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/watchdog/WatchDogTimer.h b/circuitpython/shared-bindings/watchdog/WatchDogTimer.h
new file mode 100644
index 0000000..4804474
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/WatchDogTimer.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Noralf Trønnes
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGTIMER_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGTIMER_H
+
+#include <py/obj.h>
+#include "shared-bindings/watchdog/WatchDogMode.h"
+
+typedef struct _watchdog_watchdogtimer_obj_t watchdog_watchdogtimer_obj_t;
+
+extern void common_hal_watchdog_feed(watchdog_watchdogtimer_obj_t *self);
+
+extern void common_hal_watchdog_set_mode(watchdog_watchdogtimer_obj_t *self, watchdog_watchdogmode_t);
+extern watchdog_watchdogmode_t common_hal_watchdog_get_mode(watchdog_watchdogtimer_obj_t *self);
+
+extern void common_hal_watchdog_set_timeout(watchdog_watchdogtimer_obj_t *self, mp_float_t timeout);
+extern mp_float_t common_hal_watchdog_get_timeout(watchdog_watchdogtimer_obj_t *self);
+
+extern void common_hal_watchdog_enable(watchdog_watchdogtimer_obj_t *self);
+extern void common_hal_watchdog_deinit(watchdog_watchdogtimer_obj_t *self);
+
+extern const mp_obj_type_t watchdog_watchdogtimer_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG_WATCHDOGTIMER_H
diff --git a/circuitpython/shared-bindings/watchdog/__init__.c b/circuitpython/shared-bindings/watchdog/__init__.c
new file mode 100644
index 0000000..a0e357e
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/__init__.c
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/runtime.h"
+#include "shared-bindings/watchdog/__init__.h"
+#include "shared-bindings/watchdog/WatchDogMode.h"
+
+//| """Watchdog Timer
+//|
+//| The `watchdog` module provides support for a Watchdog Timer. This timer will reset the device
+//| if it hasn't been fed after a specified amount of time. This is useful to ensure the board
+//| has not crashed or locked up. Note that on some platforms the watchdog timer cannot be disabled
+//| once it has been enabled.
+//|
+//| The `WatchDogTimer` is used to restart the system when the application crashes and ends
+//| up into a non recoverable state. Once started it cannot be stopped or
+//| reconfigured in any way. After enabling, the application must "feed" the
+//| watchdog periodically to prevent it from expiring and resetting the system.
+//|
+//| Example usage::
+//|
+//| from microcontroller import watchdog as w
+//| from watchdog import WatchDogMode
+//| w.timeout=2.5 # Set a timeout of 2.5 seconds
+//| w.mode = WatchDogMode.RAISE
+//| w.feed()"""
+
+//| class WatchDogTimeout(Exception):
+//| """Exception raised when the watchdog timer is set to
+//| ``WatchDogMode.RAISE`` and expires.
+//|
+//| Example::
+//|
+//| import microcontroller
+//| import watchdog
+//| import time
+//|
+//| wdt = microcontroller.watchdog
+//| wdt.timeout = 5
+//|
+//| while True:
+//| wdt.mode = watchdog.WatchDogMode.RAISE
+//| print("Starting loop -- should exit after five seconds")
+//| try:
+//| while True:
+//| time.sleep(10) # Also works with pass
+//| except watchdog.WatchDogTimeout as e:
+//| print("Watchdog expired")
+//| except Exception as e:
+//| print("Other exception")
+//|
+//| print("Exited loop")
+//| """
+
+const mp_obj_type_t mp_type_WatchDogTimeout = {
+ { &mp_type_type },
+ .name = MP_QSTR_WatchDogTimeout,
+ .make_new = mp_obj_exception_make_new,
+ .attr = mp_obj_exception_attr,
+ .parent = &mp_type_Exception,
+};
+
+mp_obj_exception_t mp_watchdog_timeout_exception = {
+ .base.type = &mp_type_WatchDogTimeout,
+ .args = (mp_obj_tuple_t *)&mp_const_empty_tuple_obj,
+ .traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj,
+};
+
+STATIC const mp_rom_map_elem_t watchdog_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_watchdog) },
+ { MP_ROM_QSTR(MP_QSTR_WatchDogMode), MP_ROM_PTR(&watchdog_watchdogmode_type) },
+ { MP_ROM_QSTR(MP_QSTR_WatchDogTimeout), MP_ROM_PTR(&mp_type_WatchDogTimeout) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(watchdog_module_globals, watchdog_module_globals_table);
+
+const mp_obj_module_t watchdog_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&watchdog_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_watchdog, watchdog_module, CIRCUITPY_WATCHDOG);
diff --git a/circuitpython/shared-bindings/watchdog/__init__.h b/circuitpython/shared-bindings/watchdog/__init__.h
new file mode 100644
index 0000000..0921141
--- /dev/null
+++ b/circuitpython/shared-bindings/watchdog/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG___INIT___H
+
+#include "py/obj.h"
+#include "py/objexcept.h"
+
+extern const mp_obj_module_t watchdog_module;
+extern mp_obj_exception_t mp_watchdog_timeout_exception;
+extern const mp_obj_type_t mp_type_WatchDogTimeout;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WATCHDOG___INIT___H
diff --git a/circuitpython/shared-bindings/wifi/AuthMode.c b/circuitpython/shared-bindings/wifi/AuthMode.c
new file mode 100644
index 0000000..528fcd4
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/AuthMode.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/enum.h"
+
+#include "shared-bindings/wifi/AuthMode.h"
+
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, OPEN, AUTHMODE_OPEN);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, WEP, AUTHMODE_WEP);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, WPA, AUTHMODE_WPA);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, WPA2, AUTHMODE_WPA2);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, WPA3, AUTHMODE_WPA3);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, PSK, AUTHMODE_PSK);
+MAKE_ENUM_VALUE(wifi_authmode_type, authmode, ENTERPRISE, AUTHMODE_ENTERPRISE);
+
+//| class AuthMode:
+//| """The authentication protocols used by WiFi."""
+//|
+//| OPEN: object
+//| """Open network. No authentication required."""
+//|
+//| WEP: object
+//| """Wired Equivalent Privacy."""
+//|
+//| WPA: object
+//| """Wireless Protected Access."""
+//|
+//| WPA2: object
+//| """Wireless Protected Access 2."""
+//|
+//| WPA3: object
+//| """Wireless Protected Access 3."""
+//|
+//| PSK: object
+//| """Pre-shared Key. (password)"""
+//|
+//| ENTERPRISE: object
+//| """Each user has a unique credential."""
+//|
+MAKE_ENUM_MAP(wifi_authmode) {
+ MAKE_ENUM_MAP_ENTRY(authmode, OPEN),
+ MAKE_ENUM_MAP_ENTRY(authmode, WEP),
+ MAKE_ENUM_MAP_ENTRY(authmode, WPA),
+ MAKE_ENUM_MAP_ENTRY(authmode, WPA2),
+ MAKE_ENUM_MAP_ENTRY(authmode, WPA3),
+ MAKE_ENUM_MAP_ENTRY(authmode, PSK),
+ MAKE_ENUM_MAP_ENTRY(authmode, ENTERPRISE),
+};
+STATIC MP_DEFINE_CONST_DICT(wifi_authmode_locals_dict, wifi_authmode_locals_table);
+
+MAKE_PRINTER(wifi, wifi_authmode);
+
+MAKE_ENUM_TYPE(wifi, AuthMode, wifi_authmode);
diff --git a/circuitpython/shared-bindings/wifi/AuthMode.h b/circuitpython/shared-bindings/wifi/AuthMode.h
new file mode 100644
index 0000000..a1016d6
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/AuthMode.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_AUTHMODE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_AUTHMODE_H
+
+#include "py/enum.h"
+
+typedef enum {
+ AUTHMODE_OPEN,
+ AUTHMODE_WEP,
+ AUTHMODE_WPA,
+ AUTHMODE_WPA2,
+ AUTHMODE_WPA3,
+ AUTHMODE_PSK,
+ AUTHMODE_ENTERPRISE
+} wifi_authmode_t;
+
+extern const mp_obj_type_t wifi_authmode_type;
+extern const cp_enum_obj_t authmode_OPEN_obj;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_AUTHMODE_H
diff --git a/circuitpython/shared-bindings/wifi/Monitor.c b/circuitpython/shared-bindings/wifi/Monitor.c
new file mode 100644
index 0000000..a63c0a8
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Monitor.c
@@ -0,0 +1,171 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpstate.h"
+#include "py/runtime.h"
+#include "py/objproperty.h"
+
+#include "shared-bindings/util.h"
+#include "shared-bindings/wifi/Packet.h"
+#include "shared-bindings/wifi/Monitor.h"
+
+//| class Monitor:
+//| """For monitoring WiFi packets."""
+//|
+
+//| def __init__(self, channel: Optional[int] = 1, queue: Optional[int] = 128) -> None:
+//| """Initialize `wifi.Monitor` singleton.
+//|
+//| :param int channel: The WiFi channel to scan.
+//| :param int queue: The queue size for buffering the packet.
+//|
+//| """
+//| ...
+//|
+STATIC mp_obj_t wifi_monitor_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_channel, ARG_queue };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_channel, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} },
+ { MP_QSTR_queue, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 128} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_channel].u_int < 1 || args[ARG_channel].u_int > 13) {
+ mp_raise_ValueError_varg(translate("%q out of bounds"), MP_QSTR_channel);
+ }
+
+ if (args[ARG_queue].u_int < 0) {
+ mp_raise_ValueError_varg(translate("%q out of bounds"), MP_QSTR_channel);
+ }
+
+ wifi_monitor_obj_t *self = MP_STATE_VM(wifi_monitor_singleton);
+ if (common_hal_wifi_monitor_deinited()) {
+ self = m_new_obj(wifi_monitor_obj_t);
+ self->base.type = &wifi_monitor_type;
+ common_hal_wifi_monitor_construct(self, args[ARG_channel].u_int, args[ARG_queue].u_int);
+ MP_STATE_VM(wifi_monitor_singleton) = self;
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| channel: int
+//| """The WiFi channel to scan."""
+//|
+STATIC mp_obj_t wifi_monitor_obj_get_channel(mp_obj_t self_in) {
+ return common_hal_wifi_monitor_get_channel(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_get_channel_obj, wifi_monitor_obj_get_channel);
+
+STATIC mp_obj_t wifi_monitor_obj_set_channel(mp_obj_t self_in, mp_obj_t channel) {
+ mp_int_t c = mp_obj_get_int(channel);
+ if (c < 1 || c > 13) {
+ mp_raise_ValueError_varg(translate("%q out of bounds"), MP_QSTR_channel);
+ }
+ common_hal_wifi_monitor_set_channel(self_in, c);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(wifi_monitor_set_channel_obj, wifi_monitor_obj_set_channel);
+
+MP_PROPERTY_GETSET(wifi_monitor_channel_obj,
+ (mp_obj_t)&wifi_monitor_get_channel_obj,
+ (mp_obj_t)&wifi_monitor_set_channel_obj);
+
+//| queue: int
+//| """The queue size for buffering the packet."""
+//|
+STATIC mp_obj_t wifi_monitor_obj_get_queue(mp_obj_t self_in) {
+ return common_hal_wifi_monitor_get_queue(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_get_queue_obj, wifi_monitor_obj_get_queue);
+
+MP_PROPERTY_GETTER(wifi_monitor_queue_obj,
+ (mp_obj_t)&wifi_monitor_get_queue_obj);
+
+//| def deinit(self) -> None:
+//| """De-initialize `wifi.Monitor` singleton."""
+//| ...
+//|
+STATIC mp_obj_t wifi_monitor_obj_deinit(mp_obj_t self_in) {
+ common_hal_wifi_monitor_deinit(self_in);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_deinit_obj, wifi_monitor_obj_deinit);
+
+//| def lost(self) -> int:
+//| """Returns the packet loss count. The counter resets after each poll."""
+//| ...
+//|
+STATIC mp_obj_t wifi_monitor_obj_get_lost(mp_obj_t self_in) {
+ return common_hal_wifi_monitor_get_lost(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_lost_obj, wifi_monitor_obj_get_lost);
+
+//| def queued(self) -> int:
+//| """Returns the packet queued count."""
+//| ...
+//|
+STATIC mp_obj_t wifi_monitor_obj_get_queued(mp_obj_t self_in) {
+ if (common_hal_wifi_monitor_deinited()) {
+ return mp_obj_new_int_from_uint(0);
+ }
+ return common_hal_wifi_monitor_get_queued(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_queued_obj, wifi_monitor_obj_get_queued);
+
+//| def packet(self) -> dict:
+//| """Returns the monitor packet."""
+//| ...
+//|
+STATIC mp_obj_t wifi_monitor_obj_get_packet(mp_obj_t self_in) {
+ if (common_hal_wifi_monitor_deinited()) {
+ raise_deinited_error();
+ }
+ return common_hal_wifi_monitor_get_packet(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_monitor_packet_obj, wifi_monitor_obj_get_packet);
+
+STATIC const mp_rom_map_elem_t wifi_monitor_locals_dict_table[] = {
+ // properties
+ { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wifi_monitor_channel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_queue), MP_ROM_PTR(&wifi_monitor_queue_obj) },
+
+ // functions
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wifi_monitor_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_lost), MP_ROM_PTR(&wifi_monitor_lost_obj) },
+ { MP_ROM_QSTR(MP_QSTR_queued), MP_ROM_PTR(&wifi_monitor_queued_obj) },
+ { MP_ROM_QSTR(MP_QSTR_packet), MP_ROM_PTR(&wifi_monitor_packet_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(wifi_monitor_locals_dict, wifi_monitor_locals_dict_table);
+
+const mp_obj_type_t wifi_monitor_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Monitor,
+ .make_new = wifi_monitor_make_new,
+ .locals_dict = (mp_obj_t)&wifi_monitor_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/wifi/Monitor.h b/circuitpython/shared-bindings/wifi/Monitor.h
new file mode 100644
index 0000000..38c52a0
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Monitor.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H
+
+#include "common-hal/wifi/Monitor.h"
+
+const mp_obj_type_t wifi_monitor_type;
+
+void common_hal_wifi_monitor_construct(wifi_monitor_obj_t *self,
+ uint8_t channel, size_t queue);
+void common_hal_wifi_monitor_deinit(wifi_monitor_obj_t *self);
+bool common_hal_wifi_monitor_deinited(void);
+
+void common_hal_wifi_monitor_set_channel(wifi_monitor_obj_t *self, uint8_t channel);
+mp_obj_t common_hal_wifi_monitor_get_channel(wifi_monitor_obj_t *self);
+
+mp_obj_t common_hal_wifi_monitor_get_queue(wifi_monitor_obj_t *self);
+
+mp_obj_t common_hal_wifi_monitor_get_lost(wifi_monitor_obj_t *self);
+
+mp_obj_t common_hal_wifi_monitor_get_queued(wifi_monitor_obj_t *self);
+
+mp_obj_t common_hal_wifi_monitor_get_packet(wifi_monitor_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_MONITOR_H
diff --git a/circuitpython/shared-bindings/wifi/Network.c b/circuitpython/shared-bindings/wifi/Network.c
new file mode 100644
index 0000000..9a457b9
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Network.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/wifi/Network.h"
+
+//| class Network:
+//| """A wifi network provided by a nearby access point.
+//|
+//| """
+//|
+
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `wifi.Network`. They are returned by `wifi.Radio.start_scanning_networks`."""
+//| ...
+//|
+
+//| ssid: str
+//| """String id of the network"""
+//|
+STATIC mp_obj_t wifi_network_get_ssid(mp_obj_t self) {
+ return common_hal_wifi_network_get_ssid(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_ssid_obj, wifi_network_get_ssid);
+
+MP_PROPERTY_GETTER(wifi_network_ssid_obj,
+ (mp_obj_t)&wifi_network_get_ssid_obj);
+
+
+//| bssid: bytes
+//| """BSSID of the network (usually the AP's MAC address)"""
+//|
+STATIC mp_obj_t wifi_network_get_bssid(mp_obj_t self) {
+ return common_hal_wifi_network_get_bssid(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_bssid_obj, wifi_network_get_bssid);
+
+MP_PROPERTY_GETTER(wifi_network_bssid_obj,
+ (mp_obj_t)&wifi_network_get_bssid_obj);
+
+
+//| rssi: int
+//| """Signal strength of the network"""
+//|
+STATIC mp_obj_t wifi_network_get_rssi(mp_obj_t self) {
+ return common_hal_wifi_network_get_rssi(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_rssi_obj, wifi_network_get_rssi);
+
+MP_PROPERTY_GETTER(wifi_network_rssi_obj,
+ (mp_obj_t)&wifi_network_get_rssi_obj);
+
+
+//| channel: int
+//| """Channel number the network is operating on"""
+//|
+STATIC mp_obj_t wifi_network_get_channel(mp_obj_t self) {
+ return common_hal_wifi_network_get_channel(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_channel_obj, wifi_network_get_channel);
+
+MP_PROPERTY_GETTER(wifi_network_channel_obj,
+ (mp_obj_t)&wifi_network_get_channel_obj);
+
+//| country: str
+//| """String id of the country code"""
+//|
+STATIC mp_obj_t wifi_network_get_country(mp_obj_t self) {
+ return common_hal_wifi_network_get_country(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_country_obj, wifi_network_get_country);
+
+MP_PROPERTY_GETTER(wifi_network_country_obj,
+ (mp_obj_t)&wifi_network_get_country_obj);
+
+//| authmode: str
+//| """String id of the authmode"""
+//|
+STATIC mp_obj_t wifi_network_get_authmode(mp_obj_t self) {
+ return common_hal_wifi_network_get_authmode(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_authmode_obj, wifi_network_get_authmode);
+
+MP_PROPERTY_GETTER(wifi_network_authmode_obj,
+ (mp_obj_t)&wifi_network_get_authmode_obj);
+
+STATIC const mp_rom_map_elem_t wifi_network_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_ssid), MP_ROM_PTR(&wifi_network_ssid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bssid), MP_ROM_PTR(&wifi_network_bssid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&wifi_network_rssi_obj) },
+ { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wifi_network_channel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&wifi_network_country_obj) },
+ { MP_ROM_QSTR(MP_QSTR_authmode), MP_ROM_PTR(&wifi_network_authmode_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(wifi_network_locals_dict, wifi_network_locals_dict_table);
+
+const mp_obj_type_t wifi_network_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Network,
+ .locals_dict = (mp_obj_t)&wifi_network_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/wifi/Network.h b/circuitpython/shared-bindings/wifi/Network.h
new file mode 100644
index 0000000..0f07e7b
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Network.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_NETWORK_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_NETWORK_H
+
+#include <stdint.h>
+
+#include "common-hal/wifi/Network.h"
+
+#include "py/objstr.h"
+
+const mp_obj_type_t wifi_network_type;
+
+extern mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self);
+extern mp_obj_t common_hal_wifi_network_get_bssid(wifi_network_obj_t *self);
+extern mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self);
+extern mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self);
+extern mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self);
+extern mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_NETWORK_H
diff --git a/circuitpython/shared-bindings/wifi/Packet.c b/circuitpython/shared-bindings/wifi/Packet.c
new file mode 100644
index 0000000..d21c8b0
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Packet.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/enum.h"
+
+#include "shared-bindings/wifi/Packet.h"
+
+MAKE_ENUM_VALUE(wifi_packet_type, packet, CH, PACKET_CH);
+MAKE_ENUM_VALUE(wifi_packet_type, packet, LEN, PACKET_LEN);
+MAKE_ENUM_VALUE(wifi_packet_type, packet, RAW, PACKET_RAW);
+MAKE_ENUM_VALUE(wifi_packet_type, packet, RSSI, PACKET_RSSI);
+
+//| class Packet:
+//| """The packet parameters."""
+//|
+//| CH: object
+//| """The packet's channel."""
+//|
+//| LEN: object
+//| """The packet's length."""
+//|
+//| RAW: object
+//| """The packet's payload."""
+//|
+//| RSSI: object
+//| """The packet's rssi."""
+//|
+MAKE_ENUM_MAP(wifi_packet) {
+ MAKE_ENUM_MAP_ENTRY(packet, CH),
+ MAKE_ENUM_MAP_ENTRY(packet, LEN),
+ MAKE_ENUM_MAP_ENTRY(packet, RAW),
+ MAKE_ENUM_MAP_ENTRY(packet, RSSI),
+};
+STATIC MP_DEFINE_CONST_DICT(wifi_packet_locals_dict, wifi_packet_locals_table);
+
+MAKE_PRINTER(wifi, wifi_packet);
+
+const mp_obj_type_t wifi_packet_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Packet,
+ .print = wifi_packet_print,
+ .locals_dict = (mp_obj_t)&wifi_packet_locals_dict,
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = mp_generic_unary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/wifi/Packet.h b/circuitpython/shared-bindings/wifi/Packet.h
new file mode 100644
index 0000000..09dfddf
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Packet.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 microDev
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H
+
+#include "py/enum.h"
+
+typedef enum {
+ PACKET_CH,
+ PACKET_LEN,
+ PACKET_RAW,
+ PACKET_RSSI,
+} wifi_packet_t;
+
+extern const mp_obj_type_t wifi_packet_type;
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_PACKET_H
diff --git a/circuitpython/shared-bindings/wifi/Radio.c b/circuitpython/shared-bindings/wifi/Radio.c
new file mode 100644
index 0000000..cf1e9df
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Radio.c
@@ -0,0 +1,542 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/wifi/__init__.h"
+#include "shared-bindings/wifi/AuthMode.h"
+
+#include <regex.h>
+#include <string.h>
+
+#include "py/runtime.h"
+#include "py/objproperty.h"
+
+#define MAC_ADDRESS_LENGTH 6
+
+//| class Radio:
+//| """Native wifi radio.
+//|
+//| This class manages the station and access point functionality of the native
+//| Wifi radio.
+//|
+//| """
+//|
+
+//| def __init__(self) -> None:
+//| """You cannot create an instance of `wifi.Radio`.
+//| Use `wifi.radio` to access the sole instance available."""
+//| ...
+//|
+
+//| enabled: bool
+//| """``True`` when the wifi radio is enabled.
+//| If you set the value to ``False``, any open sockets will be closed.
+//| """
+//|
+STATIC mp_obj_t wifi_radio_get_enabled(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_wifi_radio_get_enabled(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_enabled_obj, wifi_radio_get_enabled);
+
+static mp_obj_t wifi_radio_set_enabled(mp_obj_t self, mp_obj_t value) {
+ const bool enabled = mp_obj_is_true(value);
+
+ common_hal_wifi_radio_set_enabled(self, enabled);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_enabled_obj, wifi_radio_set_enabled);
+
+MP_PROPERTY_GETSET(wifi_radio_enabled_obj,
+ (mp_obj_t)&wifi_radio_get_enabled_obj,
+ (mp_obj_t)&wifi_radio_set_enabled_obj);
+
+//| hostname: Union[str | ReadableBuffer]
+//| """Hostname for wifi interface. When the hostname is altered after interface started/connected
+//| the changes would only be reflected once the interface restarts/reconnects."""
+//|
+STATIC mp_obj_t wifi_radio_get_hostname(mp_obj_t self_in) {
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_wifi_radio_get_hostname(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_hostname_obj, wifi_radio_get_hostname);
+
+STATIC mp_obj_t wifi_radio_set_hostname(mp_obj_t self_in, mp_obj_t hostname_in) {
+ mp_buffer_info_t hostname;
+ mp_get_buffer_raise(hostname_in, &hostname, MP_BUFFER_READ);
+
+ if (hostname.len < 1 || hostname.len > 253) {
+ mp_raise_ValueError(translate("Hostname must be between 1 and 253 characters"));
+ }
+
+ #ifndef CONFIG_IDF_TARGET_ESP32C3
+ regex_t regex; // validate hostname according to RFC 1123
+ regcomp(&regex,"^(([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]{0,61}[a-z0-9])$", REG_EXTENDED | REG_ICASE | REG_NOSUB);
+ if (regexec(&regex, hostname.buf, 0, NULL, 0)) {
+ mp_raise_ValueError(translate("invalid hostname"));
+ }
+ regfree(&regex);
+ #endif
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_wifi_radio_set_hostname(self, hostname.buf);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_hostname_obj, wifi_radio_set_hostname);
+
+MP_PROPERTY_GETSET(wifi_radio_hostname_obj,
+ (mp_obj_t)&wifi_radio_get_hostname_obj,
+ (mp_obj_t)&wifi_radio_set_hostname_obj);
+
+//| mac_address: ReadableBuffer
+//| """MAC address for the station. When the address is altered after interface is connected
+//| the changes would only be reflected once the interface reconnects."""
+//|
+STATIC mp_obj_t wifi_radio_get_mac_address(mp_obj_t self_in) {
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_FROM_PTR(common_hal_wifi_radio_get_mac_address(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_mac_address_obj, wifi_radio_get_mac_address);
+
+STATIC mp_obj_t wifi_radio_set_mac_address(mp_obj_t self_in, mp_obj_t mac_address_in) {
+ mp_buffer_info_t mac_address;
+ mp_get_buffer_raise(mac_address_in, &mac_address, MP_BUFFER_READ);
+
+ if (mac_address.len != MAC_ADDRESS_LENGTH) {
+ mp_raise_ValueError(translate("Invalid MAC address"));
+ }
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_wifi_radio_set_mac_address(self, mac_address.buf);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_mac_address_obj, wifi_radio_set_mac_address);
+
+MP_PROPERTY_GETSET(wifi_radio_mac_address_obj,
+ (mp_obj_t)&wifi_radio_get_mac_address_obj,
+ (mp_obj_t)&wifi_radio_set_mac_address_obj);
+
+//| mac_address_ap: ReadableBuffer
+//| """MAC address for the AP. When the address is altered after interface is started
+//| the changes would only be reflected once the interface restarts."""
+//|
+STATIC mp_obj_t wifi_radio_get_mac_address_ap(mp_obj_t self_in) {
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_FROM_PTR(common_hal_wifi_radio_get_mac_address_ap(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_mac_address_ap_obj, wifi_radio_get_mac_address_ap);
+
+STATIC mp_obj_t wifi_radio_set_mac_address_ap(mp_obj_t self_in, mp_obj_t mac_address_in) {
+ mp_buffer_info_t mac_address;
+ mp_get_buffer_raise(mac_address_in, &mac_address, MP_BUFFER_READ);
+
+ if (mac_address.len != MAC_ADDRESS_LENGTH) {
+ mp_raise_ValueError(translate("Invalid MAC address"));
+ }
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_wifi_radio_set_mac_address_ap(self, mac_address.buf);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_mac_address_ap_obj, wifi_radio_set_mac_address_ap);
+
+MP_PROPERTY_GETSET(wifi_radio_mac_address_ap_obj,
+ (mp_obj_t)&wifi_radio_get_mac_address_ap_obj,
+ (mp_obj_t)&wifi_radio_set_mac_address_ap_obj);
+
+//| def start_scanning_networks(self, *, start_channel: int = 1, stop_channel: int = 11) -> Iterable[Network]:
+//| """Scans for available wifi networks over the given channel range. Make sure the channels are allowed in your country."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_start_scanning_networks(mp_obj_t self_in) {
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_wifi_radio_start_scanning_networks(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_start_scanning_networks_obj, wifi_radio_start_scanning_networks);
+
+//| def stop_scanning_networks(self) -> None:
+//| """Stop scanning for Wifi networks and free any resources used to do it."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_stop_scanning_networks(mp_obj_t self_in) {
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_wifi_radio_stop_scanning_networks(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_scanning_networks_obj, wifi_radio_stop_scanning_networks);
+
+//| def start_station(self) -> None:
+//| """Starts a Station."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_start_station(mp_obj_t self) {
+ common_hal_wifi_radio_start_station(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_start_station_obj, wifi_radio_start_station);
+
+//| def stop_station(self) -> None:
+//| """Stops the Station."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_stop_station(mp_obj_t self) {
+ common_hal_wifi_radio_stop_station(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_station_obj, wifi_radio_stop_station);
+
+//| def start_ap(self,
+//| ssid: Union[str | ReadableBuffer],
+//| password: Union[str | ReadableBuffer] = "",
+//| *,
+//| channel: Optional[int] = 1,
+//| authmode: Optional[AuthMode],
+//| max_connections: Optional[int] = 4) -> None:
+//| """Starts an Access Point with the specified ssid and password.
+//|
+//| If ``channel`` is given, the access point will use that channel unless
+//| a station is already operating on a different channel.
+//|
+//| If ``authmode`` is given, the access point will use that Authentication
+//| mode. If a password is given, ``authmode`` must not be ``OPEN``.
+//| If ``authmode`` isn't given, ``OPEN`` will be used when password isn't provided,
+//| otherwise ``WPA_WPA2_PSK``.
+//|
+//| If ``max_connections`` is given, the access point will allow up to
+//| that number of stations to connect."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_start_ap(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_ssid, ARG_password, ARG_channel, ARG_authmode, ARG_max_connections };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_password, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
+ { MP_QSTR_authmode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_max_connections, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 4} },
+ };
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ uint8_t authmode = 0;
+ if (args[ARG_authmode].u_obj != MP_OBJ_NULL) {
+ mp_obj_iter_buf_t iter_buf;
+ mp_obj_t item, iterable = mp_getiter(args[ARG_authmode].u_obj, &iter_buf);
+ while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
+ authmode |= (1 << (wifi_authmode_t)cp_enum_value(&wifi_authmode_type, item));
+ }
+ }
+
+ mp_buffer_info_t ssid;
+ mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ);
+
+ mp_buffer_info_t password;
+ password.len = 0;
+ if (args[ARG_password].u_obj != MP_OBJ_NULL) {
+ if (authmode == 1) {
+ mp_raise_ValueError(translate("AuthMode.OPEN is not used with password"));
+ } else if (authmode == 0) {
+ authmode = (1 << AUTHMODE_WPA) | (1 << AUTHMODE_WPA2) | (1 << AUTHMODE_PSK);
+ }
+ mp_get_buffer_raise(args[ARG_password].u_obj, &password, MP_BUFFER_READ);
+ if (password.len > 0 && (password.len < 8 || password.len > 63)) {
+ mp_raise_ValueError(translate("WiFi password must be between 8 and 63 characters"));
+ }
+ } else {
+ authmode = 1;
+ }
+
+ common_hal_wifi_radio_start_ap(self, ssid.buf, ssid.len, password.buf, password.len, args[ARG_channel].u_int, authmode, args[ARG_max_connections].u_int);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_start_ap_obj, 1, wifi_radio_start_ap);
+
+//| def stop_ap(self) -> None:
+//| """Stops the Access Point."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_stop_ap(mp_obj_t self) {
+ common_hal_wifi_radio_stop_ap(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_ap_obj, wifi_radio_stop_ap);
+
+//| def connect(self,
+//| ssid: Union[str | ReadableBuffer],
+//| password: Union[str | ReadableBuffer] = "",
+//| *,
+//| channel: Optional[int] = 0,
+//| bssid: Optional[Union[str | ReadableBuffer]] = "",
+//| timeout: Optional[float] = None) -> None:
+//| """Connects to the given ssid and waits for an ip address. Reconnections are handled
+//| automatically once one connection succeeds.
+//|
+//| By default, this will scan all channels and connect to the access point (AP) with the
+//| given ``ssid`` and greatest signal strength (rssi).
+//|
+//| If ``channel`` is given, the scan will begin with the given channel and connect to
+//| the first AP with the given ``ssid``. This can speed up the connection time
+//| significantly because a full scan doesn't occur.
+//|
+//| If ``bssid`` is given, the scan will start at the first channel or the one given and
+//| connect to the AP with the given ``bssid`` and ``ssid``."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_ssid, ARG_password, ARG_channel, ARG_bssid, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_password, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_float_t timeout = 0;
+ if (args[ARG_timeout].u_obj != mp_const_none) {
+ timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ }
+
+ mp_buffer_info_t ssid;
+ ssid.len = 0;
+ mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ);
+ if (ssid.len > 32) {
+ mp_raise_ValueError(translate("ssid can't be more than 32 bytes"));
+ }
+
+ mp_buffer_info_t password;
+ password.len = 0;
+ if (args[ARG_password].u_obj != MP_OBJ_NULL) {
+ mp_get_buffer_raise(args[ARG_password].u_obj, &password, MP_BUFFER_READ);
+ if (password.len > 0 && (password.len < 8 || password.len > 63)) {
+ mp_raise_ValueError(translate("WiFi password must be between 8 and 63 characters"));
+ }
+ }
+
+ #define MAC_ADDRESS_LENGTH 6
+
+ mp_buffer_info_t bssid;
+ bssid.len = 0;
+ // Should probably make sure bssid is just bytes and not something else too
+ if (args[ARG_bssid].u_obj != MP_OBJ_NULL) {
+ mp_get_buffer_raise(args[ARG_bssid].u_obj, &bssid, MP_BUFFER_READ);
+ if (bssid.len != MAC_ADDRESS_LENGTH) {
+ mp_raise_ValueError(translate("Invalid BSSID"));
+ }
+ }
+
+ wifi_radio_error_t error = common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, args[ARG_channel].u_int, timeout, bssid.buf, bssid.len);
+ if (error == WIFI_RADIO_ERROR_AUTH_FAIL) {
+ mp_raise_ConnectionError(translate("Authentication failure"));
+ } else if (error == WIFI_RADIO_ERROR_NO_AP_FOUND) {
+ mp_raise_ConnectionError(translate("No network with that ssid"));
+ } else if (error != WIFI_RADIO_ERROR_NONE) {
+ mp_raise_msg_varg(&mp_type_ConnectionError, translate("Unknown failure %d"), error);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_connect_obj, 1, wifi_radio_connect);
+
+//| ipv4_gateway: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the station gateway when connected to an access point. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_gateway(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_gateway(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_gateway_obj, wifi_radio_get_ipv4_gateway);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_gateway_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_gateway_obj);
+
+//| ipv4_gateway_ap: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the access point gateway, when enabled. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_gateway_ap(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_gateway_ap(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_gateway_ap_obj, wifi_radio_get_ipv4_gateway_ap);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_gateway_ap_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_gateway_ap_obj);
+
+//| ipv4_subnet: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the station subnet when connected to an access point. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_subnet(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_subnet(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_subnet_obj, wifi_radio_get_ipv4_subnet);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_subnet_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_subnet_obj);
+
+//| ipv4_subnet_ap: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the access point subnet, when enabled. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_subnet_ap(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_subnet_ap(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_subnet_ap_obj, wifi_radio_get_ipv4_subnet_ap);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_subnet_ap_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_subnet_ap_obj);
+
+//| ipv4_address: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the station when connected to an access point. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_address(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_address(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_address_obj, wifi_radio_get_ipv4_address);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_address_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_address_obj);
+
+//| ipv4_address_ap: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the access point, when enabled. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_address_ap(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_address_ap(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_address_ap_obj, wifi_radio_get_ipv4_address_ap);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_address_ap_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_address_ap_obj);
+
+//| ipv4_dns: Optional[ipaddress.IPv4Address]
+//| """IP v4 Address of the DNS server in use when connected to an access point. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ipv4_dns(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ipv4_dns(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_dns_obj, wifi_radio_get_ipv4_dns);
+
+MP_PROPERTY_GETTER(wifi_radio_ipv4_dns_obj,
+ (mp_obj_t)&wifi_radio_get_ipv4_dns_obj);
+
+//| ap_info: Optional[Network]
+//| """Network object containing BSSID, SSID, authmode, channel, country and RSSI when connected to an access point. None otherwise."""
+//|
+STATIC mp_obj_t wifi_radio_get_ap_info(mp_obj_t self) {
+ return common_hal_wifi_radio_get_ap_info(self);
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ap_info_obj, wifi_radio_get_ap_info);
+
+MP_PROPERTY_GETTER(wifi_radio_ap_info_obj,
+ (mp_obj_t)&wifi_radio_get_ap_info_obj);
+
+//| def ping(self, ip: ipaddress.IPv4Address, *, timeout: Optional[float] = 0.5) -> Optional[float]:
+//| """Ping an IP to test connectivity. Returns echo time in seconds.
+//| Returns None when it times out."""
+//| ...
+//|
+STATIC mp_obj_t wifi_radio_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_ip, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_ip, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_float_t timeout = 0.5;
+ if (args[ARG_timeout].u_obj != mp_const_none) {
+ timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ }
+
+ mp_int_t time_ms = common_hal_wifi_radio_ping(self, args[ARG_ip].u_obj, timeout);
+ if (time_ms == -1) {
+ return mp_const_none;
+ }
+
+ return mp_obj_new_float(time_ms / 1000.0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_ping_obj, 1, wifi_radio_ping);
+
+STATIC const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&wifi_radio_enabled_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&wifi_radio_hostname_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_mac_address), MP_ROM_PTR(&wifi_radio_mac_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mac_address_ap), MP_ROM_PTR(&wifi_radio_mac_address_ap_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_scanning_networks), MP_ROM_PTR(&wifi_radio_start_scanning_networks_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_scanning_networks), MP_ROM_PTR(&wifi_radio_stop_scanning_networks_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_station), MP_ROM_PTR(&wifi_radio_start_station_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_station), MP_ROM_PTR(&wifi_radio_stop_station_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_ap), MP_ROM_PTR(&wifi_radio_start_ap_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_ap), MP_ROM_PTR(&wifi_radio_stop_ap_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wifi_radio_connect_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_connect_to_enterprise), MP_ROM_PTR(&wifi_radio_connect_to_enterprise_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_ap_info), MP_ROM_PTR(&wifi_radio_ap_info_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_dns), MP_ROM_PTR(&wifi_radio_ipv4_dns_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_gateway), MP_ROM_PTR(&wifi_radio_ipv4_gateway_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_gateway_ap), MP_ROM_PTR(&wifi_radio_ipv4_gateway_ap_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_subnet), MP_ROM_PTR(&wifi_radio_ipv4_subnet_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_subnet_ap), MP_ROM_PTR(&wifi_radio_ipv4_subnet_ap_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&wifi_radio_ipv4_address_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_ipv4_address_ap_obj) },
+
+ // { MP_ROM_QSTR(MP_QSTR_access_point_active), MP_ROM_PTR(&wifi_radio_access_point_active_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_start_access_point), MP_ROM_PTR(&wifi_radio_start_access_point_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_ping), MP_ROM_PTR(&wifi_radio_ping_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(wifi_radio_locals_dict, wifi_radio_locals_dict_table);
+
+const mp_obj_type_t wifi_radio_type = {
+ .base = { &mp_type_type },
+ .name = MP_QSTR_Radio,
+ .locals_dict = (mp_obj_t)&wifi_radio_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/wifi/Radio.h b/circuitpython/shared-bindings/wifi/Radio.h
new file mode 100644
index 0000000..cee9f6e
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/Radio.h
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_RADIO_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_RADIO_H
+
+#include <stdint.h>
+
+#include "common-hal/wifi/Radio.h"
+
+#include "py/objstr.h"
+
+const mp_obj_type_t wifi_radio_type;
+
+typedef enum {
+ // 0 is circuitpython-specific; 1-53 are IEEE; 200+ are Espressif
+ WIFI_RADIO_ERROR_NONE = 0,
+ WIFI_RADIO_ERROR_UNSPECIFIED = 1,
+ WIFI_RADIO_ERROR_AUTH_EXPIRE = 2,
+ WIFI_RADIO_ERROR_AUTH_LEAVE = 3,
+ WIFI_RADIO_ERROR_ASSOC_EXPIRE = 4,
+ WIFI_RADIO_ERROR_ASSOC_TOOMANY = 5,
+ WIFI_RADIO_ERROR_NOT_AUTHED = 6,
+ WIFI_RADIO_ERROR_NOT_ASSOCED = 7,
+ WIFI_RADIO_ERROR_ASSOC_LEAVE = 8,
+ WIFI_RADIO_ERROR_ASSOC_NOT_AUTHED = 9,
+ WIFI_RADIO_ERROR_DISASSOC_PWRCAP_BAD = 10,
+ WIFI_RADIO_ERROR_DISASSOC_SUPCHAN_BAD = 11,
+ WIFI_RADIO_ERROR_IE_INVALID = 13,
+ WIFI_RADIO_ERROR_MIC_FAILURE = 14,
+ WIFI_RADIO_ERROR_4WAY_HANDSHAKE_TIMEOUT = 15,
+ WIFI_RADIO_ERROR_GROUP_KEY_UPDATE_TIMEOUT = 16,
+ WIFI_RADIO_ERROR_IE_IN_4WAY_DIFFERS = 17,
+ WIFI_RADIO_ERROR_GROUP_CIPHER_INVALID = 18,
+ WIFI_RADIO_ERROR_PAIRWISE_CIPHER_INVALID = 19,
+ WIFI_RADIO_ERROR_AKMP_INVALID = 20,
+ WIFI_RADIO_ERROR_UNSUPP_RSN_IE_VERSION = 21,
+ WIFI_RADIO_ERROR_INVALID_RSN_IE_CAP = 22,
+ WIFI_RADIO_ERROR_802_1X_AUTH_FAILED = 23,
+ WIFI_RADIO_ERROR_CIPHER_SUITE_REJECTED = 24,
+ WIFI_RADIO_ERROR_INVALID_PMKID = 53,
+ WIFI_RADIO_ERROR_BEACON_TIMEOUT = 200,
+ WIFI_RADIO_ERROR_NO_AP_FOUND = 201,
+ WIFI_RADIO_ERROR_AUTH_FAIL = 202,
+ WIFI_RADIO_ERROR_ASSOC_FAIL = 203,
+ WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT = 204,
+ WIFI_RADIO_ERROR_CONNECTION_FAIL = 205,
+ WIFI_RADIO_ERROR_AP_TSF_RESET = 206,
+} wifi_radio_error_t;
+
+extern bool common_hal_wifi_radio_get_enabled(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled);
+
+extern mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname);
+
+extern mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_set_mac_address(wifi_radio_obj_t *self, const uint8_t *mac);
+extern mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint8_t *mac);
+
+extern mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self);
+
+extern void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self);
+extern void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self);
+
+extern void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, uint8_t authmode, uint8_t max_connections);
+extern void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self);
+
+extern wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, mp_float_t timeout, uint8_t *bssid, size_t bssid_len);
+
+extern mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_dns(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self);
+extern mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self);
+
+extern mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_RADIO_H
diff --git a/circuitpython/shared-bindings/wifi/ScannedNetworks.c b/circuitpython/shared-bindings/wifi/ScannedNetworks.c
new file mode 100644
index 0000000..0706d8f
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/ScannedNetworks.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/wifi/ScannedNetworks.h"
+
+//| class ScannedNetworks:
+//| """Iterates over all `wifi.Network` objects found while scanning. This object is always created
+//| by a `wifi.Radio`: it has no user-visible constructor."""
+//|
+STATIC mp_obj_t scannednetworks_iternext(mp_obj_t self_in) {
+ mp_check_self(mp_obj_is_type(self_in, &wifi_scannednetworks_type));
+ wifi_scannednetworks_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t network = common_hal_wifi_scannednetworks_next(self);
+ if (network != mp_const_none) {
+ return network;
+ }
+
+ return MP_OBJ_STOP_ITERATION;
+}
+
+//| def __init__(self) -> None:
+//| """Cannot be instantiated directly. Use `wifi.Radio.start_scanning_networks`."""
+//| ...
+//|
+//| def __iter__(self) -> Iterator[Network]:
+//| """Returns itself since it is the iterator."""
+//| ...
+//|
+//| def __next__(self) -> Network:
+//| """Returns the next `wifi.Network`.
+//| Raises `StopIteration` if scanning is finished and no other results are available."""
+//| ...
+//|
+
+const mp_obj_type_t wifi_scannednetworks_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_ScannedNetworks,
+ MP_TYPE_EXTENDED_FIELDS(
+ .getiter = mp_identity_getiter,
+ .iternext = scannednetworks_iternext,
+ )
+};
diff --git a/circuitpython/shared-bindings/wifi/ScannedNetworks.h b/circuitpython/shared-bindings/wifi/ScannedNetworks.h
new file mode 100644
index 0000000..8e0aa43
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/ScannedNetworks.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_SCANNEDNETWORKS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_SCANNEDNETWORKS_H
+
+#include "py/obj.h"
+#include "common-hal/wifi/ScannedNetworks.h"
+
+extern const mp_obj_type_t wifi_scannednetworks_type;
+
+mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_SCANNEDNETWORKS_H
diff --git a/circuitpython/shared-bindings/wifi/__init__.c b/circuitpython/shared-bindings/wifi/__init__.c
new file mode 100644
index 0000000..0f9dee8
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/__init__.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/wifi/__init__.h"
+#include "shared-bindings/wifi/AuthMode.h"
+#include "shared-bindings/wifi/Network.h"
+#include "shared-bindings/wifi/Monitor.h"
+#include "shared-bindings/wifi/Packet.h"
+#include "shared-bindings/wifi/Radio.h"
+
+//| """
+//| The `wifi` module provides necessary low-level functionality for managing
+//| wifi connections. Use `socketpool` for communicating over the network."""
+//|
+//| radio: Radio
+//| """Wifi radio used to manage both station and AP modes.
+//| This object is the sole instance of `wifi.Radio`."""
+//|
+
+// Called when wifi is imported.
+STATIC mp_obj_t wifi___init__(void) {
+ common_hal_wifi_init();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(wifi___init___obj, wifi___init__);
+
+STATIC const mp_rom_map_elem_t wifi_module_globals_table[] = {
+ // Name
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wifi) },
+
+ // Initialization
+ { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&wifi___init___obj) },
+
+ // Classes
+ { MP_ROM_QSTR(MP_QSTR_AuthMode), MP_ROM_PTR(&wifi_authmode_type) },
+ { MP_ROM_QSTR(MP_QSTR_Monitor), MP_ROM_PTR(&wifi_monitor_type) },
+ { MP_ROM_QSTR(MP_QSTR_Network), MP_ROM_PTR(&wifi_network_type) },
+ { MP_ROM_QSTR(MP_QSTR_Packet), MP_ROM_PTR(&wifi_packet_type) },
+ { MP_ROM_QSTR(MP_QSTR_Radio), MP_ROM_PTR(&wifi_radio_type) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_radio), MP_ROM_PTR(&common_hal_wifi_radio_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(wifi_module_globals, wifi_module_globals_table);
+
+const mp_obj_module_t wifi_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&wifi_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_wifi, wifi_module, CIRCUITPY_WIFI);
diff --git a/circuitpython/shared-bindings/wifi/__init__.h b/circuitpython/shared-bindings/wifi/__init__.h
new file mode 100644
index 0000000..e626727
--- /dev/null
+++ b/circuitpython/shared-bindings/wifi/__init__.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H
+
+#include "shared-bindings/wifi/Radio.h"
+
+extern wifi_radio_obj_t common_hal_wifi_radio_obj;
+
+void common_hal_wifi_init(void);
+void common_hal_wifi_gc_collect(void);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H
diff --git a/circuitpython/shared-bindings/zlib/__init__.c b/circuitpython/shared-bindings/zlib/__init__.c
new file mode 100644
index 0000000..65bec24
--- /dev/null
+++ b/circuitpython/shared-bindings/zlib/__init__.c
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Mark Komus
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/builtin.h"
+#include "py/objtuple.h"
+#include "py/binary.h"
+#include "py/parsenum.h"
+
+#include "shared-bindings/zlib/__init__.h"
+
+#include "supervisor/shared/translate.h"
+
+//| """zlib decompression functionality
+//|
+//| The `zlib` module allows limited functionality similar to the CPython zlib library.
+//| This module allows to decompress binary data compressed with DEFLATE algorithm
+//| (commonly used in zlib library and gzip archiver). Compression is not yet implemented."""
+//|
+
+//| def zlib_decompress(data: bytes, wbits: Optional[int] = 0, bufsize: Optional[int] = 0) -> bytes:
+//| """Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
+//| size used during compression (8-15, the dictionary size is power of 2 of
+//| that value). Additionally, if value is positive, *data* is assumed to be
+//| zlib stream (with zlib header). Otherwise, if it's negative, it's assumed
+//| to be raw DEFLATE stream.
+//|
+//| The wbits parameter controls the size of the history buffer (or “window size”), and what header
+//| and trailer format is expected.
+//|
+//| Common wbits values:
+//|
+//| * To decompress deflate format, use wbits = -15
+//| * To decompress zlib format, use wbits = 15
+//| * To decompress gzip format, use wbits = 31
+//|
+//| :param bytes data: data to be decompressed
+//| :param int wbits: DEFLATE dictionary window size used during compression. See above.
+//| :param int bufsize: ignored for compatibility with CPython only
+//| """
+//| ...
+//|
+STATIC mp_obj_t zlib_decompress(size_t n_args, const mp_obj_t *args) {
+ bool is_zlib = true;
+ if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) {
+ is_zlib = false;
+ }
+
+ return common_hal_zlib_decompress(args[0], is_zlib);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(zlib_decompress_obj, 1, 3, zlib_decompress);
+
+STATIC const mp_rom_map_elem_t zlib_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zlib) },
+ { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&zlib_decompress_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(zlib_globals, zlib_globals_table);
+
+const mp_obj_module_t zlib_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&zlib_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_zlib, zlib_module, CIRCUITPY_ZLIB);
diff --git a/circuitpython/shared-bindings/zlib/__init__.h b/circuitpython/shared-bindings/zlib/__init__.h
new file mode 100644
index 0000000..232d08e
--- /dev/null
+++ b/circuitpython/shared-bindings/zlib/__init__.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Mark Komus
+ *
+ * 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.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ZLIB___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_ZLIB___INIT___H
+
+mp_obj_t common_hal_zlib_decompress(mp_obj_t data, bool is_zlib);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ZLIB___INIT___H