diff --git a/.travis.yml b/.travis.yml index 44369ddfee..9a058aa643 100755 --- a/.travis.yml +++ b/.travis.yml @@ -12,20 +12,32 @@ git: # pip packages, and so forth. By gathering activities together in optimal # ways, the "run time" and "total time" of the travis jobs can be minimized. # -# Since at the time of writing Travis generally starts 5 or 6 jobs, the -# builds have been organized into 5 groups of *approximately* equal durations. -# Additionally, the jobs that need extra SDKs are also organized together. +# Builds are organized so some will complete quickly, and others are of +# approximately equal size. Try not to freeze out other Travis users. +# +# Board names are in alphabetical order for easy finding, but grouped by +# Adafruit/modified-Adafruit and Other. Ideally they'd be separated into +# separate jobs, but there are too many. # # When adding new boards, take a look on the travis CI page # https://travis-ci.org/adafruit/circuitpython to which build that installs # that SDK is shortest and add it there. In the case of major re-organizations, # just try to make the builds "about equal in run time" env: - - TRAVIS_TESTS="unix docs translations website" TRAVIS_BOARDS="trinket_m0_haxpress circuitplayground_express mini_sam_m4 grandcentral_m4_express capablerobot_usbhub pygamer pca10056 pca10059 feather_nrf52840_express makerdiary_nrf52840_mdk makerdiary_nrf52840_mdk_usb_dongle particle_boron particle_argon particle_xenon sparkfun_nrf52840_mini electronut_labs_papyr electronut_labs_blip" TRAVIS_SDK=arm:nrf - - TRAVIS_BOARDS="metro_m0_express metro_m4_express metro_m4_airlift_lite pirkey_m0 trellis_m4_express trinket_m0 sparkfun_lumidrive sparkfun_redboard_turbo bast_pro_mini_m0 datum_distance pyruler" TRAVIS_SDK=arm - - TRAVIS_BOARDS="cp32-m4 feather_radiofruit_zigbee gemma_m0 hallowing_m0_express itsybitsy_m0_express itsybitsy_m4_express meowmeow sam32 uchip escornabot_makech pygamer_advance datum_imu" TRAVIS_SDK=arm - - TRAVIS_BOARDS="feather_m0_supersized feather_m0_express_crickit feather_m0_rfm69 feather_m0_rfm9x feather_m4_express arduino_zero arduino_mkr1300 arduino_mkrzero pewpew10 kicksat-sprite ugame10 robohatmm1_m0 robohatmm1_m4 datum_light" TRAVIS_SDK=arm - - TRAVIS_BOARDS="datalore_ip_m4 circuitplayground_express_crickit feather_m0_adalogger feather_m0_basic feather_m0_express catwan_usbstick pyportal sparkfun_samd21_mini sparkfun_samd21_dev pybadge pybadge_airlift datum_weather" TRAVIS_SDK=arm + # Non-board tasks + - TRAVIS_TESTS="unix docs translations website" TRAVIS_BOARDS="" + # Adafruit and Nordic nRF boards + - TRAVIS_BOARDS="circuitplayground_bluefruit feather_nrf52840_express metro_nrf52840_express pca10056 pca10059" TRAVIS_SDK=arm + # Other nRF boards + - TRAVIS_BOARDS="electronut_labs_blip electronut_labs_papyr makerdiary_nrf52840_mdk makerdiary_nrf52840_mdk_usb_dongle particle_argon particle_boron particle_xenon sparkfun_nrf52840_mini" TRAVIS_SDK=arm + # Adafruit and modified Adafruit SAMD21 (M0) + Other SAMD21 (M0) + - TRAVIS_BOARDS="circuitplayground_express circuitplayground_express_crickit feather_m0_adalogger feather_m0_basic feather_m0_express feather_m0_express_crickit feather_m0_rfm69 feather_m0_rfm9x feather_m0_supersized feather_radiofruit_zigbee gemma_m0 hallowing_m0_express " TRAVIS_SDK=arm + - TRAVIS_BOARDS="itsybitsy_m0_express metro_m0_express pirkey_m0 pyruler trinket_m0 trinket_m0_haxpress arduino_mkr1300 arduino_mkrzero arduino_zero bast_pro_mini_m0 catwan_usbstick datum_distance datum_imu datum_weather" TRAVIS_SDK=arm + - TRAVIS_BOARDS="escornabot_makech meowmeow pewpew10 robohatmm1_m0 snekboard sparkfun_lumidrive sparkfun_redboard_turbo sparkfun_samd21_dev sparkfun_samd21_mini uchip ugame10" TRAVIS_SDK=arm + # Adafruit SAMD51 (M4) + Other SAMD51 + - TRAVIS_BOARDS="feather_m4_express grandcentral_m4_express itsybitsy_m4_express metro_m4_airlift_lite metro_m4_express pybadge pybadge_airlift pygamer pygamer_advance" TRAVIS_SDK=arm + - TRAVIS_BOARDS="pyportal pyportal_titano trellis_m4_express capablerobot_usbhub cp32-m4 datalore_ip_m4 datum_light kicksat-sprite mini_sam_m4 robohatmm1_m4 sam32" TRAVIS_SDK=arm + addons: artifacts: @@ -88,7 +100,7 @@ before_script: # Check if there's any board missing in TRAVIS_BOARDS - cd tools && python3 -u travis_new_boards_check.py - cd .. - + # report some good version numbers to the build - gcc --version - (! var_search "${TRAVIS_SDK-}" arm || arm-none-eabi-gcc --version) diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 6d1ae72916..0d2d660e88 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 6d1ae72916cf240ea86185c45f844d59f56d8ec3 +Subproject commit 0d2d660e886de8a1b96778c865c7fa48df5f4ea6 diff --git a/lib/tinyusb b/lib/tinyusb index 1ee9ef4f2b..00c440cb26 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 1ee9ef4f2b7c6acfab6c398a4f57ca22036958f7 +Subproject commit 00c440cb26fbea7fd367623454d8b67855f1372f diff --git a/locale/ID.po b/locale/ID.po index 74682ccef5..93216163ac 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -255,6 +255,7 @@ msgstr "Semua timer untuk pin ini sedang digunakan" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -337,6 +338,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -366,7 +372,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -435,6 +441,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -510,6 +520,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "Tidak bisa menyesuaikan data ke dalam paket advertisment" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -608,7 +622,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Gagal untuk melanjutkan scanning, status: 0x%08lX" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "Gagal untuk menemukan layanan, status: 0x%08lX" @@ -628,17 +642,22 @@ msgstr "Gagal untuk mendapatkan status softdevice, error: 0x%08lX" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, fuzzy, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Gagal untuk membaca nilai atribut, status: 0x%08lX" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Gagal untuk menulis nilai gatts, status: 0x%08lX" @@ -668,6 +687,11 @@ msgstr "Gagal untuk memulai advertisement, status: 0x%08lX" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, fuzzy, c-format msgid "Failed to start scanning, err 0x%04x" @@ -683,12 +707,12 @@ msgstr "Gagal untuk memberhentikan advertisement, status: 0x%08lX" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Gagal untuk menulis nilai atribut, status: 0x%08lX" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Gagal untuk menulis nilai gatts, status: 0x%08lX" @@ -834,10 +858,18 @@ msgstr "Pin-pin tidak valid" msgid "Invalid polarity" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "" @@ -956,13 +988,15 @@ msgstr "" msgid "No such file/directory" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c #, fuzzy msgid "Not connected" msgstr "Tidak dapat menyambungkan ke AP" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "" @@ -1092,6 +1126,7 @@ msgid "Sample rate must be positive" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Nilai sampel terlalu tinggi. Nilai harus kurang dari %d" @@ -1111,7 +1146,7 @@ msgid "Slices not supported" msgstr "" #: ports/nrf/common-hal/bleio/Adapter.c -#, c-format +#, fuzzy, c-format msgid "Soft device assert, id: 0x%08lX, pc: 0x%08lX" msgstr "Dukungan soft device, id: 0x%08lX, pc: 0x%08l" @@ -1180,7 +1215,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1289,6 +1328,19 @@ msgstr "" msgid "Unsupported pull value." msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1388,10 +1440,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "mode compile buruk" @@ -1709,6 +1757,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "'except' standar harus terakhir" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2048,6 +2100,12 @@ msgstr "" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" @@ -2147,8 +2205,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2234,6 +2292,14 @@ msgstr "panjang data string memiliki keganjilan (odd-length)" msgid "offset out of bounds" msgstr "modul tidak ditemukan" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2457,10 +2523,6 @@ msgstr "sintaksis error pada pendeskripsi uctypes" msgid "threshold must be in the range 0-65536" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index f2c406ff52..ee0d8485ac 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -9,6 +9,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-08-21 14:18-0400\n" +"POT-Creation-Date: 2019-08-19 10:22-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -253,6 +254,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -333,6 +335,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -361,7 +368,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -425,6 +432,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -499,6 +510,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -596,7 +611,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "" @@ -613,17 +628,22 @@ msgstr "" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "" @@ -653,6 +673,11 @@ msgstr "" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -668,12 +693,12 @@ msgstr "" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "" @@ -819,10 +844,18 @@ msgstr "" msgid "Invalid polarity" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "" @@ -941,12 +974,14 @@ msgstr "" msgid "No such file/directory" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "" @@ -1072,6 +1107,7 @@ msgid "Sample rate must be positive" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "" @@ -1157,7 +1193,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1265,6 +1305,19 @@ msgstr "" msgid "Unsupported pull value." msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1355,10 +1408,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1675,6 +1724,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2014,6 +2067,12 @@ msgstr "" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" @@ -2112,8 +2171,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2198,6 +2257,14 @@ msgstr "" msgid "offset out of bounds" msgstr "" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2421,10 +2488,6 @@ msgstr "" msgid "threshold must be in the range 0-65536" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index 3ed00c9384..8dfc602009 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -255,6 +255,7 @@ msgstr "Alle timer für diesen Pin werden bereits benutzt" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -337,6 +338,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Der Puffer muss eine Mindestenslänge von 1 haben" @@ -365,7 +371,7 @@ msgid "Can not use dotstar with %s" msgstr "Kann dotstar nicht mit %s verwenden" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -429,6 +435,10 @@ msgstr "Characteristic UUID stimmt nicht mit der Service-UUID überein" msgid "Characteristic already in use by another Service." msgstr "Characteristic wird bereits von einem anderen Dienst verwendet." +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "Schreiben von CharacteristicBuffer ist nicht vorgesehen" @@ -503,6 +513,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "Zu vielen Daten für das advertisement packet" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Die Zielkapazität ist kleiner als destination_length." @@ -600,7 +614,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Der Scanvorgang kann nicht fortgesetzt werden. Status: 0x%04x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "Es konnten keine Dienste gefunden werden" @@ -617,17 +631,22 @@ msgstr "Fehler beim Abrufen des Softdevice-Status" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Kann CCCD value nicht lesen. Status: 0x%04x" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "gatts value konnte nicht gelesen werden. Status: 0x%04x" @@ -657,6 +676,11 @@ msgstr "Kann advertisement nicht starten. Status: 0x%04x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -672,12 +696,12 @@ msgstr "Kann advertisement nicht stoppen. Status: 0x%04x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Kann den Attributwert nicht schreiben. Status: 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "gatts value konnte nicht geschrieben werden. Status: 0x%04x" @@ -825,10 +849,18 @@ msgstr "Ungültige Pins" msgid "Invalid polarity" msgstr "Ungültige Polarität" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Ungültiger Ausführungsmodus" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "Ungültige Anzahl von Stimmen" @@ -954,12 +986,14 @@ msgstr "Kein Speicherplatz auf Gerät" msgid "No such file/directory" msgstr "Keine solche Datei/Verzeichnis" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "Nicht verbunden" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "Spielt nicht" @@ -1089,6 +1123,7 @@ msgid "Sample rate must be positive" msgstr "Abtastrate muss positiv sein" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Abtastrate zu hoch. Wert muss unter %d liegen" @@ -1186,7 +1221,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1296,6 +1335,19 @@ msgstr "Nicht unterstützte Operation" msgid "Unsupported pull value." msgstr "Nicht unterstützter Pull-Wert" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "Viper-Funktionen unterstützen derzeit nicht mehr als 4 Argumente" @@ -1395,10 +1447,6 @@ msgstr "Array/Bytes auf der rechten Seite erforderlich" msgid "attributes not supported yet" msgstr "Attribute werden noch nicht unterstützt" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1715,6 +1763,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "Die Standart-Ausnahmebehandlung muss als letztes sein" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2061,6 +2113,12 @@ msgstr "map buffer zu klein" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "maximale Rekursionstiefe überschritten" @@ -2159,8 +2217,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2245,6 +2303,14 @@ msgstr "String mit ungerader Länge" msgid "offset out of bounds" msgstr "offset außerhalb der Grenzen" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2473,10 +2539,6 @@ msgstr "Syntaxfehler in uctypes Deskriptor" msgid "threshold must be in the range 0-65536" msgstr "threshold muss im Intervall 0-65536 liegen" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/en_US.po b/locale/en_US.po index 5b173fba65..a78c5d4e16 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -253,6 +253,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -333,6 +334,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -361,7 +367,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -425,6 +431,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -499,6 +509,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -596,7 +610,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "" @@ -613,17 +627,22 @@ msgstr "" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "" @@ -653,6 +672,11 @@ msgstr "" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -668,12 +692,12 @@ msgstr "" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "" @@ -819,10 +843,18 @@ msgstr "" msgid "Invalid polarity" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "" @@ -941,12 +973,14 @@ msgstr "" msgid "No such file/directory" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "" @@ -1072,6 +1106,7 @@ msgid "Sample rate must be positive" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "" @@ -1157,7 +1192,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1265,6 +1304,19 @@ msgstr "" msgid "Unsupported pull value." msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1355,10 +1407,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1675,6 +1723,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2014,6 +2066,12 @@ msgstr "" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" @@ -2112,8 +2170,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2198,6 +2256,14 @@ msgstr "" msgid "offset out of bounds" msgstr "" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2421,10 +2487,6 @@ msgstr "" msgid "threshold must be in the range 0-65536" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/en_x_pirate.po b/locale/en_x_pirate.po index fe04b804b2..b51bf9d075 100644 --- a/locale/en_x_pirate.po +++ b/locale/en_x_pirate.po @@ -255,6 +255,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -337,6 +338,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -365,7 +371,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -429,6 +435,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -503,6 +513,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -600,7 +614,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "" @@ -617,17 +631,22 @@ msgstr "" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "" @@ -657,6 +676,11 @@ msgstr "" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -672,12 +696,12 @@ msgstr "" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "" @@ -823,10 +847,18 @@ msgstr "" msgid "Invalid polarity" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "" @@ -945,12 +977,14 @@ msgstr "" msgid "No such file/directory" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "" @@ -1076,6 +1110,7 @@ msgid "Sample rate must be positive" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "" @@ -1161,7 +1196,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1269,6 +1308,19 @@ msgstr "" msgid "Unsupported pull value." msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1359,10 +1411,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1679,6 +1727,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2018,6 +2070,12 @@ msgstr "" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" @@ -2116,8 +2174,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2202,6 +2260,14 @@ msgstr "" msgid "offset out of bounds" msgstr "" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2425,10 +2491,6 @@ msgstr "" msgid "threshold must be in the range 0-65536" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/es.po b/locale/es.po index 35d4bd320d..551f6680c7 100644 --- a/locale/es.po +++ b/locale/es.po @@ -257,6 +257,7 @@ msgstr "Todos los timers para este pin están siendo utilizados" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -333,6 +334,11 @@ msgstr "El brillo no se puede ajustar" msgid "Buffer incorrect size. Should be %d bytes." msgstr "Tamaño de buffer incorrecto. Debe ser de %d bytes." +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/displayio/Display.c msgid "Buffer is not a bytearray." msgstr "" @@ -369,7 +375,7 @@ msgid "Can not use dotstar with %s" msgstr "No se puede usar dotstar con %s" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -433,6 +439,10 @@ msgstr "Características UUID no concide con el Service UUID" msgid "Characteristic already in use by another Service." msgstr "Características ya esta en uso por otro Serivice" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "CharateristicBuffer escritura no proporcionada" @@ -507,6 +517,10 @@ msgstr "Trozo de datos debe seguir fmt chunk" msgid "Data too large for advertisement packet" msgstr "Data es muy grande para el paquete de advertisement." +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Capacidad de destino es mas pequeña que destination_length." @@ -604,7 +618,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "No se puede iniciar el escaneo. err: 0x%02x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "No se puede descubrir servicios" @@ -622,17 +636,22 @@ msgstr "No se puede obtener el estado del softdevice" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "Error al notificar o indicar el valor del atributo, err 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "No se puede leer el valor del atributo. err 0x%02x" #: ports/nrf/common-hal/bleio/Characteristic.c -#, c-format +#: ports/nrf/common-hal/bleio/Descriptor.c +#, fuzzy, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "Error al leer valor del atributo, err 0x%04" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "No se puede escribir el valor del atributo. status: 0x%02x" @@ -662,6 +681,11 @@ msgstr "No se puede inicar el anuncio. err: 0x%04x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -677,12 +701,12 @@ msgstr "No se puede detener el anuncio. err: 0x%04x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "No se puede escribir el valor del atributo. err: 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "No se puede escribir el valor del atributo. err: 0x%04x" @@ -830,10 +854,18 @@ msgstr "pines inválidos" msgid "Invalid polarity" msgstr "Polaridad inválida" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Modo de ejecución inválido." +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "Cuenta de voces inválida" @@ -956,12 +988,14 @@ msgstr "No queda espacio en el dispositivo" msgid "No such file/directory" msgstr "No existe el archivo/directorio" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "No conectado" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "No reproduciendo" @@ -1100,6 +1134,7 @@ msgid "Sample rate must be positive" msgstr "Sample rate debe ser positivo" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Frecuencia de muestreo demasiado alta. Debe ser menor a %d" @@ -1197,8 +1232,12 @@ msgid "Tile height must exactly divide bitmap height" msgstr "La altura del Tile debe dividir exacto la altura del bitmap" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" -msgstr "Los índices de Tile deben ser 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" +msgstr "" #: shared-bindings/displayio/TileGrid.c msgid "Tile width must exactly divide bitmap width" @@ -1306,6 +1345,19 @@ msgstr "Operación no soportada" msgid "Unsupported pull value." msgstr "valor pull no soportado." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "funciones Viper actualmente no soportan más de 4 argumentos." @@ -1404,10 +1456,6 @@ msgstr "array/bytes requeridos en el lado derecho" msgid "attributes not supported yet" msgstr "atributos aún no soportados" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "mal GATT role" - #: py/builtinevex.c msgid "bad compile mode" msgstr "modo de compilación erroneo" @@ -1729,6 +1777,10 @@ msgstr "números decimales no soportados" msgid "default 'except' must be last" msgstr "'except' por defecto deberia estar de último" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2073,6 +2125,12 @@ msgstr "map buffer muy pequeño" msgid "math domain error" msgstr "error de dominio matemático" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profundidad máxima de recursión excedida" @@ -2171,8 +2229,8 @@ msgstr "no hay tal atributo" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2261,6 +2319,14 @@ msgstr "string de longitud impar" msgid "offset out of bounds" msgstr "address fuera de límites" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2488,10 +2554,6 @@ msgstr "error de sintaxis en el descriptor uctypes" msgid "threshold must be in the range 0-65536" msgstr "limite debe ser en el rango 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "el indice del tile fuera de limite" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "time.struct_time() toma un sequencio 9" @@ -2848,6 +2910,9 @@ msgstr "paso cero" #~ msgid "STA required" #~ msgstr "STA requerido" +#~ msgid "Tile indices must be 0 - 255" +#~ msgstr "Los índices de Tile deben ser 0 - 255" + #~ msgid "UART(%d) does not exist" #~ msgstr "UART(%d) no existe" @@ -2867,6 +2932,9 @@ msgstr "paso cero" #~ msgstr "" #~ "Usa esptool para borrar la flash y vuelve a cargar Python en su lugar" +#~ msgid "bad GATT role" +#~ msgstr "mal GATT role" + #~ msgid "buffer too long" #~ msgstr "buffer demasiado largo" @@ -2949,6 +3017,9 @@ msgstr "paso cero" #~ msgid "services includes an object that is not a Service" #~ msgstr "services incluye un objeto que no es servicio" +#~ msgid "tile index out of bounds" +#~ msgstr "el indice del tile fuera de limite" + #~ msgid "too many arguments" #~ msgstr "muchos argumentos" diff --git a/locale/fil.po b/locale/fil.po index 4469ab2775..af9d9c219e 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -257,6 +257,7 @@ msgstr "Lahat ng timers para sa pin na ito ay ginagamit" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -339,6 +340,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Buffer dapat ay hindi baba sa 1 na haba" @@ -368,7 +374,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -433,6 +439,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -510,6 +520,10 @@ msgstr "Dapat sunurin ng Data chunk ang fmt chunk" msgid "Data too large for advertisement packet" msgstr "Hindi makasya ang data sa loob ng advertisement packet" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -611,7 +625,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Hindi maituloy ang pag scan, status: 0x%0xlX" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "Nabigo sa pagdiscover ng services, status: 0x%08lX" @@ -631,17 +645,22 @@ msgstr "Nabigo sa pagkuha ng softdevice state, error: 0x%08lX" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, fuzzy, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Hindi mabasa ang value ng attribute, status: 0x%08lX" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Hindi maisulat ang gatts value, status: 0x%08lX" @@ -671,6 +690,11 @@ msgstr "Hindi masimulaan ang advertisement, status: 0x%08lX" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, fuzzy, c-format msgid "Failed to start scanning, err 0x%04x" @@ -686,12 +710,12 @@ msgstr "Hindi mahinto ang advertisement, status: 0x%08lX" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Hindi maisulat ang attribute value, status: 0x%08lX" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Hindi maisulat ang gatts value, status: 0x%08lX" @@ -839,10 +863,18 @@ msgstr "Mali ang pins" msgid "Invalid polarity" msgstr "Mali ang polarity" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Mali ang run mode." +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "Maling bilang ng voice" @@ -965,13 +997,15 @@ msgstr "" msgid "No such file/directory" msgstr "Walang file/directory" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c #, fuzzy msgid "Not connected" msgstr "Hindi maka connect sa AP" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "Hindi playing" @@ -1105,6 +1139,7 @@ msgid "Sample rate must be positive" msgstr "Sample rate ay dapat positibo" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Sample rate ay masyadong mataas. Ito ay dapat hindi hiigit sa %d" @@ -1200,7 +1235,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1310,6 +1349,19 @@ msgstr "Hindi sinusuportahang operasyon" msgid "Unsupported pull value." msgstr "Hindi suportado ang pull value." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1408,10 +1460,6 @@ msgstr "array/bytes kinakailangan sa kanang bahagi" msgid "attributes not supported yet" msgstr "attributes hindi sinusuportahan" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "masamang mode ng compile" @@ -1735,6 +1783,10 @@ msgstr "decimal numbers hindi sinusuportahan" msgid "default 'except' must be last" msgstr "default 'except' ay dapat sa huli" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2084,6 +2136,12 @@ msgstr "masyadong maliit ang buffer map" msgid "math domain error" msgstr "may pagkakamali sa math domain" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "lumagpas ang maximum recursion depth" @@ -2183,8 +2241,8 @@ msgstr "walang ganoon na attribute" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2270,6 +2328,14 @@ msgstr "odd-length string" msgid "offset out of bounds" msgstr "wala sa sakop ang address" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2498,10 +2564,6 @@ msgstr "may pagkakamali sa sintaks sa uctypes descriptor" msgid "threshold must be in the range 0-65536" msgstr "ang threshold ay dapat sa range 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "time.struct_time() kumukuha ng 9-sequence" diff --git a/locale/fr.po b/locale/fr.po index 3fc0e5e080..a64f04e28c 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -260,6 +260,7 @@ msgstr "Tous les timers pour cette broche sont utilisés" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -344,6 +345,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Le tampon doit être de longueur au moins 1" @@ -373,7 +379,7 @@ msgid "Can not use dotstar with %s" msgstr "Impossible d'utiliser 'dotstar' avec %s" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -439,6 +445,10 @@ msgstr "L'UUID de 'Characteristic' ne correspond pas à l'UUID du Service" msgid "Characteristic already in use by another Service." msgstr "'Characteristic' déjà en utilisation par un autre service" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "Ecriture sur 'CharacteristicBuffer' non fournie" @@ -515,6 +525,10 @@ msgstr "Un bloc de données doit suivre un bloc de format" msgid "Data too large for advertisement packet" msgstr "Données trop volumineuses pour un paquet de diffusion" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "La capacité de destination est plus petite que 'destination_length'." @@ -615,7 +629,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Impossible de poursuivre le scan, err 0x%04x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "Echec de la découverte de services" @@ -636,17 +650,22 @@ msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" "Impossible de notifier ou d'indiquer la valeur de l'attribut, err 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, fuzzy, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Impossible de lire la valeur 'CCCD', err 0x%04x" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "Impossible de lire la valeur de l'attribut, err 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Impossible de lire la valeur de 'gatts', err 0x%04x" @@ -676,6 +695,11 @@ msgstr "Impossible de commencer à diffuser, err 0x%04x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, fuzzy, c-format msgid "Failed to start scanning, err 0x%04x" @@ -691,12 +715,12 @@ msgstr "Echec de l'arrêt de diffusion, err 0x%04x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Impossible d'écrire la valeur de l'attribut, err 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Impossible d'écrire la valeur de 'gatts', err 0x%04x" @@ -847,10 +871,18 @@ msgstr "Broches invalides" msgid "Invalid polarity" msgstr "Polarité invalide" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Mode de lancement invalide." +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c #, fuzzy msgid "Invalid voice count" @@ -974,13 +1006,15 @@ msgstr "Il n'y a plus d'espace libre sur le périphérique" msgid "No such file/directory" msgstr "Fichier/dossier introuvable" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c #, fuzzy msgid "Not connected" msgstr "Non connecté" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "Ne joue pas" @@ -1122,6 +1156,7 @@ msgid "Sample rate must be positive" msgstr "Le taux d'échantillonage doit être positif" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Taux d'échantillonage trop élevé. Doit être inf. à %d" @@ -1221,8 +1256,12 @@ msgid "Tile height must exactly divide bitmap height" msgstr "La hauteur de la tuile doit diviser exactement la hauteur de l'image" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" -msgstr "Les indices des tuiles doivent être compris entre 0 et 255 " +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" +msgstr "" #: shared-bindings/displayio/TileGrid.c msgid "Tile width must exactly divide bitmap width" @@ -1335,6 +1374,19 @@ msgstr "Opération non supportée" msgid "Unsupported pull value." msgstr "Valeur de tirage 'pull' non supportée." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1433,10 +1485,6 @@ msgstr "tableau/octets requis à droite" msgid "attributes not supported yet" msgstr "attribut pas encore supporté" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "mauvais rôle GATT" - #: py/builtinevex.c msgid "bad compile mode" msgstr "mauvais mode de compilation" @@ -1771,6 +1819,10 @@ msgstr "nombres décimaux non supportés" msgid "default 'except' must be last" msgstr "l''except' par défaut doit être en dernier" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2117,6 +2169,12 @@ msgstr "tampon trop petit" msgid "math domain error" msgstr "erreur de domaine math" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profondeur maximale de récursivité dépassée" @@ -2217,8 +2275,8 @@ msgstr "pas de tel attribut" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2306,6 +2364,14 @@ msgstr "chaîne de longueur impaire" msgid "offset out of bounds" msgstr "adresse hors limites" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2540,10 +2606,6 @@ msgstr "erreur de syntaxe dans le descripteur d'uctypes" msgid "threshold must be in the range 0-65536" msgstr "le seuil doit être dans la gamme 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "indice de tuile hors limites" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "time.struct_time() prend une séquence de longueur 9" @@ -2899,6 +2961,9 @@ msgstr "'step' nul" #~ msgid "STA required" #~ msgstr "'STA' requis" +#~ msgid "Tile indices must be 0 - 255" +#~ msgstr "Les indices des tuiles doivent être compris entre 0 et 255 " + #~ msgid "UART(%d) does not exist" #~ msgstr "UART(%d) n'existe pas" @@ -2918,6 +2983,9 @@ msgstr "'step' nul" #~ msgstr "" #~ "Utilisez 'esptool' pour effacer la flash et recharger Python à la place" +#~ msgid "bad GATT role" +#~ msgstr "mauvais rôle GATT" + #~ msgid "buffer too long" #~ msgstr "tampon trop long" @@ -2995,6 +3063,9 @@ msgstr "'step' nul" #~ msgid "services includes an object that is not a Service" #~ msgstr "'services' inclut un object qui n'est pas un 'Service'" +#~ msgid "tile index out of bounds" +#~ msgstr "indice de tuile hors limites" + #~ msgid "too many arguments" #~ msgstr "trop d'arguments" diff --git a/locale/it_IT.po b/locale/it_IT.po index f49402dbd4..296ecc5480 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -112,7 +112,7 @@ msgid "'%s' expects {r0, r1, ...}" msgstr "'%s' aspetta un registro" #: py/emitinlinextensa.c -#, c-format +#, fuzzy, c-format msgid "'%s' integer %d is not within range %d..%d" msgstr "intero '%s' non è nell'intervallo %d..%d" @@ -256,6 +256,7 @@ msgstr "Tutti i timer per questo pin sono in uso" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -339,6 +340,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Il buffer deve essere lungo almeno 1" @@ -368,7 +374,7 @@ msgid "Can not use dotstar with %s" msgstr "dotstar non può essere usato con %s" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -434,6 +440,10 @@ msgstr "caratteristico UUID non assomiglia servizio UUID" msgid "Characteristic already in use by another Service." msgstr "caratteristico già usato da un altro servizio" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "CharacteristicBuffer scritura non dato" @@ -511,6 +521,10 @@ msgstr "" msgid "Data too large for advertisement packet" msgstr "Impossibile inserire dati nel pacchetto di advertisement." +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "La capacità di destinazione è più piccola di destination_length." @@ -611,7 +625,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Impossible iniziare la scansione. status: 0x%02x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "Impossibile fermare advertisement. status: 0x%02x" @@ -630,17 +644,22 @@ msgstr "Impossibile fermare advertisement. status: 0x%02x" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "Notificamento o indicazione di attribute value fallito, err 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, fuzzy, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Impossibile leggere valore dell'attributo. status: 0x%02x" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "Tentative leggere attribute value fallito, err 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Impossibile scrivere valore dell'attributo. status: 0x%02x" @@ -670,6 +689,11 @@ msgstr "Impossibile avviare advertisement. status: 0x%02x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, fuzzy, c-format msgid "Failed to start scanning, err 0x%04x" @@ -685,12 +709,12 @@ msgstr "Impossibile fermare advertisement. status: 0x%02x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Impossibile scrivere valore dell'attributo. status: 0x%02x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Impossibile scrivere valore dell'attributo. status: 0x%02x" @@ -840,10 +864,18 @@ msgstr "Pin non validi" msgid "Invalid polarity" msgstr "Polarità non valida" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Modalità di esecuzione non valida." +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c #, fuzzy msgid "Invalid voice count" @@ -964,13 +996,15 @@ msgstr "Non che spazio sul dispositivo" msgid "No such file/directory" msgstr "Nessun file/directory esistente" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c #, fuzzy msgid "Not connected" msgstr "Impossible connettersi all'AP" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "In pausa" @@ -1110,6 +1144,7 @@ msgid "Sample rate must be positive" msgstr "STA deve essere attiva" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "" @@ -1199,7 +1234,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1309,6 +1348,19 @@ msgstr "Operazione non supportata" msgid "Unsupported pull value." msgstr "Valore di pull non supportato." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "Le funzioni Viper non supportano più di 4 argomenti al momento" @@ -1402,10 +1454,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "attributi non ancora supportati" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1526,7 +1574,7 @@ msgid "can't assign to expression" msgstr "impossibile assegnare all'espressione" #: py/obj.c -#, c-format +#, fuzzy, c-format msgid "can't convert %s to complex" msgstr "non è possibile convertire a complex" @@ -1728,6 +1776,10 @@ msgstr "numeri decimali non supportati" msgid "default 'except' must be last" msgstr "'except' predefinito deve essere ultimo" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2077,6 +2129,12 @@ msgstr "map buffer troppo piccolo" msgid "math domain error" msgstr "errore di dominio matematico" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "profondità massima di ricorsione superata" @@ -2177,8 +2235,8 @@ msgstr "attributo inesistente" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2266,6 +2324,14 @@ msgstr "stringa di lunghezza dispari" msgid "offset out of bounds" msgstr "indirizzo fuori limite" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2496,10 +2562,6 @@ msgstr "errore di sintassi nel descrittore uctypes" msgid "threshold must be in the range 0-65536" msgstr "la soglia deve essere nell'intervallo 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" @@ -2591,7 +2653,7 @@ msgid "unindent does not match any outer indentation level" msgstr "" #: py/objstr.c -#, c-format +#, fuzzy, c-format msgid "unknown conversion specifier %c" msgstr "specificatore di conversione %s sconosciuto" diff --git a/locale/pl.po b/locale/pl.po index 93b988a971..5fb27a7292 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -254,6 +254,7 @@ msgstr "Wszystkie timery tej nóżki w użyciu" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -336,6 +337,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Bufor musi mieć długość 1 lub więcej" @@ -364,7 +370,7 @@ msgid "Can not use dotstar with %s" msgstr "Nie można używać dotstar z %s" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -428,6 +434,10 @@ msgstr "UUID charakterystyki inny niż UUID serwisu" msgid "Characteristic already in use by another Service." msgstr "Charakterystyka w użyciu w innym serwisie" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "Pisanie do CharacteristicBuffer niewspierane" @@ -502,6 +512,10 @@ msgstr "Fragment danych musi następować po fragmencie fmt" msgid "Data too large for advertisement packet" msgstr "Zbyt dużo danych pakietu rozgłoszeniowego" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Pojemność celu mniejsza od destination_length." @@ -557,12 +571,12 @@ msgid "Failed sending command." msgstr "" #: ports/nrf/sd_mutex.c -#, c-format +#, fuzzy, c-format msgid "Failed to acquire mutex, err 0x%04x" msgstr "Nie udało się uzyskać blokady, błąd 0x$04x" #: ports/nrf/common-hal/bleio/Service.c -#, c-format +#, fuzzy, c-format msgid "Failed to add characteristic, err 0x%04x" msgstr "Nie udało się dodać charakterystyki, błąd 0x$04x" @@ -599,7 +613,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Nie udała się kontynuacja skanowania, błąd 0x%04x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "Nie udało się odkryć serwisów" @@ -616,17 +630,22 @@ msgstr "Nie udało się odczytać stanu softdevice" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "Nie udało się powiadomić o wartości atrybutu, błąd 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Nie udało się odczytać CCCD, błąd 0x%04x" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "Nie udało się odczytać wartości atrybutu, błąd 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Nie udało się odczytać gatts, błąd 0x%04x" @@ -656,6 +675,11 @@ msgstr "Nie udało się rozpocząć rozgłaszania, błąd 0x%04x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -671,12 +695,12 @@ msgstr "Nie udało się zatrzymać rozgłaszania, błąd 0x%04x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Nie udało się zapisać atrybutu, błąd 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Nie udało się zapisać gatts, błąd 0x%04x" @@ -824,10 +848,18 @@ msgstr "Złe nóżki" msgid "Invalid polarity" msgstr "Zła polaryzacja" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Zły tryb uruchomienia" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "Zła liczba głosów" @@ -951,12 +983,14 @@ msgstr "Brak miejsca" msgid "No such file/directory" msgstr "Brak pliku/katalogu" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "Nie podłączono" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "Nic nie jest odtwarzane" @@ -1082,6 +1116,7 @@ msgid "Sample rate must be positive" msgstr "Częstotliwość próbkowania musi być dodatnia" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Zbyt wysoka częstotliwość próbkowania. Musi być mniejsza niż %d" @@ -1177,8 +1212,12 @@ msgid "Tile height must exactly divide bitmap height" msgstr "Wysokość bitmapy musi być wielokrotnością wysokości kafelka" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" -msgstr "Indeks kafelka musi być pomiędzy 0 a 255 włącznie" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" +msgstr "" #: shared-bindings/displayio/TileGrid.c msgid "Tile width must exactly divide bitmap width" @@ -1285,6 +1324,19 @@ msgstr "Zła operacja" msgid "Unsupported pull value." msgstr "Zła wartość podciągnięcia." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "Funkcje Viper nie obsługują obecnie więcej niż 4 argumentów" @@ -1379,10 +1431,6 @@ msgstr "tablica/bytes wymagane po prawej stronie" msgid "attributes not supported yet" msgstr "atrybuty nie są jeszcze obsługiwane" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "zła rola GATT" - #: py/builtinevex.c msgid "bad compile mode" msgstr "zły tryb kompilacji" @@ -1699,6 +1747,10 @@ msgstr "liczby dziesiętne nieobsługiwane" msgid "default 'except' must be last" msgstr "domyślny 'except' musi być ostatni" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2039,6 +2091,12 @@ msgstr "bufor mapy zbyt mały" msgid "math domain error" msgstr "błąd domeny" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "przekroczono dozwoloną głębokość rekurencji" @@ -2137,8 +2195,8 @@ msgstr "nie ma takiego atrybutu" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2223,6 +2281,14 @@ msgstr "łańcuch o nieparzystej długości" msgid "offset out of bounds" msgstr "offset poza zakresem" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2448,10 +2514,6 @@ msgstr "błąd składni w deskryptorze uctypes" msgid "threshold must be in the range 0-65536" msgstr "threshold musi być w zakresie 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "indeks kafelka poza zakresem" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "time.struct_time() wymaga 9-elementowej sekwencji" @@ -2706,11 +2768,20 @@ msgstr "zerowy krok" #~ msgid "Must be a Group subclass." #~ msgstr "Musi dziedziczyć z Group." +#~ msgid "Tile indices must be 0 - 255" +#~ msgstr "Indeks kafelka musi być pomiędzy 0 a 255 włącznie" + #~ msgid "UUID integer value not in range 0 to 0xffff" #~ msgstr "Wartość UUID poza zakresem 0 do 0xffff" +#~ msgid "bad GATT role" +#~ msgstr "zła rola GATT" + #~ msgid "interval not in range 0.0020 to 10.24" #~ msgstr "przedział poza zakresem 0.0020 do 10.24" #~ msgid "services includes an object that is not a Service" #~ msgstr "obiekt typu innego niż Service w services" + +#~ msgid "tile index out of bounds" +#~ msgstr "indeks kafelka poza zakresem" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 4bfc9eb65d..82a990ccdb 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -256,6 +256,7 @@ msgstr "Todos os temporizadores para este pino estão em uso" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -336,6 +337,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -365,7 +371,7 @@ msgid "Can not use dotstar with %s" msgstr "" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" +msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c @@ -430,6 +436,10 @@ msgstr "" msgid "Characteristic already in use by another Service." msgstr "" +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "" @@ -506,6 +516,10 @@ msgstr "Pedaço de dados deve seguir o pedaço de cortes" msgid "Data too large for advertisement packet" msgstr "Não é possível ajustar dados no pacote de anúncios." +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -606,7 +620,7 @@ msgstr "" msgid "Failed to continue scanning, err 0x%04x" msgstr "Não é possível iniciar o anúncio. status: 0x%02x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy msgid "Failed to discover services" msgstr "Não pode parar propaganda. status: 0x%02x" @@ -625,17 +639,22 @@ msgstr "Não pode parar propaganda. status: 0x%02x" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, fuzzy, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Não é possível ler o valor do atributo. status: 0x%02x" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Não é possível gravar o valor do atributo. status: 0x%02x" @@ -665,6 +684,11 @@ msgstr "Não é possível iniciar o anúncio. status: 0x%02x" msgid "Failed to start connecting, error 0x%04x" msgstr "" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, fuzzy, c-format msgid "Failed to start scanning, err 0x%04x" @@ -680,12 +704,12 @@ msgstr "Não pode parar propaganda. status: 0x%02x" msgid "Failed to write CCCD, err 0x%04x" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Não é possível gravar o valor do atributo. status: 0x%02x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, fuzzy, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Não é possível gravar o valor do atributo. status: 0x%02x" @@ -833,10 +857,18 @@ msgstr "Pinos inválidos" msgid "Invalid polarity" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "" +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c #, fuzzy msgid "Invalid voice count" @@ -956,13 +988,15 @@ msgstr "" msgid "No such file/directory" msgstr "" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c #, fuzzy msgid "Not connected" msgstr "Não é possível conectar-se ao AP" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "" @@ -1092,6 +1126,7 @@ msgid "Sample rate must be positive" msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Taxa de amostragem muito alta. Deve ser menor que %d" @@ -1177,7 +1212,11 @@ msgid "Tile height must exactly divide bitmap height" msgstr "" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" msgstr "" #: shared-bindings/displayio/TileGrid.c @@ -1286,6 +1325,19 @@ msgstr "" msgid "Unsupported pull value." msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "" @@ -1376,10 +1428,6 @@ msgstr "" msgid "attributes not supported yet" msgstr "atributos ainda não suportados" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "" - #: py/builtinevex.c msgid "bad compile mode" msgstr "" @@ -1699,6 +1747,10 @@ msgstr "" msgid "default 'except' must be last" msgstr "" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2039,6 +2091,12 @@ msgstr "" msgid "math domain error" msgstr "" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "" @@ -2138,8 +2196,8 @@ msgstr "" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2224,6 +2282,14 @@ msgstr "" msgid "offset out of bounds" msgstr "" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2449,10 +2515,6 @@ msgstr "" msgid "threshold must be in the range 0-65536" msgstr "Limite deve estar no alcance de 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index e1637386dd..81653b1d23 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -255,6 +255,7 @@ msgstr "Cǐ yǐn jiǎo de suǒyǒu jìshí qì zhèngzài shǐyòng" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c #: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #: ports/nrf/common-hal/pulseio/PulseOut.c shared-bindings/pulseio/PWMOut.c #: shared-module/_pew/PewPew.c msgid "All timers in use" @@ -337,6 +338,11 @@ msgstr "" msgid "Buffer is too small" msgstr "" +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + #: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "Huǎnchōng qū bìxū zhìshǎo chángdù 1" @@ -365,8 +371,8 @@ msgid "Can not use dotstar with %s" msgstr "Wúfǎ yǔ dotstar yīqǐ shǐyòng %s" #: ports/nrf/common-hal/bleio/Characteristic.c -msgid "Can't set CCCD for local Characteristic" -msgstr "Wúfǎ wéi běndì tèzhēng shèzhì CCCD" +msgid "Can't set CCCD on local Characteristic" +msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/pulseio/PulseIn.c msgid "Cannot delete values" @@ -429,6 +435,10 @@ msgstr "Zìfú UUID bù fúhé fúwù UUID" msgid "Characteristic already in use by another Service." msgstr "Qítā fúwù bùmén yǐ shǐyòng de gōngnéng." +#: shared-bindings/bleio/Service.c +msgid "Characteristic is already attached to a Service" +msgstr "" + #: shared-bindings/bleio/CharacteristicBuffer.c msgid "CharacteristicBuffer writing not provided" msgstr "Wèi tígōng zìfú huǎncún xiě rù" @@ -503,6 +513,10 @@ msgstr "Shùjù kuài bìxū zūnxún fmt qū kuài" msgid "Data too large for advertisement packet" msgstr "Guǎnggào bāo de shùjù tài dà" +#: shared-bindings/bleio/Characteristic.c +msgid "Descriptor is already attached to a Characteristic" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Mùbiāo róngliàng xiǎoyú mùdì de_chángdù." @@ -600,7 +614,7 @@ msgstr "Liánjiē shībài: Chāoshí" msgid "Failed to continue scanning, err 0x%04x" msgstr "Jìxù sǎomiáo shībài, err 0x%04x" -#: ports/nrf/common-hal/bleio/Central.c +#: ports/nrf/common-hal/bleio/__init__.c msgid "Failed to discover services" msgstr "Fāxiàn fúwù shībài" @@ -617,17 +631,22 @@ msgstr "Wúfǎ huòdé ruǎnjiàn shèbèi zhuàngtài" msgid "Failed to notify or indicate attribute value, err 0x%04x" msgstr "Wúfǎ tōngzhī huò xiǎnshì shǔxìng zhí, err 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +msgid "Failed to pair" +msgstr "" + #: ports/nrf/common-hal/bleio/Characteristic.c #, c-format msgid "Failed to read CCCD value, err 0x%04x" msgstr "Dòu qǔ CCCD zhí, err 0x%04x shībài" #: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c #, c-format msgid "Failed to read attribute value, err 0x%04x" msgstr "Dòu qǔ shǔxìng zhí shībài, err 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to read gatts value, err 0x%04x" msgstr "Wúfǎ dòu qǔ gatts zhí, err 0x%04x" @@ -657,6 +676,11 @@ msgstr "Qǐdòng guǎnggào shībài, err 0x%04x" msgid "Failed to start connecting, error 0x%04x" msgstr "Wúfǎ kāishǐ liánjiē, cuòwù 0x%04x" +#: ports/nrf/common-hal/bleio/Peripheral.c +#, c-format +msgid "Failed to start pairing, error 0x%04x" +msgstr "" + #: ports/nrf/common-hal/bleio/Scanner.c #, c-format msgid "Failed to start scanning, err 0x%04x" @@ -672,12 +696,12 @@ msgstr "Wúfǎ tíngzhǐ guǎnggào, err 0x%04x" msgid "Failed to write CCCD, err 0x%04x" msgstr "Wúfǎ xiě rù CCCD, cuòwù 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write attribute value, err 0x%04x" msgstr "Xiě rù shǔxìng zhí shībài, err 0x%04x" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c #, c-format msgid "Failed to write gatts value, err 0x%04x" msgstr "Xiě rù gatts zhí,err 0x%04x shībài" @@ -825,10 +849,18 @@ msgstr "Wúxiào de yǐn jiǎo" msgid "Invalid polarity" msgstr "Wúxiào liǎng jí zhí" +#: shared-bindings/bleio/Characteristic.c +msgid "Invalid properties" +msgstr "" + #: shared-bindings/microcontroller/__init__.c msgid "Invalid run mode." msgstr "Wúxiào de yùnxíng móshì." +#: shared-module/bleio/Attribute.c +msgid "Invalid security_mode" +msgstr "" + #: shared-bindings/audiocore/Mixer.c msgid "Invalid voice count" msgstr "Wúxiào de yǔyīn jìshù" @@ -951,12 +983,14 @@ msgstr "Shèbèi shàng méiyǒu kònggé" msgid "No such file/directory" msgstr "Méiyǒu cǐ lèi wénjiàn/mùlù" -#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/__init__.c shared-bindings/bleio/Central.c #: shared-bindings/bleio/CharacteristicBuffer.c +#: shared-bindings/bleio/Peripheral.c msgid "Not connected" msgstr "Wèi liánjiē" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c msgid "Not playing" msgstr "Wèi bòfàng" @@ -1087,6 +1121,7 @@ msgid "Sample rate must be positive" msgstr "Cǎiyàng lǜ bìxū wèi zhèng shù" #: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/nrf/common-hal/audiopwmio/PWMAudioOut.c #, c-format msgid "Sample rate too high. It must be less than %d" msgstr "Cǎiyàng lǜ tài gāo. Tā bìxū xiǎoyú %d" @@ -1184,8 +1219,12 @@ msgid "Tile height must exactly divide bitmap height" msgstr "Píng pū gāodù bìxū huàfēn wèi tú gāodù" #: shared-bindings/displayio/TileGrid.c -msgid "Tile indices must be 0 - 255" -msgstr "Píng pū zhǐshù bìxū wèi 0 - 255" +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-module/displayio/TileGrid.c +msgid "Tile value out of bounds" +msgstr "" #: shared-bindings/displayio/TileGrid.c msgid "Tile width must exactly divide bitmap width" @@ -1292,6 +1331,19 @@ msgstr "Bù zhīchí de cāozuò" msgid "Unsupported pull value." msgstr "Bù zhīchí de lādòng zhí." +#: ports/nrf/common-hal/bleio/Characteristic.c +msgid "Value length required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + #: py/emitnative.c msgid "Viper functions don't currently support more than 4 arguments" msgstr "Viper hánshù mùqián bù zhīchí chāoguò 4 gè cānshù" @@ -1389,10 +1441,6 @@ msgstr "yòu cè xūyào shùzǔ/zì jié" msgid "attributes not supported yet" msgstr "shǔxìng shàngwèi zhīchí" -#: ports/nrf/common-hal/bleio/Characteristic.c -msgid "bad GATT role" -msgstr "zǒng xiédìng de bùliáng juésè" - #: py/builtinevex.c msgid "bad compile mode" msgstr "biānyì móshì cuòwù" @@ -1711,6 +1759,10 @@ msgstr "bù zhīchí xiǎoshù shù" msgid "default 'except' must be last" msgstr "mòrèn 'except' bìxū shì zuìhòu yīgè" +#: shared-bindings/bleio/Characteristic.c +msgid "descriptors includes an object that is not a Descriptors" +msgstr "" + #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" @@ -2052,6 +2104,12 @@ msgstr "dìtú huǎnchōng qū tài xiǎo" msgid "math domain error" msgstr "shùxué yù cuòwù" +#: ports/nrf/common-hal/bleio/Characteristic.c +#: ports/nrf/common-hal/bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + #: py/runtime.c msgid "maximum recursion depth exceeded" msgstr "chāochū zuìdà dìguī shēndù" @@ -2151,8 +2209,8 @@ msgstr "méiyǒu cǐ shǔxìng" msgid "non-Service found in services" msgstr "" -#: ports/nrf/common-hal/bleio/Central.c -msgid "non-UUID found in service_uuids" +#: ports/nrf/common-hal/bleio/__init__.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" #: py/compile.c @@ -2237,6 +2295,14 @@ msgstr "jīshù zìfú chuàn" msgid "offset out of bounds" msgstr "piānlí biānjiè" +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/nrf/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" @@ -2462,10 +2528,6 @@ msgstr "uctypes miáoshù fú zhōng de yǔfǎ cuòwù" msgid "threshold must be in the range 0-65536" msgstr "yùzhí bìxū zài fànwéi 0-65536" -#: shared-bindings/displayio/TileGrid.c -msgid "tile index out of bounds" -msgstr "kuài suǒyǐn chāochū fànwéi" - #: shared-bindings/time/__init__.c msgid "time.struct_time() takes a 9-sequence" msgstr "time.struct_time() xūyào 9 xùliè" @@ -2561,7 +2623,7 @@ msgid "unknown conversion specifier %c" msgstr "wèizhī de zhuǎnhuàn biāozhù %c" #: py/objstr.c -#, c-format +#, fuzzy, c-format msgid "unknown format code '%c' for object of type '%s'" msgstr "lèixíng '%s' duìxiàng wèizhī de géshì dàimǎ '%c'" @@ -2678,6 +2740,9 @@ msgstr "líng bù" #~ msgid "Can't connect in Peripheral mode" #~ msgstr "Wúfǎ zài biānyuán móshì zhōng liánjiē" +#~ msgid "Can't set CCCD for local Characteristic" +#~ msgstr "Wúfǎ wéi běndì tèzhēng shèzhì CCCD" + #~ msgid "Data too large for the advertisement packet" #~ msgstr "Guǎnggào bāo de shùjù tài dà" @@ -2732,9 +2797,15 @@ msgstr "líng bù" #~ msgid "Only bit maps of 8 bit color or less are supported" #~ msgstr "Jǐn zhīchí 8 wèi yánsè huò xiǎoyú" +#~ msgid "Tile indices must be 0 - 255" +#~ msgstr "Píng pū zhǐshù bìxū wèi 0 - 255" + #~ msgid "UUID integer value not in range 0 to 0xffff" #~ msgstr "UUID zhěngshù zhí bùzài fànwéi 0 zhì 0xffff" +#~ msgid "bad GATT role" +#~ msgstr "zǒng xiédìng de bùliáng juésè" + #~ msgid "expected a DigitalInOut" #~ msgstr "qídài de DigitalInOut" @@ -2747,6 +2818,9 @@ msgstr "líng bù" #~ msgid "services includes an object that is not a Service" #~ msgstr "fúwù bāokuò yīgè bùshì fúwù de wùjiàn" +#~ msgid "tile index out of bounds" +#~ msgstr "kuài suǒyǐn chāochū fànwéi" + #~ msgid "too many arguments" #~ msgstr "tài duō cānshù" diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index 6b5eeddcca..481a420cbc 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -35,6 +35,8 @@ #include "py/mpstate.h" #include "py/runtime.h" +#if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO + static audio_dma_t* audio_dma_state[AUDIO_DMA_CHANNEL_COUNT]; // This cannot be in audio_dma_state because it's volatile. @@ -50,6 +52,18 @@ uint8_t find_free_audio_dma_channel(void) { return channel; } +void audio_dma_disable_channel(uint8_t channel) { + if (channel >= AUDIO_DMA_CHANNEL_COUNT) + return; + dma_disable_channel(channel); +} + +void audio_dma_enable_channel(uint8_t channel) { + if (channel >= AUDIO_DMA_CHANNEL_COUNT) + return; + dma_enable_channel(channel); +} + void audio_dma_convert_signed(audio_dma_t* dma, uint8_t* buffer, uint32_t buffer_length, uint8_t** output_buffer, uint32_t* output_buffer_length, uint8_t* output_spacing) { @@ -252,16 +266,19 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma, } dma_configure(dma_channel, dma_trigger_source, true); - dma_enable_channel(dma_channel); + audio_dma_enable_channel(dma_channel); return AUDIO_DMA_OK; } void audio_dma_stop(audio_dma_t* dma) { - dma_disable_channel(dma->dma_channel); - disable_event_channel(dma->event_channel); - MP_STATE_PORT(playing_audio)[dma->dma_channel] = NULL; - + uint8_t channel = dma->dma_channel; + if (channel < AUDIO_DMA_CHANNEL_COUNT) { + audio_dma_disable_channel(channel); + disable_event_channel(dma->event_channel); + MP_STATE_PORT(playing_audio)[channel] = NULL; + audio_dma_state[channel] = NULL; + } dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT; } @@ -290,7 +307,7 @@ void audio_dma_reset(void) { for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) { audio_dma_state[i] = NULL; audio_dma_pending[i] = false; - dma_disable_channel(i); + audio_dma_disable_channel(i); dma_descriptor(i)->BTCTRL.bit.VALID = false; MP_STATE_PORT(playing_audio)[i] = NULL; } @@ -333,3 +350,4 @@ void audio_dma_background(void) { audio_dma_pending[i] = false; } } +#endif diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h index 53173c2777..9d923c5ce1 100644 --- a/ports/atmel-samd/audio_dma.h +++ b/ports/atmel-samd/audio_dma.h @@ -83,6 +83,9 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t* dma, bool output_signed, uint32_t output_register_address, uint8_t dma_trigger_source); + +void audio_dma_disable_channel(uint8_t channel); +void audio_dma_enable_channel(uint8_t channel); void audio_dma_stop(audio_dma_t* dma); bool audio_dma_get_playing(audio_dma_t* dma); void audio_dma_pause(audio_dma_t* dma); diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 4e88d34e79..6942380706 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -56,7 +56,7 @@ void run_background_tasks(void) { assert_heap_ok(); running_background_tasks = true; - #if (defined(SAMD21) && defined(PIN_PA02)) || defined(SAMD51) + #if CIRCUITPY_AUDIOIO || CIRCUITPY_AUDIOBUSIO audio_dma_background(); #endif #if CIRCUITPY_DISPLAYIO diff --git a/ports/atmel-samd/boards/pyportal_titano/board.c b/ports/atmel-samd/boards/pyportal_titano/board.c new file mode 100644 index 0000000000..0ed1010a1c --- /dev/null +++ b/ports/atmel-samd/boards/pyportal_titano/board.c @@ -0,0 +1,129 @@ +/* + * 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 "boards/board.h" +#include "mpconfigboard.h" +#include "hal/include/hal_gpio.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/displayio/FourWire.h" + +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" + +#include "tick.h" + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + 0x01, DELAY, 100/5, // Soft reset, then delay 10 ms + 0xB9, 3, 0xFF, 0x83, 0x57, // Extension command set + 0xFF, DELAY, 500/5, + 0xB3, 4, 0x80, 0x00, 0x06, 0x06, // 0x80 enables SDO pin (0x00 disables) + 0xB6, 2, 0x01, 0x25, // -1.52V + 0xB0, 1, 0x68, // Normal mode 70Hz, Idle mode 55 Hz + 0xCC, 1, 0x05, + 0xB1, 6, + 0x00, // Not deep standby + 0x15, // BT + 0x1C, // VSPR + 0x1C, // VSNR + 0x83, // AP + 0xAA, // FS + 0xC0, 6, + 0x50, // OPON normal + 0x50, // OPON idle + 0x01, // STBA + 0x3C, // STBA + 0x1E, // STBA + 0x08, // GEN + 0xB4, 7, + 0x02, // NW 0x02 + 0x40, // RTN + 0x00, // DIV + 0x2A, // DUM + 0x2A, // DUM + 0x0D, // GDON + 0x78, // GDOFF + 0xE0, 34, + 0x02, 0x0A, 0x11, 0x1d, 0x23, 0x35, 0x41, 0x4b, 0x4b, + 0x42, 0x3A, 0x27, 0x1B, 0x08, 0x09, 0x03, 0x02, 0x0A, + 0x11, 0x1d, 0x23, 0x35, 0x41, 0x4b, 0x4b, 0x42, 0x3A, + 0x27, 0x1B, 0x08, 0x09, 0x03, 0x00, 0x01, + 0x3a, 1, 0x55, + 0x36, 1, 0x00, + 0x11, DELAY, 150/5, // Exit Sleep, then delay 150 ms + 0x29, DELAY, 50/5 +}; + +void board_init(void) { + busio_spi_obj_t* spi = &displays[0].fourwire_bus.inline_bus; + common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA12, &pin_PA14); + common_hal_busio_spi_never_reset(spi); + + displayio_fourwire_obj_t* bus = &displays[0].fourwire_bus; + bus->base.type = &displayio_fourwire_type; + common_hal_displayio_fourwire_construct(bus, + spi, + &pin_PB05, // TFT_DC Command or data + &pin_PB06, // TFT_CS Chip select + &pin_PA00, // TFT_RST Reset + 24000000); + + displayio_display_obj_t* display = &displays[0].display; + display->base.type = &displayio_display_type; + common_hal_displayio_display_construct(display, + bus, + 480, // Width + 320, // Height + 0, // column start + 0, // row start + 270, // rotation + 16, // Color depth + false, // grayscale + false, // pixels_in_byte_share_row (unused for depths > 8) + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command + MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command + 0x37, // Set vertical scroll command + display_init_sequence, + sizeof(display_init_sequence), + &pin_PB31, // Backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness (ignored) + true, // auto_brightness + false, // single_byte_bounds + false); // data_as_commands +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.h b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.h new file mode 100644 index 0000000000..91c1188108 --- /dev/null +++ b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.h @@ -0,0 +1,39 @@ +#define MICROPY_HW_BOARD_NAME "Adafruit PyPortal Titano" +#define MICROPY_HW_MCU_NAME "samd51j20" + +#define CIRCUITPY_MCU_FAMILY samd51 + + +#define MICROPY_HW_LED_STATUS (&pin_PA27) + +#define MICROPY_HW_NEOPIXEL (&pin_PB22) + +// These are pins not to reset. +// QSPI Data pins +#define MICROPY_PORT_A ( PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11 ) +// QSPI CS, and QSPI SCK +#define MICROPY_PORT_B ( PORT_PB10 | PORT_PB11 | PORT_PB22 ) +#define MICROPY_PORT_C ( 0 ) +#define MICROPY_PORT_D (0) + +#define AUTORESET_DELAY_MS 500 + +// If you change this, then make sure to update the linker scripts as well to +// make sure you don't overwrite code +#define CIRCUITPY_INTERNAL_NVM_SIZE 8192 + +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#define DEFAULT_I2C_BUS_SCL (&pin_PB03) +#define DEFAULT_I2C_BUS_SDA (&pin_PB02) + +#define DEFAULT_SPI_BUS_SCK (&pin_PA13) +#define DEFAULT_SPI_BUS_MOSI (&pin_PA12) +#define DEFAULT_SPI_BUS_MISO (&pin_PA14) + +#define DEFAULT_UART_BUS_RX (&pin_PB13) +#define DEFAULT_UART_BUS_TX (&pin_PB12) + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 diff --git a/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk new file mode 100644 index 0000000000..0ca4383118 --- /dev/null +++ b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk @@ -0,0 +1,16 @@ +LD_FILE = boards/samd51x20-bootloader-external-flash.ld +USB_VID = 0x239A +USB_PID = 0x8054 +USB_PRODUCT = "PyPortal Titano" +USB_MANUFACTURER = "Adafruit Industries LLC" + +CHIP_VARIANT = SAMD51J20A +CHIP_FAMILY = samd51 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 2 +EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, GD25Q64C" +LONGINT_IMPL = MPZ + +# No touch on SAMD51 yet +CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/pyportal_titano/pins.c b/ports/atmel-samd/boards/pyportal_titano/pins.c new file mode 100644 index 0000000000..6bc0a504a4 --- /dev/null +++ b/ports/atmel-samd/boards/pyportal_titano/pins.c @@ -0,0 +1,94 @@ +#include "shared-bindings/board/__init__.h" + +#include "boards/board.h" +#include "shared-module/displayio/__init__.h" + +// This mapping only includes functional names because pins broken +// out on connectors are labeled with their MCU name available from +// microcontroller.pin. +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AUDIO_OUT), MP_ROM_PTR(&pin_PA02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, // analog out/in + { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_PA27) }, + + // Light sensor + { MP_OBJ_NEW_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_PA07) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PA07) }, + + // STEMMA connectors + { MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA04) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA04) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA05) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) }, + + // Indicator LED + { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_PB23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL),MP_ROM_PTR(&pin_PB22) }, + + // LCD pins + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_PA00) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RD), MP_ROM_PTR(&pin_PB04) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RS), MP_ROM_PTR(&pin_PB05) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_PB06) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_TE), MP_ROM_PTR(&pin_PB07) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_WR), MP_ROM_PTR(&pin_PB09) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_PB09) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_PB31) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA0), MP_ROM_PTR(&pin_PA16) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA1), MP_ROM_PTR(&pin_PA17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA2), MP_ROM_PTR(&pin_PA18) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA3), MP_ROM_PTR(&pin_PA19) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA4), MP_ROM_PTR(&pin_PA20) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA5), MP_ROM_PTR(&pin_PA21) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA6), MP_ROM_PTR(&pin_PA22) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LCD_DATA7), MP_ROM_PTR(&pin_PA23) }, + + // Touch pins + { MP_OBJ_NEW_QSTR(MP_QSTR_TOUCH_YD), MP_ROM_PTR(&pin_PB00) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TOUCH_XL), MP_ROM_PTR(&pin_PB01) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TOUCH_YU), MP_ROM_PTR(&pin_PA06) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TOUCH_XR), MP_ROM_PTR(&pin_PB08) }, + + // ESP control + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_CS), MP_ROM_PTR(&pin_PB14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_GPIO0), MP_ROM_PTR(&pin_PB15) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_BUSY), MP_ROM_PTR(&pin_PB16) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RESET), MP_ROM_PTR(&pin_PB17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RTS), MP_ROM_PTR(&pin_PA15) }, + + // UART + { MP_OBJ_NEW_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PB13) }, + + // SPI + { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI),MP_ROM_PTR(&pin_PA12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SCK),MP_ROM_PTR(&pin_PA13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MISO),MP_ROM_PTR(&pin_PA14) }, + + // I2C + { MP_OBJ_NEW_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_PB02) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_PB03) }, + + // SD Card + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS),MP_ROM_PTR(&pin_PB30) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CARD_DETECT),MP_ROM_PTR(&pin_PA01) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + // TFT control pins + {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(&pin_PB31)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_PA12)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_PA13)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_MISO), MP_ROM_PTR(&pin_PA14)}, + {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_PA00)}, + {MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_PB06)}, + {MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_PB05)}, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/boards/snekboard/board.c b/ports/atmel-samd/boards/snekboard/board.c new file mode 100644 index 0000000000..c8e20206a1 --- /dev/null +++ b/ports/atmel-samd/boards/snekboard/board.c @@ -0,0 +1,38 @@ +/* + * 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 "boards/board.h" + +void board_init(void) +{ +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.h b/ports/atmel-samd/boards/snekboard/mpconfigboard.h new file mode 100644 index 0000000000..a349143d91 --- /dev/null +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.h @@ -0,0 +1,35 @@ +#define MICROPY_HW_BOARD_NAME "keithp.com snekboard" +#define MICROPY_HW_MCU_NAME "samd21g18" + +#define MICROPY_HW_LED_STATUS (&pin_PA02) + +#define MICROPY_HW_NEOPIXEL (&pin_PB11) + +#define SPI_FLASH_MOSI_PIN &pin_PB22 +#define SPI_FLASH_MISO_PIN &pin_PB03 +#define SPI_FLASH_SCK_PIN &pin_PB23 +#define SPI_FLASH_CS_PIN &pin_PA27 + +// These are pins not to reset. +#define MICROPY_PORT_A (PORT_PB11) +#define MICROPY_PORT_B ( 0 ) +#define MICROPY_PORT_C ( 0 ) + + +// If you change this, then make sure to update the linker scripts as well to +// make sure you don't overwrite code. +#define CIRCUITPY_INTERNAL_NVM_SIZE 256 + +#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#define BOARD_HAS_CRYSTAL 0 + +#define DEFAULT_I2C_BUS_SCL (&pin_PA08) /* ANALOG 5 */ +#define DEFAULT_I2C_BUS_SDA (&pin_PA09) /* ANALOG 6 */ + +#define DEFAULT_UART_BUS_RX (&pin_PB08) /* ANALOG 1 */ +#define DEFAULT_UART_BUS_TX (&pin_PB09) /* ANALOG 2 */ + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk new file mode 100644 index 0000000000..9892ade8f2 --- /dev/null +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -0,0 +1,16 @@ +LD_FILE = boards/samd21x18-bootloader-external-flash.ld +USB_VID = 0x239A +USB_PID = 0x804E +USB_PRODUCT = "snekboard" +USB_MANUFACTURER = "keithp.com" + +CHIP_VARIANT = SAMD21G18A +CHIP_FAMILY = samd21 + +SPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = "W25Q16JV_IQ" +LONGINT_IMPL = MPZ + +CFLAGS_INLINE_LIMIT = 60 +SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/boards/snekboard/pins.c b/ports/atmel-samd/boards/snekboard/pins.c new file mode 100644 index 0000000000..48bdc672e0 --- /dev/null +++ b/ports/atmel-samd/boards/snekboard/pins.c @@ -0,0 +1,28 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA09) }, + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_PA11) }, + { MP_ROM_QSTR(MP_QSTR_POWER1), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_DIR1), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_POWER2), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_DIR2), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_POWER3), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_DIR3), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_POWER4), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_DIR4), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PB11) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index 8b308b60b0..76010a6843 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -385,7 +385,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se init_event_channel_interrupt(event_channel, CORE_GCLK, EVSYS_ID_GEN_DMAC_CH_0 + dma_channel); // Turn on serializer now to get it in sync with DMA. i2s_set_serializer_enable(self->serializer, true); - dma_enable_channel(dma_channel); + audio_dma_enable_channel(dma_channel); // Record uint32_t buffers_processed = 0; @@ -408,9 +408,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se // If wait_counts exceeds the max count, buffer has probably stopped filling; // DMA may have missed an I2S trigger event. while (!event_interrupt_active(event_channel) && ++wait_counts < MAX_WAIT_COUNTS) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } // The mic is running all the time, so we don't need to wait the usual 10msec or 100msec @@ -466,7 +464,7 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se } disable_event_channel(event_channel); - dma_disable_channel(dma_channel); + audio_dma_disable_channel(dma_channel); // Turn off serializer, but leave clock on, to avoid mic startup delay. i2s_set_serializer_enable(self->serializer, false); diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index a75abd324b..90f1aa41f6 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -69,9 +69,7 @@ static void ramp_value(uint16_t start, uint16_t end) { DAC->DATA.reg = value; DAC->DATABUF.reg = value; common_hal_mcu_delay_us(50); - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } } #endif @@ -94,9 +92,7 @@ static void ramp_value(uint16_t start, uint16_t end) { DAC->DATABUF[1].reg = value; common_hal_mcu_delay_us(50); - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } } #endif diff --git a/ports/atmel-samd/common-hal/busio/UART.c b/ports/atmel-samd/common-hal/busio/UART.c index f04594842e..2505e894af 100644 --- a/ports/atmel-samd/common-hal/busio/UART.c +++ b/ports/atmel-samd/common-hal/busio/UART.c @@ -291,13 +291,11 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t // Reset the timeout on every character read. start_ticks = ticks_ms; } -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; + RUN_BACKGROUND_TASKS; // Allow user to break out of a timeout with a KeyboardInterrupt. if (mp_hal_is_interrupted()) { break; } -#endif // If we are zero timeout, make sure we don't loop again (in the event // we read in under 1ms) if (self->timeout_ms == 0) { @@ -339,9 +337,7 @@ size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, done = true; break; } - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } if (!done) { diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index 528a5c808a..8b8bc6dc68 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -198,9 +198,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu while(pulse_index < length) { // Do other things while we wait. The interrupts will handle sending the // signal. - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } tc->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.c b/ports/atmel-samd/common-hal/touchio/TouchIn.c index 9fb3a2ea1a..71886089c4 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.c +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.c @@ -51,9 +51,7 @@ static uint16_t get_raw_reading(touchio_touchin_obj_t *self) { while (!adafruit_ptc_is_conversion_finished(PTC)) { // wait - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } return adafruit_ptc_get_conversion_result(PTC); diff --git a/ports/atmel-samd/mphalport.c b/ports/atmel-samd/mphalport.c index 5c34a576a8..957bf6073e 100644 --- a/ports/atmel-samd/mphalport.c +++ b/ports/atmel-samd/mphalport.c @@ -53,9 +53,7 @@ void mp_hal_delay_ms(mp_uint_t delay) { uint64_t start_tick = ticks_ms; uint64_t duration = 0; while (duration < delay) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; // Check to see if we've been CTRL-Ced by autoreload or the user. if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)) || MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 9da2c498d0..9a461f9d82 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -95,8 +95,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-inline -fno-ipa-sra else CFLAGS += -Os -DNDEBUG - # TODO: Test with -flto - ### CFLAGS += -flto + CFLAGS += -flto -flto-partition=none endif @@ -185,8 +184,7 @@ SRC_C += \ # USB source files for nrf52840 ifeq ($(MCU_SUB_VARIANT),nrf52840) SRC_C += \ - lib/tinyusb/src/portable/nordic/nrf5x/dcd_nrf5x.c \ - lib/tinyusb/src/portable/nordic/nrf5x/hal_nrf5x.c + lib/tinyusb/src/portable/nordic/nrf5x/dcd_nrf5x.c endif SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ diff --git a/ports/nrf/background.c b/ports/nrf/background.c index 9c4f3ab27e..453bc96dfb 100644 --- a/ports/nrf/background.c +++ b/ports/nrf/background.c @@ -33,6 +33,10 @@ #include "shared-module/displayio/__init__.h" #endif +#if CIRCUITPY_AUDIOPWMIO +#include "common-hal/audiopwmio/PWMAudioOut.h" +#endif + static bool running_background_tasks = false; void background_tasks_reset(void) { @@ -47,6 +51,9 @@ void run_background_tasks(void) { running_background_tasks = true; filesystem_background(); usb_background(); +#if CIRCUITPY_AUDIOPWMIO + audiopwmout_background(); +#endif #if CIRCUITPY_DISPLAYIO displayio_refresh_displays(); diff --git a/ports/nrf/bluetooth/ble_uart.c b/ports/nrf/bluetooth/ble_uart.c index 91d10cff15..d83cf3980a 100644 --- a/ports/nrf/bluetooth/ble_uart.c +++ b/ports/nrf/bluetooth/ble_uart.c @@ -138,9 +138,7 @@ void ble_uart_init(void) { m_cccd_enabled = false; while (!m_cccd_enabled) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } } @@ -150,9 +148,7 @@ bool ble_uart_connected(void) { char ble_uart_rx_chr(void) { while (isBufferEmpty(&m_rx_ring_buffer)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } uint8_t byte; diff --git a/ports/nrf/boards/circuitplayground_bluefruit/board.c b/ports/nrf/boards/circuitplayground_bluefruit/board.c new file mode 100644 index 0000000000..4421970eef --- /dev/null +++ b/ports/nrf/boards/circuitplayground_bluefruit/board.c @@ -0,0 +1,38 @@ +/* + * 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.h b/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.h new file mode 100644 index 0000000000..04c7e8d606 --- /dev/null +++ b/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * 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 "nrfx/hal/nrf_gpio.h" + +#define MICROPY_HW_BOARD_NAME "Adafruit Circuit Playground Bluefruit" +#define MICROPY_HW_MCU_NAME "nRF52840" +#define MICROPY_PY_SYS_PLATFORM "CircuitPlaygroundBluefruit" + +#define FLASH_SIZE (0x100000) +#define FLASH_PAGE_SIZE (4096) + +#define MICROPY_HW_NEOPIXEL (&pin_P0_13) + +#define MICROPY_HW_LED_STATUS (&pin_P1_14) + +#if QSPI_FLASH_FILESYSTEM +#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 21) +#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 23) +#define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(1, 00) +#define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 22) +#define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 19) +#define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(0, 15) +#endif + +#if SPI_FLASH_FILESYSTEM +#define SPI_FLASH_MOSI_PIN &pin_P0_21 +#define SPI_FLASH_MISO_PIN &pin_P0_23 +#define SPI_FLASH_SCK_PIN &pin_P0_19 +#define SPI_FLASH_CS_PIN &pin_P0_15 +#endif + +#define CIRCUITPY_AUTORELOAD_DELAY_MS 500 + +#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) + +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#define BOARD_HAS_CRYSTAL 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_P0_04) +#define DEFAULT_I2C_BUS_SDA (&pin_P0_05) + +#define DEFAULT_SPI_BUS_SCK (&pin_P0_05) +#define DEFAULT_SPI_BUS_MOSI (&pin_P1_03) +#define DEFAULT_SPI_BUS_MISO (&pin_P0_29) + +#define DEFAULT_UART_BUS_RX (&pin_P0_30) +#define DEFAULT_UART_BUS_TX (&pin_P0_14) diff --git a/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.mk b/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.mk new file mode 100644 index 0000000000..dbb32629c6 --- /dev/null +++ b/ports/nrf/boards/circuitplayground_bluefruit/mpconfigboard.mk @@ -0,0 +1,26 @@ +USB_VID = 0x239A +USB_PID = 0x8046 +USB_PRODUCT = "Circuit Playground Bluefruit" +USB_MANUFACTURER = "Adafruit Industries LLC" + +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52840 +MCU_CHIP = nrf52840 +SD ?= s140 +SOFTDEV_VERSION ?= 6.1.0 + +BOOT_SETTING_ADDR = 0xFF000 + +ifeq ($(SD),) + LD_FILE = boards/nrf52840_1M_256k.ld +else + LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld + CIRCUITPY_BLEIO = 1 +endif + +NRF_DEFINES += -DNRF52840_XXAA -DNRF52840 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = "GD25Q16C" diff --git a/ports/nrf/boards/circuitplayground_bluefruit/pins.c b/ports/nrf/boards/circuitplayground_bluefruit/pins.c new file mode 100644 index 0000000000..5566516795 --- /dev/null +++ b/ports/nrf/boards/circuitplayground_bluefruit/pins.c @@ -0,0 +1,71 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_AUDIO), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_P0_26) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_05) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_29) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_29) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_03) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P0_03) }, + + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_04) }, + + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_05) }, + + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_30) }, + + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_P0_14) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_14) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_14) }, + + { MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_P0_28) }, + + { MP_ROM_QSTR(MP_QSTR_TEMPERATURE), MP_ROM_PTR(&pin_P0_31) }, + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_P0_31) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_PTR(&pin_P1_02) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P1_02) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_PTR(&pin_P1_15) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_15) }, + + { MP_ROM_QSTR(MP_QSTR_SLIDE_SWITCH), MP_ROM_PTR(&pin_P1_06) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P1_06) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P1_14) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_P0_13) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P0_13) }, + + { MP_ROM_QSTR(MP_QSTR_MICROPHONE_CLOCK), MP_ROM_PTR(&pin_P0_17) }, + { MP_ROM_QSTR(MP_QSTR_MICROPHONE_DATA), MP_ROM_PTR(&pin_P0_16) }, + + { MP_ROM_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_ACCELEROMETER_SDA), MP_ROM_PTR(&pin_P1_10) }, + { MP_ROM_QSTR(MP_QSTR_ACCELEROMETER_SCL), MP_ROM_PTR(&pin_P1_12) }, + + { MP_ROM_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_P1_04) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h index e1f43e3c93..70ccffc3f3 100644 --- a/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h +++ b/ports/nrf/boards/feather_nrf52840_express/mpconfigboard.h @@ -27,8 +27,6 @@ #include "nrfx/hal/nrf_gpio.h" -#define FEATHER52840 - #define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "Feather52840Express" diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py deleted file mode 100644 index d1cfd5b706..0000000000 --- a/ports/nrf/boards/make-pins.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -"""Creates the pin file for the nRF5.""" - -from __future__ import print_function - -import argparse -import sys -import csv - - -def parse_port_pin(name_str): - """Parses a string and returns a (port-num, pin-num) tuple.""" - if len(name_str) < 4: - raise ValueError("Expecting pin name to be at least 5 charcters.") - if name_str[0] != 'P': - raise ValueError("Expecting pin name to start with P") - if name_str[1] not in ('0', '1'): - raise ValueError("Expecting pin port to be in 0 or 1") - port = ord(name_str[1]) - ord('0') - pin_str = name_str[3:] - if not pin_str.isdigit(): - raise ValueError("Expecting numeric pin number.") - return (port, int(pin_str)) - - -class Pin(object): - """Holds the information associated with a pin.""" - - def __init__(self, port, pin): - self.port = port - self.pin = pin - self.adc_channel = '0' - self.board_pin = False - - def cpu_pin_name(self): - return 'P{:d}_{:02d}'.format(self.port, self.pin) - - def is_board_pin(self): - return self.board_pin - - def set_is_board_pin(self): - self.board_pin = True - - def parse_adc(self, adc_str): - if (adc_str[:3] != 'AIN'): - return - self.adc_channel = 'SAADC_CH_PSELP_PSELP_AnalogInput%d' % int(adc_str[3]) - - def print(self): - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s});'.format( - self.cpu_pin_name(), self.cpu_pin_name(), - self.port, self.pin, self.adc_channel)) - - def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) - - -class NamedPin(object): - - def __init__(self, name, pin): - self._name = name - self._pin = pin - - def pin(self): - return self._pin - - def name(self): - return self._name - - -class Pins(object): - - def __init__(self): - self.cpu_pins = [] # list of NamedPin objects - self.board_pins = [] # list of NamedPin objects - - def find_pin(self, port_num, pin_num): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.port == port_num and pin.pin == pin_num: - return pin - - def parse_af_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[0]) - except: - continue - pin = Pin(port_num, pin_num) - if len(row) > 1: - pin.parse_adc(row[1]) - self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) - - def parse_board_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[1]) - except: - continue - pin = self.find_pin(port_num, pin_num) - if pin: - pin.set_is_board_pin() - self.board_pins.append(NamedPin(row[0], pin)) - - def print_named(self, label, named_pins): - print('') - print('STATIC const mp_rom_map_elem_t {:s}_table[] = {{'.format(label)) - for named_pin in named_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) - print('};') - print('MP_DEFINE_CONST_DICT({:s}, {:s}_table);'.format(label, label)) - - def print(self): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print() - self.print_named('mcu_pin_globals', self.cpu_pins) - self.print_named('board_module_globals', self.board_pins) - - def print_header(self, hdr_filename): - with open(hdr_filename, 'wt') as hdr_file: - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print_header(hdr_file) - - def print_qstr(self, qstr_filename): - with open(qstr_filename, 'wt') as qstr_file: - qstr_set = set([]) - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - qstr_set |= set([named_pin.name()]) - for named_pin in self.board_pins: - qstr_set |= set([named_pin.name()]) - for qstr in sorted(qstr_set): - print('Q({})'.format(qstr), file=qstr_file) - - -def main(): - parser = argparse.ArgumentParser( - prog="make-pins.py", - usage="%(prog)s [options] [command]", - description="Generate board specific pin file" - ) - parser.add_argument( - "-a", "--af", - dest="af_filename", - help="Specifies the alternate function file for the chip", - default="nrf_af.csv" - ) - parser.add_argument( - "-b", "--board", - dest="board_filename", - help="Specifies the board file", - ) - parser.add_argument( - "-p", "--prefix", - dest="prefix_filename", - help="Specifies beginning portion of generated pins file", - default="nrf52_prefix.c" - ) - parser.add_argument( - "-q", "--qstr", - dest="qstr_filename", - help="Specifies name of generated qstr header file", - default="build/pins_qstr.h" - ) - parser.add_argument( - "-r", "--hdr", - dest="hdr_filename", - help="Specifies name of generated pin header file", - default="build/pins.h" - ) - args = parser.parse_args(sys.argv[1:]) - - pins = Pins() - - print('// This file was automatically generated by make-pins.py') - print('//') - if args.af_filename: - print('// --af {:s}'.format(args.af_filename)) - pins.parse_af_file(args.af_filename) - - if args.board_filename: - print('// --board {:s}'.format(args.board_filename)) - pins.parse_board_file(args.board_filename) - - if args.prefix_filename: - print('// --prefix {:s}'.format(args.prefix_filename)) - print('') - with open(args.prefix_filename, 'r') as prefix_file: - print(prefix_file.read()) - pins.print() - pins.print_header(args.hdr_filename) - pins.print_qstr(args.qstr_filename) - - -if __name__ == "__main__": - main() diff --git a/ports/nrf/boards/metro_nrf52840_express/board.c b/ports/nrf/boards/metro_nrf52840_express/board.c new file mode 100644 index 0000000000..4421970eef --- /dev/null +++ b/ports/nrf/boards/metro_nrf52840_express/board.c @@ -0,0 +1,38 @@ +/* + * 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.h b/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.h new file mode 100644 index 0000000000..520eef90d9 --- /dev/null +++ b/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.h @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * 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 "nrfx/hal/nrf_gpio.h" + +#define MICROPY_HW_BOARD_NAME "Adafruit Metro nRF52840 Express" +#define MICROPY_HW_MCU_NAME "nRF52840" +#define MICROPY_PY_SYS_PLATFORM "Metro52840Express" + +#define FLASH_SIZE (0x100000) +#define FLASH_PAGE_SIZE (4096) + +#define MICROPY_HW_NEOPIXEL (&pin_P0_13) + +#define MICROPY_HW_LED_STATUS (&pin_P1_13) + +#if QSPI_FLASH_FILESYSTEM +#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 17) +#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 23) +#define MICROPY_QSPI_DATA2 NRF_GPIO_PIN_MAP(0, 22) +#define MICROPY_QSPI_DATA3 NRF_GPIO_PIN_MAP(0, 21) +#define MICROPY_QSPI_SCK NRF_GPIO_PIN_MAP(0, 19) +#define MICROPY_QSPI_CS NRF_GPIO_PIN_MAP(0, 20) +#endif + +#if SPI_FLASH_FILESYSTEM +#define SPI_FLASH_MOSI_PIN &pin_P0_17 +#define SPI_FLASH_MISO_PIN &pin_P0_23 +#define SPI_FLASH_SCK_PIN &pin_P0_19 +#define SPI_FLASH_CS_PIN &pin_P0_20 +#endif + +#define CIRCUITPY_AUTORELOAD_DELAY_MS 500 + +#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) + +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) + +#define BOARD_HAS_CRYSTAL 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_P0_16) +#define DEFAULT_I2C_BUS_SDA (&pin_P0_15) + +#define DEFAULT_SPI_BUS_SCK (&pin_P0_07) +#define DEFAULT_SPI_BUS_MOSI (&pin_P1_08) +#define DEFAULT_SPI_BUS_MISO (&pin_P0_11) + +#define DEFAULT_UART_BUS_RX (&pin_P0_24) +#define DEFAULT_UART_BUS_TX (&pin_P0_25) diff --git a/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.mk b/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.mk new file mode 100644 index 0000000000..4c1c93c10a --- /dev/null +++ b/ports/nrf/boards/metro_nrf52840_express/mpconfigboard.mk @@ -0,0 +1,26 @@ +USB_VID = 0x239A +USB_PID = 0x8040 +USB_PRODUCT = "Metro nRF52840 Express" +USB_MANUFACTURER = "Adafruit Industries LLC" + +MCU_SERIES = m4 +MCU_VARIANT = nrf52 +MCU_SUB_VARIANT = nrf52840 +MCU_CHIP = nrf52840 +SD ?= s140 +SOFTDEV_VERSION ?= 6.1.0 + +BOOT_SETTING_ADDR = 0xFF000 + +ifeq ($(SD),) + LD_FILE = boards/nrf52840_1M_256k.ld +else + LD_FILE = boards/adafruit_$(MCU_SUB_VARIANT)_$(SD_LOWER)_v$(firstword $(subst ., ,$(SOFTDEV_VERSION))).ld + CIRCUITPY_BLEIO = 1 +endif + +NRF_DEFINES += -DNRF52840_XXAA -DNRF52840 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICE_COUNT = 1 +EXTERNAL_FLASH_DEVICES = "GD25Q16C" diff --git a/ports/nrf/boards/metro_nrf52840_express/pins.c b/ports/nrf/boards/metro_nrf52840_express/pins.c new file mode 100644 index 0000000000..452e31202b --- /dev/null +++ b/ports/nrf/boards/metro_nrf52840_express/pins.c @@ -0,0 +1,56 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_P0_04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_P0_05) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_P0_28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_P0_30) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_P0_02) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_P0_03) }, + + { MP_ROM_QSTR(MP_QSTR_AREF), MP_ROM_PTR(&pin_P0_31) }, + + { MP_ROM_QSTR(MP_QSTR_SWITCH), MP_ROM_PTR(&pin_P1_02) }, + + { MP_ROM_QSTR(MP_QSTR_NFC1), MP_ROM_PTR(&pin_P0_09) }, + { MP_ROM_QSTR(MP_QSTR_NFC2), MP_ROM_PTR(&pin_P0_10) }, + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_P0_24) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_P0_24) }, + + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_P0_25) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_P0_25) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_P1_10) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_P1_04) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_P1_11) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_P1_12) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_P1_14) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_P0_26) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_P0_27) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_P0_12) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_P0_06) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_P0_08) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_P1_09) }, + { MP_ROM_QSTR(MP_QSTR_D13),MP_ROM_PTR(&pin_P0_14) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_P0_15) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_P0_16) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL),MP_ROM_PTR(&pin_P0_13) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_P0_07) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_P1_08) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_P0_11) }, + + { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_P1_13) }, + { MP_ROM_QSTR(MP_QSTR_RED_LED), MP_ROM_PTR(&pin_P1_13) }, + + { MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_P1_15) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; + +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/nrf/boards/particle_argon/mpconfigboard.h b/ports/nrf/boards/particle_argon/mpconfigboard.h index 0ee785c31b..a4ecb2bb43 100644 --- a/ports/nrf/boards/particle_argon/mpconfigboard.h +++ b/ports/nrf/boards/particle_argon/mpconfigboard.h @@ -27,8 +27,6 @@ #include "nrfx/hal/nrf_gpio.h" -#define FEATHER52840 - #define MICROPY_HW_BOARD_NAME "Particle Argon" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "Particle Argon" diff --git a/ports/nrf/boards/particle_boron/mpconfigboard.h b/ports/nrf/boards/particle_boron/mpconfigboard.h index b814fc6946..5e817311f9 100644 --- a/ports/nrf/boards/particle_boron/mpconfigboard.h +++ b/ports/nrf/boards/particle_boron/mpconfigboard.h @@ -27,8 +27,6 @@ #include "nrfx/hal/nrf_gpio.h" -#define FEATHER52840 - #define MICROPY_HW_BOARD_NAME "Particle Boron" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "Particle Boron" diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/particle_xenon/mpconfigboard.h index c8da667369..6c8cc7cef2 100644 --- a/ports/nrf/boards/particle_xenon/mpconfigboard.h +++ b/ports/nrf/boards/particle_xenon/mpconfigboard.h @@ -27,8 +27,6 @@ #include "nrfx/hal/nrf_gpio.h" -#define FEATHER52840 - #define MICROPY_HW_BOARD_NAME "Particle Xenon" #define MICROPY_HW_MCU_NAME "nRF52840" #define MICROPY_PY_SYS_PLATFORM "Particle Xenon" diff --git a/ports/nrf/common-hal/audiobusio/I2SOut.c b/ports/nrf/common-hal/audiobusio/I2SOut.c new file mode 100644 index 0000000000..8be1fb2f8c --- /dev/null +++ b/ports/nrf/common-hal/audiobusio/I2SOut.c @@ -0,0 +1,70 @@ +/* + * 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 "common-hal/microcontroller/Pin.h" +#include "common-hal/audiobusio/I2SOut.h" + +#include "py/obj.h" +#include "py/runtime.h" + +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) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t* self, + mp_obj_t sample, bool loop) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t* self) { + mp_raise_NotImplementedError(NULL); +} diff --git a/ports/nrf/common-hal/audiobusio/I2SOut.h b/ports/nrf/common-hal/audiobusio/I2SOut.h new file mode 100644 index 0000000000..01c944e721 --- /dev/null +++ b/ports/nrf/common-hal/audiobusio/I2SOut.h @@ -0,0 +1,36 @@ +/* + * 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_NRF_COMMON_HAL_AUDIOBUSIO_I2SOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_AUDIOBUSIO_I2SOUT_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} audiobusio_i2sout_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_AUDIOBUSIO_I2SOUT_H diff --git a/ports/nrf/common-hal/audiobusio/PDMIn.c b/ports/nrf/common-hal/audiobusio/PDMIn.c new file mode 100644 index 0000000000..a7f9c9d747 --- /dev/null +++ b/ports/nrf/common-hal/audiobusio/PDMIn.c @@ -0,0 +1,130 @@ +/* + * 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 "common-hal/audiobusio/PDMIn.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/runtime.h" + +__attribute__((used)) +NRF_PDM_Type *nrf_pdm = NRF_PDM; + +static uint32_t dummy_buffer[4]; + +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) { + assert_pin_free(clock_pin); + assert_pin_free(data_pin); + claim_pin(clock_pin); + claim_pin(data_pin); + + self->mono = mono; + self->clock_pin_number = clock_pin->number; + self->data_pin_number = data_pin->number; + + if (sample_rate != 16000) { + mp_raise_ValueError(translate("only sample_rate=16000 is supported")); + } + if (bit_depth != 16) { + mp_raise_ValueError(translate("only bit_depth=16 is supported")); + } + nrf_pdm->PSEL.CLK = self->clock_pin_number; + nrf_pdm->PSEL.DIN = self->data_pin_number; + nrf_pdm->PDMCLKCTRL = PDM_PDMCLKCTRL_FREQ_Default; // For Ratio64 + nrf_pdm->RATIO = PDM_RATIO_RATIO_Ratio64; + nrf_pdm->GAINL = PDM_GAINL_GAINL_DefaultGain; + nrf_pdm->GAINR = PDM_GAINR_GAINR_DefaultGain; + nrf_pdm->ENABLE = 1; + + nrf_pdm->SAMPLE.PTR = (uintptr_t)&dummy_buffer; + nrf_pdm->SAMPLE.MAXCNT = 1; + nrf_pdm->TASKS_START = 1; +} + +bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t* self) { + return !self->clock_pin_number; +} + +void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t* self) { + nrf_pdm->ENABLE = 0; + + reset_pin_number(self->clock_pin_number); + self->clock_pin_number = 0; + reset_pin_number(self->data_pin_number); + self->data_pin_number = 0; +} + +uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t* self) { + return 16; +} + +uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t* self) { + return 16000; +} + +uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* self, + uint16_t* output_buffer, uint32_t output_buffer_length) { + // Note: Adafruit's module has SELECT pulled to GND, which makes the DATA + // valid when the CLK is low, therefore it must be sampled on the rising edge. + if (self->mono) { + nrf_pdm->MODE = PDM_MODE_OPERATION_Stereo | PDM_MODE_EDGE_LeftRising; + } else { + nrf_pdm->MODE = PDM_MODE_OPERATION_Mono | PDM_MODE_EDGE_LeftRising; + } + + // step 1. Redirect to real buffer + nrf_pdm->SAMPLE.PTR = (uintptr_t)output_buffer; + nrf_pdm->SAMPLE.MAXCNT = output_buffer_length; + + // a delay is the safest simple way to ensure that the above requested sample has started + mp_hal_delay_us(200); + nrf_pdm->EVENTS_END = 0; + + // step 2. Registers are double buffered, so pre-redirect back to dummy buffer + nrf_pdm->SAMPLE.PTR = (uintptr_t)&dummy_buffer; + nrf_pdm->SAMPLE.MAXCNT = 1; + + // Step 3. wait for PDM to end + while (!nrf_pdm->EVENTS_END) { + MICROPY_VM_HOOK_LOOP; + } + + // Step 4. They want unsigned + for (uint32_t i=0; imono) { + return (output_buffer_length / 2) * 2; + } else { + return (output_buffer_length / 4) * 4; + } +} diff --git a/ports/nrf/common-hal/audiobusio/PDMIn.h b/ports/nrf/common-hal/audiobusio/PDMIn.h new file mode 100644 index 0000000000..d921e42ff3 --- /dev/null +++ b/ports/nrf/common-hal/audiobusio/PDMIn.h @@ -0,0 +1,40 @@ +/* + * 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_NRF_COMMON_HAL_AUDIOBUSIO_AUDIOOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_AUDIOBUSIO_AUDIOOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t clock_pin_number, data_pin_number; + bool mono; +} audiobusio_pdmin_obj_t; + +#endif diff --git a/ports/nrf/common-hal/audiobusio/__init__.c b/ports/nrf/common-hal/audiobusio/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c new file mode 100644 index 0000000000..0321b751ca --- /dev/null +++ b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c @@ -0,0 +1,316 @@ +/* + * 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 +#include + +#include "extmod/vfs_fat.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "common-hal/audiopwmio/PWMAudioOut.h" +#include "common-hal/pulseio/PWMOut.h" +#include "shared-bindings/audiopwmio/PWMAudioOut.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/shared/translate.h" + +// TODO: This should be the same size as PWMOut.c:pwms[], but there's no trivial way to accomplish that +STATIC audiopwmio_pwmaudioout_obj_t* active_audio[4]; + +#define F_TARGET (62500) +#define F_PWM (16000000) +// return the REFRESH value, store the TOP value in an out-parameter +// Tested for key values (worst relative error = 0.224% = 3.84 cents) +// 8000: top = 250 refresh = 7 [ 8000.0] +// 22050: top = 242 refresh = 2 [22038.5] +// 24000: top = 222 refresh = 2 [24024.0] +// 44100: top = 181 refresh = 1 [44198.8] +// 48000: top = 167 refresh = 1 [47904.1] +STATIC uint32_t calculate_pwm_parameters(uint32_t sample_rate, uint32_t *top_out) { + // the desired frequency is the closest integer multiple of sample_rate not less than F_TARGET + uint32_t desired_frequency = (F_TARGET + sample_rate - 1) / sample_rate * sample_rate; + // The top value is the PWM frequency divided by the desired frequency (round to nearest) + uint32_t top = (F_PWM + desired_frequency/2) / desired_frequency; + // The actual frequency is the PWM frequency divided by the top value (round to nearest) + uint32_t actual_frequency = (F_PWM + top/2) / top; + // The multiplier is the actual frequency divided by the sample rate (round to nearest) + uint32_t multiplier = (actual_frequency + sample_rate/2) / sample_rate; + *top_out = top; + return multiplier - 1; +} + +STATIC void activate_audiopwmout_obj(audiopwmio_pwmaudioout_obj_t *self) { + for(size_t i=0; i < MP_ARRAY_SIZE(active_audio); i++) { + if(!active_audio[i]) { + active_audio[i] = self; + break; + } + } +} +STATIC void deactivate_audiopwmout_obj(audiopwmio_pwmaudioout_obj_t *self) { + for(size_t i=0; i < MP_ARRAY_SIZE(active_audio); i++) { + if(active_audio[i] == self) + active_audio[i] = NULL; + } +} + +void audiopwmout_reset() { + for(size_t i=0; i < MP_ARRAY_SIZE(active_audio); i++) + active_audio[i] = NULL; +} + +STATIC void fill_buffers(audiopwmio_pwmaudioout_obj_t *self, int buf) { + self->pwm->EVENTS_SEQSTARTED[1-buf] = 0; + uint16_t *dev_buffer = self->buffers[buf]; + uint8_t *buffer; + uint32_t buffer_length; + audioio_get_buffer_result_t get_buffer_result = + audiosample_get_buffer(self->sample, false, 0, + &buffer, &buffer_length); + if (get_buffer_result == GET_BUFFER_ERROR) { + common_hal_audiopwmio_pwmaudioout_stop(self); + return; + } + uint32_t num_samples = buffer_length / self->bytes_per_sample / self->spacing; + + if(self->bytes_per_sample == 1) { + uint8_t offset = self->signed_to_unsigned ? 0x80 : 0; + uint16_t scale = self->scale; + for(uint32_t i=0; ispacing; i++) { + uint8_t rawval = (*buffer++ + offset); + uint16_t val = (uint16_t)(((uint32_t)rawval * (uint32_t)scale) >> 8); + *dev_buffer++ = val; + if(self->spacing == 1) + *dev_buffer++ = val; + } + } else { + uint16_t offset = self->signed_to_unsigned ? 0x8000 : 0; + uint16_t scale = self->scale; + uint16_t *buffer16 = (uint16_t*)buffer; + for(uint32_t i=0; ispacing; i++) { + uint16_t rawval = (*buffer16++ + offset); + uint16_t val = (uint16_t)((rawval * (uint32_t)scale) >> 16); + *dev_buffer++ = val; + if(self->spacing == 1) + *dev_buffer++ = val; + } + } + self->pwm->SEQ[buf].PTR = (intptr_t)self->buffers[buf]; + self->pwm->SEQ[buf].CNT = num_samples*2; + + if (self->loop && get_buffer_result == GET_BUFFER_DONE) { + audiosample_reset_buffer(self->sample, false, 0); + } else if(get_buffer_result == GET_BUFFER_DONE) { + self->pwm->SHORTS = NRF_PWM_SHORT_SEQEND0_STOP_MASK | NRF_PWM_SHORT_SEQEND1_STOP_MASK; + self->stopping = true; + } +} + +STATIC void audiopwmout_background_obj(audiopwmio_pwmaudioout_obj_t *self) { + if(!common_hal_audiopwmio_pwmaudioout_get_playing(self)) + return; + if(self->stopping) { + bool stopped = + (self->pwm->EVENTS_SEQEND[0] || !self->pwm->EVENTS_SEQSTARTED[0]) && + (self->pwm->EVENTS_SEQEND[1] || !self->pwm->EVENTS_SEQSTARTED[1]); + if(stopped) + self->pwm->TASKS_STOP = 1; + } else if(!self->paused && !self->single_buffer) { + if(self->pwm->EVENTS_SEQSTARTED[0]) fill_buffers(self, 1); + if(self->pwm->EVENTS_SEQSTARTED[1]) fill_buffers(self, 0); + } +} + +void audiopwmout_background() { + for(size_t i=0; i < MP_ARRAY_SIZE(active_audio); i++) { + if(!active_audio[i]) continue; + audiopwmout_background_obj(active_audio[i]); + } +} + +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 quiescent_value) { + assert_pin_free(left_channel); + assert_pin_free(right_channel); + self->pwm = pwmout_allocate(256, PWM_PRESCALER_PRESCALER_DIV_1, true, NULL, NULL); + if(!self->pwm) { + mp_raise_RuntimeError(translate("All timers in use")); + } + + self->pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; + // two uint16_t values per sample when Grouped + // n.b. SEQ[#].CNT "counts" are 2 per sample (left and right channels) + self->pwm->DECODER = PWM_DECODER_LOAD_Grouped; + + // we use channels 0 and 2 because these are GROUPED; it lets us save half + // the space for sample data (no additional optimization is possible for + // single channel) + self->pwm->PSEL.OUT[0] = self->left_channel_number = left_channel->number; + claim_pin(left_channel); + + if(right_channel) + { + self->pwm->PSEL.OUT[2] = self->right_channel_number = right_channel->number; + claim_pin(right_channel); + } + + self->quiescent_value = quiescent_value >> 8; + + self->pwm->ENABLE = 1; + // TODO: Ramp from 0 to quiescent value +} + +bool common_hal_audiopwmio_pwmaudioout_deinited(audiopwmio_pwmaudioout_obj_t* self) { + return !self->pwm; +} + +void common_hal_audiopwmio_pwmaudioout_deinit(audiopwmio_pwmaudioout_obj_t* self) { + if (common_hal_audiopwmio_pwmaudioout_deinited(self)) { + return; + } + // TODO: ramp the pwm down from quiescent value to 0 + self->pwm->ENABLE = 0; + + if(self->left_channel_number) + reset_pin_number(self->left_channel_number); + if(self->right_channel_number) + reset_pin_number(self->right_channel_number); + + pwmout_free_channel(self->pwm, 0); + pwmout_free_channel(self->pwm, 2); + + self->pwm = NULL; + + m_free(self->buffers[0]); + self->buffers[0] = NULL; + + m_free(self->buffers[1]); + self->buffers[1] = NULL; +} + +void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t* self, mp_obj_t sample, bool loop) { + if (common_hal_audiopwmio_pwmaudioout_get_playing(self)) { + common_hal_audiopwmio_pwmaudioout_stop(self); + } + self->sample = sample; + self->loop = loop; + + uint32_t sample_rate = audiosample_sample_rate(sample); + uint32_t max_sample_rate = 62500; + if (sample_rate > max_sample_rate) { + mp_raise_ValueError_varg(translate("Sample rate too high. It must be less than %d"), max_sample_rate); + } + self->bytes_per_sample = audiosample_bits_per_sample(sample) / 8; + + uint32_t max_buffer_length; + audiosample_get_buffer_structure(sample, /* single channel */ false, + &self->single_buffer, &self->signed_to_unsigned, &max_buffer_length, + &self->spacing); + if(max_buffer_length > UINT16_MAX) { + mp_raise_ValueError_varg(translate("Buffer length %d too big. It must be less than %d"), max_buffer_length, UINT16_MAX); + } + self->buffer_length = (uint16_t)max_buffer_length; + self->buffers[0] = m_malloc(self->buffer_length * 2 * sizeof(uint16_t), false); + if(!self->single_buffer) + self->buffers[1] = m_malloc(self->buffer_length * 2 * sizeof(uint16_t), false); + + + uint32_t top; + self->pwm->SEQ[0].REFRESH = self->pwm->SEQ[1].REFRESH = calculate_pwm_parameters(sample_rate, &top); + self->scale = top-1; + self->pwm->COUNTERTOP = top; + + self->pwm->LOOP = 1; + audiosample_reset_buffer(self->sample, false, 0); + activate_audiopwmout_obj(self); + fill_buffers(self, 0); + self->pwm->SEQ[1].PTR = self->pwm->SEQ[0].PTR; + self->pwm->SEQ[1].CNT = self->pwm->SEQ[0].CNT; + self->pwm->EVENTS_SEQSTARTED[0] = 0; + self->pwm->EVENTS_SEQSTARTED[1] = 0; + self->pwm->EVENTS_STOPPED = 0; + self->pwm->SHORTS = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK; + self->pwm->TASKS_SEQSTART[0] = 1; + self->playing = true; + self->stopping = false; + self->paused = false; +} + +void common_hal_audiopwmio_pwmaudioout_stop(audiopwmio_pwmaudioout_obj_t* self) { + deactivate_audiopwmout_obj(self); + self->pwm->TASKS_STOP = 1; + self->stopping = false; + self->paused = false; + + m_free(self->buffers[0]); + self->buffers[0] = NULL; + + m_free(self->buffers[1]); + self->buffers[1] = NULL; +} + +bool common_hal_audiopwmio_pwmaudioout_get_playing(audiopwmio_pwmaudioout_obj_t* self) { + if(!self->paused && self->pwm->EVENTS_STOPPED) { + self->playing = false; + self->pwm->EVENTS_STOPPED = 0; + } + return self->playing; +} + +/* pause/resume present difficulties for the NRF PWM audio module. + * + * A PWM sequence can be stopped in its tracks by sending a TASKS_STOP event, + * but there's no way to pick up the sequence where it was stopped; you could + * start at the start of one of the two sequences, but especially for "single buffer" + * sample, this seems undesirable. + * + * Or, you can stop at the end of a sequence so that you don't duplicate anything + * when restarting, but again this is unsatisfactory for a "single buffer" sample. + * + * For now, I've taken the coward's way and left these methods unimplemented. + * Perhaps the way forward is to divide even "single buffer" samples into tasks of + * only a few ms long, so that they can be stopped/restarted quickly enough that it + * feels instant. (This also saves on memory, for long in-memory "single buffer" + * samples, since we have to locally take a resampled copy!) + */ +void common_hal_audiopwmio_pwmaudioout_pause(audiopwmio_pwmaudioout_obj_t* self) { + self->paused = true; + self->pwm->SHORTS = NRF_PWM_SHORT_SEQEND1_STOP_MASK; +} + +void common_hal_audiopwmio_pwmaudioout_resume(audiopwmio_pwmaudioout_obj_t* self) { + self->paused = false; + self->pwm->SHORTS = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK; + if (self->pwm->EVENTS_STOPPED) { + self->pwm->EVENTS_STOPPED = 0; + self->pwm->TASKS_SEQSTART[0] = 1; + } +} + +bool common_hal_audiopwmio_pwmaudioout_get_paused(audiopwmio_pwmaudioout_obj_t* self) { + return self->paused; +} diff --git a/ports/nrf/common-hal/audiopwmio/PWMAudioOut.h b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.h new file mode 100644 index 0000000000..8deff5d340 --- /dev/null +++ b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.h @@ -0,0 +1,59 @@ +/* + * 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_NRF_COMMON_HAL_AUDIOPWM_AUDIOOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_AUDIOPWM_AUDIOOUT_H + +#include "common-hal/microcontroller/Pin.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t *sample; + NRF_PWM_Type *pwm; + uint16_t *buffers[2]; + + uint16_t buffer_length; + uint16_t quiescent_value; + uint16_t scale; + + uint8_t left_channel_number; + uint8_t right_channel_number; + uint8_t spacing; + uint8_t bytes_per_sample; + + bool playing; + bool stopping; + bool paused; + bool loop; + bool signed_to_unsigned; + bool single_buffer; +} audiopwmio_pwmaudioout_obj_t; + +void audiopwmout_reset(void); + +void audiopwmout_background(void); + +#endif diff --git a/ports/nrf/common-hal/audiopwmio/__init__.c b/ports/nrf/common-hal/audiopwmio/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ports/nrf/common-hal/bleio/Adapter.c b/ports/nrf/common-hal/bleio/Adapter.c index 9d0912930b..936dfcb9b0 100644 --- a/ports/nrf/common-hal/bleio/Adapter.c +++ b/ports/nrf/common-hal/bleio/Adapter.c @@ -34,10 +34,11 @@ #include "nrfx_power.h" #include "nrf_nvic.h" #include "nrf_sdm.h" +#include "py/objstr.h" #include "py/runtime.h" -#include "shared-bindings/bleio/Adapter.h" - #include "supervisor/usb.h" +#include "shared-bindings/bleio/Adapter.h" +#include "shared-bindings/bleio/Address.h" STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { mp_raise_msg_varg(&mp_type_AssertionError, @@ -132,20 +133,42 @@ bool common_hal_bleio_adapter_get_enabled(void) { return is_enabled; } -void common_hal_bleio_adapter_get_address(bleio_address_obj_t *address) { - ble_gap_addr_t local_address; +void get_address(ble_gap_addr_t *address) { uint32_t err_code; common_hal_bleio_adapter_set_enabled(true); - err_code = sd_ble_gap_addr_get(&local_address); + err_code = sd_ble_gap_addr_get(address); if (err_code != NRF_SUCCESS) { mp_raise_OSError_msg(translate("Failed to get local address")); } - - address->type = local_address.addr_type; - - mp_buffer_info_t buf_info; - mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); - memcpy(address->bytes, buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); +} + +bleio_address_obj_t *common_hal_bleio_adapter_get_address(void) { + common_hal_bleio_adapter_set_enabled(true); + + ble_gap_addr_t local_address; + get_address(&local_address); + + bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); + address->base.type = &bleio_address_type; + + common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); + return address; +} + +mp_obj_t common_hal_bleio_adapter_get_default_name(void) { + common_hal_bleio_adapter_set_enabled(true); + + ble_gap_addr_t local_address; + get_address(&local_address); + + char name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0 }; + + name[sizeof(name) - 4] = nibble_to_hex_lower[local_address.addr[1] >> 4 & 0xf]; + name[sizeof(name) - 3] = nibble_to_hex_lower[local_address.addr[1] & 0xf]; + name[sizeof(name) - 2] = nibble_to_hex_lower[local_address.addr[0] >> 4 & 0xf]; + name[sizeof(name) - 1] = nibble_to_hex_lower[local_address.addr[0] & 0xf]; + + return mp_obj_new_str(name, sizeof(name)); } diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c new file mode 100644 index 0000000000..fd1e7538da --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.c @@ -0,0 +1,60 @@ +/* + * 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 "shared-bindings/bleio/Attribute.h" + +// Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. +void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SECURITY_MODE_NO_ACCESS: + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); + break; + + case SECURITY_MODE_OPEN: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); + break; + + case SECURITY_MODE_ENC_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); + break; + + case SECURITY_MODE_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); + break; + + case SECURITY_MODE_LESC_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); + break; + + case SECURITY_MODE_SIGNED_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); + break; + + case SECURITY_MODE_SIGNED_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); + break; + } +} diff --git a/ports/nrf/common-hal/bleio/Attribute.h b/ports/nrf/common-hal/bleio/Attribute.h new file mode 100644 index 0000000000..44c2fdfa17 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H + +// Nothing yet. + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c index d90737411f..3c5d977841 100644 --- a/ports/nrf/common-hal/bleio/Central.c +++ b/ports/nrf/common-hal/bleio/Central.c @@ -34,217 +34,9 @@ #include "nrf_soc.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/Characteristic.h" #include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -static bleio_service_obj_t *m_char_discovery_service; -static bleio_characteristic_obj_t *m_desc_discovery_characteristic; - -static volatile bool m_discovery_in_process; -static volatile bool m_discovery_successful; - -// service_uuid may be NULL, to discover all services. -STATIC bool discover_next_services(bleio_central_obj_t *self, uint16_t start_handle, ble_uuid_t *service_uuid) { - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_primary_services_discover(self->conn_handle, start_handle, service_uuid); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to discover services")); - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_characteristics(bleio_central_obj_t *self, bleio_service_obj_t *service, uint16_t start_handle) { - m_char_discovery_service = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_characteristics_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_descriptors(bleio_central_obj_t *self, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { - m_desc_discovery_characteristic = characteristic; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_descriptors_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - // Initialize several fields at once. - common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); - - service->device = MP_OBJ_FROM_PTR(central); - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - - if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known service UUID. - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); - service->uuid = uuid; - service->device = MP_OBJ_FROM_PTR(central); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just set the UUID to NULL. - service->uuid = NULL; - } - - mp_obj_list_append(central->service_list, service); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - characteristic->descriptor_list = mp_obj_new_list(0, NULL); - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known characteristic UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - bleio_characteristic_properties_t props; - - props.broadcast = gattc_char->char_props.broadcast; - props.indicate = gattc_char->char_props.indicate; - props.notify = gattc_char->char_props.notify; - props.read = gattc_char->char_props.read; - props.write = gattc_char->char_props.write; - props.write_no_response = gattc_char->char_props.write_wo_resp; - - // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); - characteristic->handle = gattc_char->handle_value; - characteristic->service = m_char_discovery_service; - - mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_desc_t *gattc_desc = &response->descs[i]; - - // Remember handles for certain well-known descriptors. - switch (gattc_desc->uuid.uuid) { - case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: - m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; - break; - - default: - // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, - // so ignore those. - // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors - break; - } - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known descriptor UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - common_hal_bleio_descriptor_construct(descriptor, uuid); - descriptor->handle = gattc_desc->handle; - descriptor->characteristic = m_desc_discovery_characteristic; - - mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; @@ -262,20 +54,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { case BLE_GAP_EVT_DISCONNECTED: central->conn_handle = BLE_CONN_HANDLE_INVALID; - m_discovery_successful = false; - m_discovery_in_process = false; - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, central); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, central); - break; - - case BLE_GATTC_EVT_DESC_DISC_RSP: - on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, central); break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: @@ -288,7 +66,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { sd_ble_gap_conn_param_update(central->conn_handle, &request->conn_params); break; } - default: // For debugging. // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); @@ -299,12 +76,11 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { void common_hal_bleio_central_construct(bleio_central_obj_t *self) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = mp_obj_new_list(0, NULL); - self->gatt_role = GATT_ROLE_CLIENT; + self->remote_services_list = mp_obj_new_list(0, NULL); self->conn_handle = BLE_CONN_HANDLE_INVALID; } -void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout, mp_obj_t service_uuids) { +void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { common_hal_bleio_adapter_set_enabled(true); ble_drv_add_event_handler(central_on_ble_evt, self); @@ -339,115 +115,12 @@ void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_o } while (self->waiting_to_connect) { - MICROPY_VM_HOOK_LOOP; + RUN_BACKGROUND_TASKS; } if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_OSError_msg(translate("Failed to connect: timeout")); } - - // Connection successful. - // Now discover services on the remote peripheral. - - if (service_uuids == mp_const_none) { - - // List of service UUID's not given, so discover all available services. - - uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; - - while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) { - // discover_next_services() appends to service_list. - - // Get the most recently discovered service, and then ask for services - // whose handles start after the last attribute handle inside that service. - const bleio_service_obj_t *service = - MP_OBJ_TO_PTR(self->service_list->items[self->service_list->len - 1]); - next_service_start_handle = service->end_handle + 1; - } - } else { - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(service_uuids, &iter_buf); - mp_obj_t uuid_obj; - while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("non-UUID found in service_uuids")); - } - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - - ble_uuid_t nrf_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); - - // Service might or might not be discovered; that's ok. Caller has to check - // Central.remote_services to find out. - // We only need to call this once for each service to discover. - discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid); - } - } - - - for (size_t service_idx = 0; service_idx < self->service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->service_list->items[service_idx]); - - // Skip the service if it had an unknown (unregistered) UUID. - if (service->uuid == NULL) { - continue; - } - - uint16_t next_char_start_handle = service->start_handle; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_characteristics() appends to the characteristic_list. - while (next_char_start_handle <= service->end_handle && - discover_next_characteristics(self, service, next_char_start_handle)) { - - - // Get the most recently discovered characteristic, and then ask for characteristics - // whose handles start after the last attribute handle inside that characteristic. - const bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); - next_char_start_handle = characteristic->handle + 1; - } - - // Got characteristics for this service. Now discover descriptors for each characteristic. - size_t char_list_len = service->characteristic_list->len; - for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { - bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); - const bool last_characteristic = char_idx == char_list_len - 1; - bleio_characteristic_obj_t *next_characteristic = last_characteristic - ? NULL - : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); - - // Skip the characteristic if it had an unknown (unregistered) UUID. - if (characteristic->uuid == NULL) { - continue; - } - - uint16_t next_desc_start_handle = characteristic->handle + 1; - - // Don't run past the end of this service or the beginning of the next characteristic. - uint16_t next_desc_end_handle = next_characteristic == NULL - ? service->end_handle - : next_characteristic->handle - 1; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_descriptors() appends to the descriptor_list. - while (next_desc_start_handle <= service->end_handle && - next_desc_start_handle < next_desc_end_handle && - discover_next_descriptors(self, characteristic, - next_desc_start_handle, next_desc_end_handle)) { - - // Get the most recently discovered descriptor, and then ask for descriptors - // whose handles start after that descriptor's handle. - const bleio_descriptor_obj_t *descriptor = - MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); - next_desc_start_handle = descriptor->handle + 1; - } - } - - } } void common_hal_bleio_central_disconnect(bleio_central_obj_t *self) { @@ -458,6 +131,15 @@ bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { return self->conn_handle != BLE_CONN_HANDLE_INVALID; } -mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { - return self->service_list; +mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; +} + +mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { + return self->remote_services_list; } diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h index ac16700888..b7a9050b86 100644 --- a/ports/nrf/common-hal/bleio/Central.h +++ b/ports/nrf/common-hal/bleio/Central.h @@ -31,15 +31,14 @@ #include #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" typedef struct { mp_obj_base_t base; - gatt_role_t gatt_role; volatile bool waiting_to_connect; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services discovered after connecting to a remote peripheral. + mp_obj_list_t *remote_services_list; } bleio_central_obj_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 17417a5e64..45e8d2495e 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -25,29 +25,23 @@ * THE SOFTWARE. */ -#include -#include - -#include "ble_drv.h" -#include "ble_gatts.h" -#include "nrf_soc.h" - #include "py/runtime.h" -#include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" -STATIC volatile bleio_characteristic_obj_t *m_read_characteristic; +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/Service.h" -STATIC uint16_t get_cccd(bleio_characteristic_obj_t *characteristic) { - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); +static volatile bleio_characteristic_obj_t *m_read_characteristic; + +STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) { uint16_t cccd; ble_gatts_value_t value = { .p_value = (uint8_t*) &cccd, .len = 2, }; - const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, characteristic->cccd_handle, &value); - + const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, cccd_handle, &value); if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) { // CCCD is not set, so say that neither Notify nor Indicate is enabled. @@ -59,64 +53,39 @@ STATIC uint16_t get_cccd(bleio_characteristic_obj_t *characteristic) { return cccd; } -STATIC void gatts_read(bleio_characteristic_obj_t *characteristic) { - // This might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because - // we can still read and write the local value. - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); +STATIC void characteristic_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { + switch (ble_evt->header.evt_id) { - mp_buffer_info_t bufinfo; - ble_gatts_value_t gatts_value = { - .p_value = NULL, - .len = 0, - }; + // More events may be handled later, so keep this as a switch. - // Read once to find out what size buffer we need, then read again to fill buffer. + case BLE_GATTC_EVT_READ_RSP: { + ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; + if (m_read_characteristic) { + m_read_characteristic->value = mp_obj_new_bytearray(response->len, response->data); + } + // Indicate to busy-wait loop that we've read the attribute value. + m_read_characteristic = NULL; + break; + } - uint32_t err_code = sd_ble_gatts_value_get(conn_handle, characteristic->handle, &gatts_value); - if (err_code == NRF_SUCCESS) { - characteristic->value_data = mp_obj_new_bytearray_of_zeros(gatts_value.len); - mp_get_buffer_raise(characteristic->value_data, &bufinfo, MP_BUFFER_WRITE); - gatts_value.p_value = bufinfo.buf; - - // Read again, with the correct size of buffer. - err_code = sd_ble_gatts_value_get(conn_handle, characteristic->handle, &gatts_value); - } - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to read gatts value, err 0x%04x"), err_code); + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); + break; } } - -STATIC void gatts_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - // This might be BLE_CONN_HANDLE_INVALID if we're not conected, but that's OK, because - // we can still read and write the local value. - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); - - ble_gatts_value_t gatts_value = { - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; - - const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, characteristic->handle, &gatts_value); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to write gatts value, err 0x%04x"), err_code); - } -} - -STATIC void gatts_notify_indicate(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { +STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { uint16_t hvx_len = bufinfo->len; ble_gatts_hvx_params_t hvx_params = { - .handle = characteristic->handle, + .handle = handle, .type = hvx_type, .offset = 0, .p_len = &hvx_len, .p_data = bufinfo->buf, }; - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); - while (1) { const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); if (err_code == NRF_SUCCESS) { @@ -125,156 +94,128 @@ STATIC void gatts_notify_indicate(bleio_characteristic_obj_t *characteristic, mp // TX buffer is full // We could wait for an event indicating the write is complete, but just retrying is easier. if (err_code == NRF_ERROR_RESOURCES) { - MICROPY_VM_HOOK_LOOP; + RUN_BACKGROUND_TASKS; continue; } // Some real error has occurred. mp_raise_OSError_msg_varg(translate("Failed to notify or indicate attribute value, err 0x%04x"), err_code); } - } -STATIC void check_connected(uint16_t conn_handle) { - if (conn_handle == BLE_CONN_HANDLE_INVALID) { - mp_raise_OSError_msg(translate("Not connected")); - } -} - -STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) { +STATIC void characteristic_gattc_read(bleio_characteristic_obj_t *characteristic) { const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); - check_connected(conn_handle); + common_hal_bleio_check_connected(conn_handle); + // Set to NULL in event loop after event. m_read_characteristic = characteristic; + ble_drv_add_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); + const uint32_t err_code = sd_ble_gattc_read(conn_handle, characteristic->handle, 0); if (err_code != NRF_SUCCESS) { mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); } while (m_read_characteristic != NULL) { - MICROPY_VM_HOOK_LOOP; - } -} - -STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) { - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); - check_connected(conn_handle); - - ble_gattc_write_params_t write_params = { - .write_op = characteristic->props.write_no_response ? BLE_GATT_OP_WRITE_CMD : BLE_GATT_OP_WRITE_REQ, - .handle = characteristic->handle, - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; - - while (1) { - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code == NRF_SUCCESS) { - break; - } - - // Write with response will return NRF_ERROR_BUSY if the response has not been received. - // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. - if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { - // We could wait for an event indicating the write is complete, but just retrying is easier. - MICROPY_VM_HOOK_LOOP; - continue; - } - - // Some real error occurred. - mp_raise_OSError_msg_varg(translate("Failed to write attribute value, err 0x%04x"), err_code); + RUN_BACKGROUND_TASKS; } + ble_drv_remove_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); } -STATIC void characteristic_on_ble_evt(ble_evt_t *ble_evt, void *param) { - switch (ble_evt->header.evt_id) { - - // More events may be handled later, so keep this as a switch. - - case BLE_GATTC_EVT_READ_RSP: { - ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; - m_read_characteristic->value_data = mp_obj_new_bytearray(response->len, response->data); - // Indicate to busy-wait loop that we've read the characteristic. - m_read_characteristic = NULL; - break; - } - - // For debugging. - default: - // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); - break; - } - -} - -void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, mp_obj_list_t *descriptor_list) { - self->service = mp_const_none; +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, 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_obj_list_t *descriptor_list) { + self->service = MP_OBJ_NULL; self->uuid = uuid; - self->value_data = mp_const_none; - self->props = props; - self->descriptor_list = descriptor_list; + self->value = mp_const_empty_bytes; self->handle = BLE_GATT_HANDLE_INVALID; + self->props = props; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->descriptor_list = descriptor_list; - ble_drv_add_event_handler(characteristic_on_ble_evt, self); + const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; + if (max_length < 0 || max_length > max_length_max) { + mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), + max_length_max, fixed_length ? "True" : "False"); + } + self->max_length = max_length; + self->fixed_length = fixed_length; + + for (size_t descriptor_idx = 0; descriptor_idx < descriptor_list->len; ++descriptor_idx) { + bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(descriptor_list->items[descriptor_idx]); + descriptor->characteristic = self; + } } mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { return self->descriptor_list; } +bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { + return self->service; +} + mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) { - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_CLIENT: - gattc_read(self); - break; - - case GATT_ROLE_SERVER: - gatts_read(self); - break; - - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); + if (common_hal_bleio_service_get_is_remote(self->service)) { + // self->value is set by evt handler. + characteristic_gattc_read(self); + } else { + self->value = common_hal_bleio_gatts_read(self->handle, conn_handle); + } } - return self->value_data; + return self->value; } void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - bool sent = false; - uint16_t cccd = 0; + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_SERVER: - if (self->props.notify || self->props.indicate) { - cccd = get_cccd(self); + if (common_hal_bleio_service_get_is_remote(self->service)) { + // Last argument is true if write-no-reponse desired. + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, + (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); + } else { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length required fixed length")); } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + bool sent = false; + uint16_t cccd = 0; + + const bool notify = self->props & CHAR_PROP_NOTIFY; + const bool indicate = self->props & CHAR_PROP_INDICATE; + if (notify | indicate) { + cccd = characteristic_get_cccd(self->cccd_handle, conn_handle); + } + // It's possible that both notify and indicate are set. - if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); + if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_NOTIFICATION); sent = true; } - if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); + if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_INDICATION); sent = true; } + if (!sent) { - gatts_write(self, bufinfo); + common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); } - break; - - case GATT_ROLE_CLIENT: - gattc_write(self, bufinfo); - break; - - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; + } } -} + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); +} bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { return self->uuid; @@ -289,18 +230,17 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, mp_raise_ValueError(translate("No CCCD for this Characteristic")); } - if (common_hal_bleio_device_get_gatt_role(self->service->device) != GATT_ROLE_CLIENT) { - mp_raise_ValueError(translate("Can't set CCCD for local Characteristic")); + if (!common_hal_bleio_service_get_is_remote(self->service)) { + mp_raise_ValueError(translate("Can't set CCCD on local Characteristic")); } + const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); + common_hal_bleio_check_connected(conn_handle); + uint16_t cccd_value = (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | (indicate ? BLE_GATT_HVX_INDICATION : 0); - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); - check_connected(conn_handle); - - ble_gattc_write_params_t write_params = { .write_op = BLE_GATT_OP_WRITE_REQ, .handle = self->cccd_handle, @@ -318,7 +258,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { // We could wait for an event indicating the write is complete, but just retrying is easier. - MICROPY_VM_HOOK_LOOP; + RUN_BACKGROUND_TASKS; continue; } diff --git a/ports/nrf/common-hal/bleio/Characteristic.h b/ports/nrf/common-hal/bleio/Characteristic.h index 7cb2275968..fb6a4c6cef 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.h +++ b/ports/nrf/common-hal/bleio/Characteristic.h @@ -28,17 +28,23 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H +#include "shared-bindings/bleio/Attribute.h" +#include "shared-module/bleio/Characteristic.h" #include "common-hal/bleio/Service.h" #include "common-hal/bleio/UUID.h" -#include "shared-module/bleio/Characteristic.h" typedef struct { mp_obj_base_t base; + // Will be MP_OBJ_NULL before being assigned to a Service. bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; - volatile mp_obj_t value_data; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; uint16_t handle; bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; mp_obj_list_t *descriptor_list; uint16_t user_desc_handle; uint16_t cccd_handle; diff --git a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c index 59eaaf02b9..64ab5e8a7a 100644 --- a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c +++ b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c @@ -37,7 +37,7 @@ #include "tick.h" -#include "common-hal/bleio/__init__.h" +#include "shared-bindings/bleio/__init__.h" #include "common-hal/bleio/CharacteristicBuffer.h" STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { @@ -99,7 +99,7 @@ int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_ // Wait for all bytes received or timeout while ( (ringbuf_count(&self->ringbuf) < len) && (ticks_ms - start_ticks < self->timeout_ms) ) { - MICROPY_VM_HOOK_LOOP; + RUN_BACKGROUND_TASKS; // Allow user to break out of a timeout with a KeyboardInterrupt. if ( mp_hal_is_interrupted() ) { return 0; diff --git a/ports/nrf/common-hal/bleio/Descriptor.c b/ports/nrf/common-hal/bleio/Descriptor.c index 005af6eaae..2a2019277d 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.c +++ b/ports/nrf/common-hal/bleio/Descriptor.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * Copyright (c) 2016 Glenn Ruben Bakke * @@ -26,17 +26,116 @@ * THE SOFTWARE. */ -#include "common-hal/bleio/Descriptor.h" +#include "py/runtime.h" + +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid) { - self->uuid = uuid; -} +static volatile bleio_descriptor_obj_t *m_read_descriptor; -mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self) { - return self->handle; +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, 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) { + self->characteristic = MP_OBJ_NULL; + self->uuid = uuid; + self->value = mp_const_empty_bytes; + self->handle = BLE_GATT_HANDLE_INVALID; + self->read_perm = read_perm; + self->write_perm = write_perm; + + const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; + if (max_length < 0 || max_length > max_length_max) { + mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), + max_length_max, fixed_length ? "True" : "False"); + } + self->max_length = max_length; + self->fixed_length = fixed_length; } bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { return self->uuid; } + +bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { + return self->characteristic; +} + +STATIC void descriptor_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { + switch (ble_evt->header.evt_id) { + + // More events may be handled later, so keep this as a switch. + + case BLE_GATTC_EVT_READ_RSP: { + ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; + if (m_read_descriptor) { + m_read_descriptor->value = mp_obj_new_bytearray(response->len, response->data); + } + // Indicate to busy-wait loop that we've read the attribute value. + m_read_descriptor = NULL; + break; + } + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled descriptor event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + +STATIC void descriptor_gattc_read(bleio_descriptor_obj_t *descriptor) { + const uint16_t conn_handle = + common_hal_bleio_device_get_conn_handle(descriptor->characteristic->service->device); + common_hal_bleio_check_connected(conn_handle); + + // Set to NULL in event loop after event. + m_read_descriptor = descriptor; + + ble_drv_add_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); + + const uint32_t err_code = sd_ble_gattc_read(conn_handle, descriptor->handle, 0); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); + } + + while (m_read_descriptor != NULL) { + MICROPY_VM_HOOK_LOOP; + } + + ble_drv_remove_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); +} + +mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self) { + // Do GATT operations only if this descriptor has been registered + if (self->handle != BLE_GATT_HANDLE_INVALID) { + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + descriptor_gattc_read(self); + } else { + self->value = common_hal_bleio_gatts_read( + self->handle, common_hal_bleio_device_get_conn_handle(self->characteristic->service->device)); + } + } + + return self->value; +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + // Do GATT operations only if this descriptor has been registered. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->characteristic->service->device); + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + // false means WRITE_REQ, not write-no-response + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + } else { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length != required fixed length")); + } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + } + } + + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); +} diff --git a/ports/nrf/common-hal/bleio/Descriptor.h b/ports/nrf/common-hal/bleio/Descriptor.h index b7af6a42f9..6db4d7be37 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.h +++ b/ports/nrf/common-hal/bleio/Descriptor.h @@ -30,14 +30,21 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H #include "py/obj.h" -#include "common-hal/bleio/Characteristic.h" + +#include "shared-bindings/bleio/Characteristic.h" #include "common-hal/bleio/UUID.h" typedef struct { mp_obj_base_t base; - uint16_t handle; + // Will be MP_OBJ_NULL before being assigned to a Characteristic. bleio_characteristic_obj_t *characteristic; bleio_uuid_obj_t *uuid; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; + uint16_t handle; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; } bleio_descriptor_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index 608bd1342b..ed35516fc9 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -36,12 +36,12 @@ #include "py/objlist.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/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -#include "common-hal/bleio/Service.h" #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) @@ -52,6 +52,19 @@ #define BLE_ADV_AD_TYPE_FIELD_SIZE 1 #define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 +static const ble_gap_sec_params_t pairing_sec_params = { + .bond = 0, // TODO: add bonding + .mitm = 0, + .lesc = 0, + .keypress = 0, + .oob = 0, + .io_caps = BLE_GAP_IO_CAPS_NONE, + .min_key_size = 7, + .max_key_size = 16, + .kdist_own = { .enc = 1, .id = 1}, + .kdist_peer = { .enc = 1, .id = 1}, +}; + STATIC void check_data_fit(size_t data_len) { if (data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX) { mp_raise_ValueError(translate("Data too large for advertisement packet")); @@ -61,6 +74,9 @@ STATIC void check_data_fit(size_t data_len) { STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { bleio_peripheral_obj_t *self = (bleio_peripheral_obj_t*)self_in; + // For debugging. + // mp_printf(&mp_plat_print, "Peripheral event: 0x%04x\n", ble_evt->header.evt_id); + switch (ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: { // Central has connected. @@ -89,10 +105,6 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { // Someday may handle timeouts or limit reached. break; - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); - break; - case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { ble_gap_evt_conn_param_update_request_t *request = &ble_evt->evt.gap_evt.params.conn_param_update_request; @@ -113,6 +125,47 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); break; + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &pairing_sec_params, NULL); + break; + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + // TODO for LESC pairing: + // sd_ble_gap_lesc_dhkey_reply(...); + break; + + case BLE_GAP_EVT_AUTH_STATUS: { + // Pairing process completed + ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; + if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { + // mp_printf(&mp_plat_print, "Pairing succeeded, status: 0x%04x\n", status->auth_status); + self->pair_status = PAIR_PAIRED; + } else { + // mp_printf(&mp_plat_print, "Pairing failed, status: 0x%04x\n", status->auth_status); + self->pair_status = PAIR_NOT_PAIRED; + } + break; + } + + case BLE_GAP_EVT_CONN_SEC_UPDATE: { + ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec; + if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) { + // Security setup did not succeed: + // mode 0, level 0 means no access + // mode 1, level 1 means open link + // mode >=1 and/or level >=1 means encryption is set up + self->pair_status = PAIR_NOT_PAIRED; + } else { + // TODO: see Bluefruit lib + // if ( !bond_load_cccd(_role, _conn_hdl, _ediv) ) { + // sd_ble_gatts_sys_attr_set(_conn_hdl, NULL, 0, 0); + // } + self->pair_status = PAIR_PAIRED; + } + break; + } + + default: // For debugging. // mp_printf(&mp_plat_print, "Unhandled peripheral event: 0x%04x\n", ble_evt->header.evt_id); @@ -120,20 +173,22 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { } } -void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name) { +void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *services_list, mp_obj_t name) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = service_list; + self->services_list = services_list; + // Used only for discovery when acting as a client. + self->remote_services_list = mp_obj_new_list(0, NULL); self->name = name; - self->gatt_role = GATT_ROLE_SERVER; self->conn_handle = BLE_CONN_HANDLE_INVALID; self->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; + self->pair_status = PAIR_NOT_PAIRED; // Add all the services. - for (size_t service_idx = 0; service_idx < service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[service_idx]); + for (size_t service_idx = 0; service_idx < services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(services_list->items[service_idx]); service->device = MP_OBJ_FROM_PTR(self); @@ -156,8 +211,8 @@ void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_ } -mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self) { - return self->service_list; +mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self) { + return self->services_list; } bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self) { @@ -247,3 +302,30 @@ void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *self) void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *self) { sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } + +mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; +} + +void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *self) { + self->pair_status = PAIR_WAITING; + + uint32_t err_code = sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to start pairing, error 0x%04x"), err_code); + } + + while (self->pair_status == PAIR_WAITING) { + MICROPY_VM_HOOK_LOOP; + } + + if (self->pair_status == PAIR_NOT_PAIRED) { + mp_raise_OSError_msg(translate("Failed to pair")); + } +} diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h index 2a12517159..e75a1641a3 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ b/ports/nrf/common-hal/bleio/Peripheral.h @@ -35,22 +35,29 @@ #include "py/obj.h" #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + typedef struct { mp_obj_base_t base; mp_obj_t name; - gatt_role_t gatt_role; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services provided by this peripheral. + mp_obj_list_t *services_list; + // Remote services discovered when this peripheral is acting as a client. + mp_obj_list_t *remote_services_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). uint8_t* advertising_data; uint8_t* scan_response_data; uint8_t adv_handle; - + pair_status_t pair_status; } bleio_peripheral_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index b6fcde8277..a7a3a6db09 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -29,8 +29,8 @@ #include "ble.h" #include "py/runtime.h" #include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" #include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/Adapter.h" @@ -39,6 +39,7 @@ void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_ob self->handle = 0xFFFF; self->uuid = uuid; self->characteristic_list = characteristic_list; + self->is_remote = false; self->is_secondary = is_secondary; for (size_t characteristic_idx = 0; characteristic_idx < characteristic_list->len; ++characteristic_idx) { @@ -46,7 +47,6 @@ void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_ob MP_OBJ_TO_PTR(characteristic_list->items[characteristic_idx]); characteristic->service = self; } - } bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { @@ -57,6 +57,10 @@ mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_ob return self->characteristic_list; } +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { return self->is_secondary; } @@ -68,13 +72,17 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(self->characteristic_list->items[characteristic_idx]); + if (characteristic->handle != BLE_GATT_HANDLE_INVALID) { + mp_raise_ValueError(translate("Characteristic already in use by another Service.")); + } + ble_gatts_char_md_t char_md = { - .char_props.broadcast = characteristic->props.broadcast, - .char_props.read = characteristic->props.read, - .char_props.write_wo_resp = characteristic->props.write_no_response, - .char_props.write = characteristic->props.write, - .char_props.notify = characteristic->props.notify, - .char_props.indicate = characteristic->props.indicate, + .char_props.broadcast = (characteristic->props & CHAR_PROP_BROADCAST) ? 1 : 0, + .char_props.read = (characteristic->props & CHAR_PROP_READ) ? 1 : 0, + .char_props.write_wo_resp = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) ? 1 : 0, + .char_props.write = (characteristic->props & CHAR_PROP_WRITE) ? 1 : 0, + .char_props.notify = (characteristic->props & CHAR_PROP_NOTIFY) ? 1 : 0, + .char_props.indicate = (characteristic->props & CHAR_PROP_INDICATE) ? 1 : 0, }; ble_gatts_attr_md_t cccd_md = { @@ -88,39 +96,74 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) char_md.p_cccd_md = &cccd_md; } - ble_uuid_t uuid; - bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &uuid); + ble_uuid_t char_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); - ble_gatts_attr_md_t attr_md = { + ble_gatts_attr_md_t char_attr_md = { .vloc = BLE_GATTS_VLOC_STACK, - .vlen = 1, + .vlen = !characteristic->fixed_length, }; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.write_perm); - ble_gatts_attr_t attr_char_value = { - .p_uuid = &uuid, - .p_attr_md = &attr_md, - .init_len = sizeof(uint8_t), - .max_len = GATT_MAX_DATA_LENGTH, + mp_buffer_info_t char_value_bufinfo; + mp_get_buffer_raise(characteristic->value, &char_value_bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t char_attr = { + .p_uuid = &char_uuid, + .p_attr_md = &char_attr_md, + .init_len = char_value_bufinfo.len, + .p_value = char_value_bufinfo.buf, + .init_offs = 0, + .max_len = characteristic->max_length, }; - ble_gatts_char_handles_t handles; + ble_gatts_char_handles_t char_handles; uint32_t err_code; - err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &attr_char_value, &handles); + err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles); if (err_code != NRF_SUCCESS) { mp_raise_OSError_msg_varg(translate("Failed to add characteristic, err 0x%04x"), err_code); } - if (characteristic->handle != BLE_GATT_HANDLE_INVALID) { - mp_raise_ValueError(translate("Characteristic already in use by another Service.")); - } + characteristic->user_desc_handle = char_handles.user_desc_handle; + characteristic->cccd_handle = char_handles.cccd_handle; + characteristic->sccd_handle = char_handles.sccd_handle; + characteristic->handle = char_handles.value_handle; - characteristic->user_desc_handle = handles.user_desc_handle; - characteristic->cccd_handle = handles.cccd_handle; - characteristic->sccd_handle = handles.sccd_handle; - characteristic->handle = handles.value_handle; - } + // Add the descriptors for this characteristic. + for (size_t descriptor_idx = 0; descriptor_idx < characteristic->descriptor_list->len; ++descriptor_idx) { + bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[descriptor_idx]); + + ble_uuid_t desc_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + + ble_gatts_attr_md_t desc_attr_md = { + // Data passed is not in a permanent location and should be copied. + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = !descriptor->fixed_length, + }; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.write_perm); + + mp_buffer_info_t desc_value_bufinfo; + mp_get_buffer_raise(descriptor->value, &desc_value_bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t desc_attr = { + .p_uuid = &desc_uuid, + .p_attr_md = &desc_attr_md, + .init_len = desc_value_bufinfo.len, + .p_value = desc_value_bufinfo.buf, + .init_offs = 0, + .max_len = descriptor->max_length, + }; + + err_code = sd_ble_gatts_descriptor_add(characteristic->handle, &desc_attr, &descriptor->handle); + + } // loop over descriptors + + } // loop over characteristics } diff --git a/ports/nrf/common-hal/bleio/Service.h b/ports/nrf/common-hal/bleio/Service.h index 583593fb80..03ac2bca80 100644 --- a/ports/nrf/common-hal/bleio/Service.h +++ b/ports/nrf/common-hal/bleio/Service.h @@ -35,6 +35,8 @@ typedef struct { mp_obj_base_t base; // Handle for this service. uint16_t handle; + // True if created during discovery. + bool is_remote; bool is_secondary; bleio_uuid_obj_t *uuid; // May be a Peripheral, Central, etc. diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index 2dba5780c1..2e26ac07d0 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -26,12 +26,24 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Central.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" + #include "common-hal/bleio/__init__.h" +static volatile bool m_discovery_in_process; +static volatile bool m_discovery_successful; + +static bleio_service_obj_t *m_char_discovery_service; +static bleio_characteristic_obj_t *m_desc_discovery_characteristic; + // Turn off BLE on a reset or reload. void bleio_reset() { if (common_hal_bleio_adapter_get_enabled()) { @@ -47,13 +59,9 @@ const super_adapter_obj_t common_hal_bleio_adapter_obj = { }, }; -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device) { - if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; - } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; - } else { - return GATT_ROLE_NONE; +void common_hal_bleio_check_connected(uint16_t conn_handle) { + if (conn_handle == BLE_CONN_HANDLE_INVALID) { + mp_raise_OSError_msg(translate("Not connected")); } } @@ -63,6 +71,433 @@ uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; } else { - return 0; + return BLE_CONN_HANDLE_INVALID; } } + +mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device) { + if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; + } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; + } else { + return NULL; + } +} + +// service_uuid may be NULL, to discover all services. +STATIC bool discover_next_services(mp_obj_t device, uint16_t start_handle, ble_uuid_t *service_uuid) { + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_primary_services_discover(conn_handle, start_handle, service_uuid); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to discover services")); + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_characteristics(mp_obj_t device, bleio_service_obj_t *service, uint16_t start_handle) { + m_char_discovery_service = service; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = service->end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_descriptors(mp_obj_t device, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { + m_desc_discovery_characteristic = characteristic; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_service_t *gattc_service = &response->services[i]; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + // Initialize several fields at once. + common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); + + service->device = device; + service->is_remote = true; + service->start_handle = gattc_service->handle_range.start_handle; + service->end_handle = gattc_service->handle_range.end_handle; + service->handle = gattc_service->handle_range.start_handle; + + if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known service UUID. + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); + service->uuid = uuid; + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just set the UUID to NULL. + service->uuid = NULL; + } + + mp_obj_list_append(common_hal_bleio_device_get_remote_services_list(device), service); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_char_t *gattc_char = &response->chars[i]; + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known characteristic UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + bleio_characteristic_properties_t props = + (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | + (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | + (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | + (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | + (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | + (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); + + // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. + common_hal_bleio_characteristic_construct( + characteristic, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc + mp_obj_new_list(0, NULL)); + characteristic->handle = gattc_char->handle_value; + characteristic->service = m_char_discovery_service; + + mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_desc_t *gattc_desc = &response->descs[i]; + + // Remember handles for certain well-known descriptors. + switch (gattc_desc->uuid.uuid) { + case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: + m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; + break; + + case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: + m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; + break; + + case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: + m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; + break; + + default: + // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, + // so ignore those. + // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors + break; + } + + bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); + descriptor->base.type = &bleio_descriptor_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known descriptor UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + common_hal_bleio_descriptor_construct(descriptor, uuid, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + GATT_MAX_DATA_LENGTH, false); + descriptor->handle = gattc_desc->handle; + descriptor->characteristic = m_desc_discovery_characteristic; + + mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t device) { + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_DISCONNECTED: + m_discovery_successful = false; + m_discovery_in_process = false; + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); + break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: + on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, device); + break; + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_obj_list_t *remote_services_list = common_hal_bleio_device_get_remote_services_list(device); + + ble_drv_add_event_handler(discovery_on_ble_evt, device); + + // Start over with an empty list. + mp_obj_list_clear(MP_OBJ_FROM_PTR(common_hal_bleio_device_get_remote_services_list(device))); + + if (service_uuids_whitelist == mp_const_none) { + // List of service UUID's not given, so discover all available services. + + uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; + + while (discover_next_services(device, next_service_start_handle, MP_OBJ_NULL)) { + // discover_next_services() appends to remote_services_list. + + // Get the most recently discovered service, and then ask for services + // whose handles start after the last attribute handle inside that service. + const bleio_service_obj_t *service = + MP_OBJ_TO_PTR(remote_services_list->items[remote_services_list->len - 1]); + next_service_start_handle = service->end_handle + 1; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("non-UUID found in service_uuids_whitelist")); + } + bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + + ble_uuid_t nrf_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); + + // Service might or might not be discovered; that's ok. Caller has to check + // Central.remote_services to find out. + // We only need to call this once for each service to discover. + discover_next_services(device, BLE_GATT_HANDLE_START, &nrf_uuid); + } + } + + + for (size_t service_idx = 0; service_idx < remote_services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(remote_services_list->items[service_idx]); + + // Skip the service if it had an unknown (unregistered) UUID. + if (service->uuid == NULL) { + continue; + } + + uint16_t next_char_start_handle = service->start_handle; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_characteristics() appends to the characteristic_list. + while (next_char_start_handle <= service->end_handle && + discover_next_characteristics(device, service, next_char_start_handle)) { + + + // Get the most recently discovered characteristic, and then ask for characteristics + // whose handles start after the last attribute handle inside that characteristic. + const bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); + next_char_start_handle = characteristic->handle + 1; + } + + // Got characteristics for this service. Now discover descriptors for each characteristic. + size_t char_list_len = service->characteristic_list->len; + for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { + bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); + const bool last_characteristic = char_idx == char_list_len - 1; + bleio_characteristic_obj_t *next_characteristic = last_characteristic + ? NULL + : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); + + // Skip the characteristic if it had an unknown (unregistered) UUID. + if (characteristic->uuid == NULL) { + continue; + } + + uint16_t next_desc_start_handle = characteristic->handle + 1; + + // Don't run past the end of this service or the beginning of the next characteristic. + uint16_t next_desc_end_handle = next_characteristic == NULL + ? service->end_handle + : next_characteristic->handle - 1; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_descriptors() appends to the descriptor_list. + while (next_desc_start_handle <= service->end_handle && + next_desc_start_handle < next_desc_end_handle && + discover_next_descriptors(device, characteristic, + next_desc_start_handle, next_desc_end_handle)) { + + // Get the most recently discovered descriptor, and then ask for descriptors + // whose handles start after that descriptor's handle. + const bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); + next_desc_start_handle = descriptor->handle + 1; + } + } + } + + // This event handler is no longer needed. + ble_drv_remove_event_handler(discovery_on_ble_evt, device); + +} + +// GATTS read of a Characteristic or Descriptor. +mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle) { + // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because + // we can still read and write the local value. + + mp_buffer_info_t bufinfo; + ble_gatts_value_t gatts_value = { + .p_value = NULL, + .len = 0, + }; + + // Read once to find out what size buffer we need, then read again to fill buffer. + + mp_obj_t value = mp_const_none; + uint32_t err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); + if (err_code == NRF_SUCCESS) { + value = mp_obj_new_bytearray_of_zeros(gatts_value.len); + mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_WRITE); + gatts_value.p_value = bufinfo.buf; + + // Read again, with the correct size of buffer. + err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); + } + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read gatts value, err 0x%04x"), err_code); + } + + return value; +} + +void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { + // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because + // we can still read and write the local value. + + ble_gatts_value_t gatts_value = { + .p_value = bufinfo->buf, + .len = bufinfo->len, + }; + + const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to write gatts value, err 0x%04x"), err_code); + } +} + +void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { + common_hal_bleio_check_connected(conn_handle); + + ble_gattc_write_params_t write_params = { + .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, + .handle = handle, + .p_value = bufinfo->buf, + .len = bufinfo->len, + }; + + while (1) { + uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + if (err_code == NRF_SUCCESS) { + break; + } + + // Write with response will return NRF_ERROR_BUSY if the response has not been received. + // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. + if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { + // We could wait for an event indicating the write is complete, but just retrying is easier. + MICROPY_VM_HOOK_LOOP; + continue; + } + + // Some real error occurred. + mp_raise_OSError_msg_varg(translate("Failed to write attribute value, err 0x%04x"), err_code); + } + +} diff --git a/ports/nrf/common-hal/bleio/__init__.h b/ports/nrf/common-hal/bleio/__init__.h index 0c46b631fc..c0bba37994 100644 --- a/ports/nrf/common-hal/bleio/__init__.h +++ b/ports/nrf/common-hal/bleio/__init__.h @@ -27,16 +27,10 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" - -#include "shared-module/bleio/__init__.h" +void bleio_reset(void); // We assume variable length data. // 20 bytes max (23 - 3). #define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device); -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); - #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H diff --git a/ports/nrf/common-hal/busio/UART.c b/ports/nrf/common-hal/busio/UART.c index b9e9e55387..54a66ddbe7 100644 --- a/ports/nrf/common-hal/busio/UART.c +++ b/ports/nrf/common-hal/busio/UART.c @@ -235,13 +235,11 @@ size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t // Wait for all bytes received or timeout while ( (ringbuf_count(&self->rbuf) < len) && (ticks_ms - start_ticks < self->timeout_ms) ) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; + RUN_BACKGROUND_TASKS; // Allow user to break out of a timeout with a KeyboardInterrupt. if ( mp_hal_is_interrupted() ) { return 0; } -#endif } // prevent conflict with uart irq @@ -271,9 +269,7 @@ size_t common_hal_busio_uart_write (busio_uart_obj_t *self, const uint8_t *data, // Wait for on-going transfer to complete while ( nrfx_uarte_tx_in_progress(self->uarte) && (ticks_ms - start_ticks < self->timeout_ms) ) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } // Time up @@ -295,9 +291,7 @@ size_t common_hal_busio_uart_write (busio_uart_obj_t *self, const uint8_t *data, (*errcode) = 0; while ( nrfx_uarte_tx_in_progress(self->uarte) && (ticks_ms - start_ticks < self->timeout_ms) ) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } if ( !nrfx_is_in_ram(data) ) { diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index ab7b5d5d68..a6b1c4ba3b 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -37,6 +37,7 @@ #include "shared-bindings/microcontroller/Processor.h" #include "supervisor/filesystem.h" +#include "supervisor/shared/safe_mode.h" #include "nrfx_glue.h" // This routine should work even when interrupts are disabled. Used by OneWire @@ -52,7 +53,13 @@ void common_hal_mcu_enable_interrupts() { } void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { - // TODO: see atmel-samd for functionality + enum { DFU_MAGIC_UF2_RESET = 0x57 }; + if(runmode == RUNMODE_BOOTLOADER) + NRF_POWER->GPREGRET = DFU_MAGIC_UF2_RESET; + else + NRF_POWER->GPREGRET = 0; + if(runmode == RUNMODE_SAFE_MODE) + safe_mode_on_next_reset(PROGRAMMATIC_SAFE_MODE); } void common_hal_mcu_reset(void) { diff --git a/ports/nrf/common-hal/neopixel_write/__init__.c b/ports/nrf/common-hal/neopixel_write/__init__.c index 78e0038e8f..3b67778a62 100644 --- a/ports/nrf/common-hal/neopixel_write/__init__.c +++ b/ports/nrf/common-hal/neopixel_write/__init__.c @@ -200,9 +200,7 @@ void common_hal_neopixel_write (const digitalio_digitalinout_obj_t* digitalinout // But we have to wait for the flag to be set. while ( !nrf_pwm_event_check(pwm, NRF_PWM_EVENT_SEQEND0) ) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } // Before leave we clear the flag for the event. diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c index 5233c9adc6..b827470d3d 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.c +++ b/ports/nrf/common-hal/pulseio/PWMOut.c @@ -57,6 +57,12 @@ STATIC uint16_t pwm_seq[MP_ARRAY_SIZE(pwms)][CHANNELS_PER_PWM]; static uint8_t never_reset_pwm[MP_ARRAY_SIZE(pwms)]; +STATIC int pwm_idx(NRF_PWM_Type *pwm) { + for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) + if(pwms[i] == pwm) return i; + return -1; +} + void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { NRF_PWM_Type* pwm = pwms[i]; @@ -133,6 +139,57 @@ bool convert_frequency(uint32_t frequency, uint16_t *countertop, nrf_pwm_clk_t * return false; } +NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, + bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out) { + for (size_t pwm_index = 0; pwm_index < MP_ARRAY_SIZE(pwms); pwm_index++) { + NRF_PWM_Type *pwm = pwms[pwm_index]; + bool pwm_already_in_use = pwm->ENABLE & SPIM_ENABLE_ENABLE_Msk; + if (pwm_already_in_use) { + if (variable_frequency) { + // Variable frequency requires exclusive use of a PWM, so try the next one. + continue; + } + + // PWM is in use, but see if it's set to the same frequency we need. If so, + // look for a free channel. + if (pwm->COUNTERTOP == countertop && pwm->PRESCALER == base_clock) { + for (size_t chan = 0; chan < CHANNELS_PER_PWM; chan++) { + if (pwm->PSEL.OUT[chan] == 0xFFFFFFFF) { + // Channel is free. + if(channel_out) + *channel_out = chan; + if(pwm_already_in_use_out) + *pwm_already_in_use_out = pwm_already_in_use; + return pwm; + } + } + } + } else { + // PWM not yet in use, so we can start to use it. Use channel 0. + if(channel_out) + *channel_out = 0; + if(pwm_already_in_use_out) + *pwm_already_in_use_out = pwm_already_in_use; + return pwm; + } + } + return NULL; +} + +void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel) { + // Disconnect pin from channel. + pwm->PSEL.OUT[channel] = 0xFFFFFFFF; + + for(int i=0; i < CHANNELS_PER_PWM; i++) { + if (pwm->PSEL.OUT[i] != 0xFFFFFFFF) { + // Some channel is still being used, so don't disable. + return; + } + } + + nrf_pwm_disable(pwm); +} + pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, const mcu_pin_obj_t* pin, uint16_t duty, @@ -148,48 +205,16 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, return PWMOUT_INVALID_FREQUENCY; } - self->pwm = NULL; - self->channel = CHANNELS_PER_PWM; // out-of-range value. + int8_t channel; bool pwm_already_in_use; - NRF_PWM_Type* pwm; - size_t pwm_index = 0; - for (; pwm_index < MP_ARRAY_SIZE(pwms); pwm_index++) { - pwm = pwms[pwm_index]; - pwm_already_in_use = pwm->ENABLE & SPIM_ENABLE_ENABLE_Msk; - if (pwm_already_in_use) { - if (variable_frequency) { - // Variable frequency requires exclusive use of a PWM, so try the next one. - continue; - } - - // PWM is in use, but see if it's set to the same frequency we need. If so, - // look for a free channel. - if (pwm->COUNTERTOP == countertop && pwm->PRESCALER == base_clock) { - for (size_t chan = 0; chan < CHANNELS_PER_PWM; chan++) { - if (pwm->PSEL.OUT[chan] == 0xFFFFFFFF) { - // Channel is free. - self->pwm = pwm; - self->channel = chan; - break; - } - } - // Did we find a channel? If not, loop and check the next pwm. - if (self->pwm != NULL) { - break; - } - } - } else { - // PWM not yet in use, so we can start to use it. Use channel 0. - self->pwm = pwm; - self->channel = 0; - break; - } - } + self->pwm = pwmout_allocate(countertop, base_clock, variable_frequency, + &channel, &pwm_already_in_use); if (self->pwm == NULL) { return PWMOUT_ALL_TIMERS_IN_USE; } + self->channel = channel; self->pin_number = pin->number; claim_pin(pin); @@ -200,17 +225,17 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, nrf_gpio_cfg_output(self->pin_number); // disable before mapping pin channel - nrf_pwm_disable(pwm); + nrf_pwm_disable(self->pwm); if (!pwm_already_in_use) { - reset_single_pwmout(pwm_index); - nrf_pwm_configure(pwm, base_clock, NRF_PWM_MODE_UP, countertop); + reset_single_pwmout(pwm_idx(self->pwm)); + nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); } // Connect channel to pin, without disturbing other channels. - pwm->PSEL.OUT[self->channel] = pin->number; + self->pwm->PSEL.OUT[self->channel] = pin->number; - nrf_pwm_enable(pwm); + nrf_pwm_enable(self->pwm); common_hal_pulseio_pwmout_set_duty_cycle(self, duty); return PWMOUT_OK; @@ -230,17 +255,7 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { NRF_PWM_Type* pwm = self->pwm; self->pwm = NULL; - // Disconnect pin from channel. - pwm->PSEL.OUT[self->channel] = 0xFFFFFFFF; - - for(int i=0; i < CHANNELS_PER_PWM; i++) { - if (self->pwm->PSEL.OUT[i] != 0xFFFFFFFF) { - // Some channel is still being used, so don't disable. - return; - } - } - - nrf_pwm_disable(pwm); + pwmout_free_channel(pwm, self->channel); } void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty_cycle) { diff --git a/ports/nrf/common-hal/pulseio/PWMOut.h b/ports/nrf/common-hal/pulseio/PWMOut.h index a4e58dc1a5..b6798cb685 100644 --- a/ports/nrf/common-hal/pulseio/PWMOut.h +++ b/ports/nrf/common-hal/pulseio/PWMOut.h @@ -41,5 +41,8 @@ typedef struct { } pulseio_pwmout_obj_t; void pwmout_reset(void); +NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, + bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out); +void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel); #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/nrf/common-hal/pulseio/PulseOut.c b/ports/nrf/common-hal/pulseio/PulseOut.c index be5deca9fb..d0433247ac 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.c +++ b/ports/nrf/common-hal/pulseio/PulseOut.c @@ -155,9 +155,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu while(pulse_array_index < length) { // Do other things while we wait. The interrupts will handle sending the // signal. - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } nrfx_timer_disable(timer); diff --git a/ports/nrf/device/nrf52/startup_nrf52840.c b/ports/nrf/device/nrf52/startup_nrf52840.c index 30634a1b54..8e1c360128 100644 --- a/ports/nrf/device/nrf52/startup_nrf52840.c +++ b/ports/nrf/device/nrf52/startup_nrf52840.c @@ -116,7 +116,7 @@ void CRYPTOCELL_IRQHandler (void) __attribute__ ((weak, alias("Default_Han void SPIM3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); void PWM3_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler"))); -const func __Vectors[] __attribute__ ((section(".isr_vector"))) = { +const func __Vectors[] __attribute__ ((used, section(".isr_vector"))) = { (func)&_estack, Reset_Handler, NMI_Handler, diff --git a/ports/nrf/mpconfigport.mk b/ports/nrf/mpconfigport.mk index 83166708a6..55920b3f4a 100644 --- a/ports/nrf/mpconfigport.mk +++ b/ports/nrf/mpconfigport.mk @@ -10,11 +10,11 @@ USB_SERIAL_NUMBER_LENGTH = 16 # All nRF ports have longints. LONGINT_IMPL = MPZ -# No DAC, so no regular audio. +# Audio via PWM +CIRCUITPY_AUDIOCORE = 1 CIRCUITPY_AUDIOIO = 0 - -# No I2S yet. -CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOPWMIO = 1 +CIRCUITPY_AUDIOBUSIO = 1 # No I2CSlave implementation CIRCUITPY_I2CSLAVE = 0 diff --git a/ports/nrf/mphalport.c b/ports/nrf/mphalport.c index 7d9463d0be..bcd9fb1145 100644 --- a/ports/nrf/mphalport.c +++ b/ports/nrf/mphalport.c @@ -39,9 +39,7 @@ void mp_hal_delay_ms(mp_uint_t delay) { uint64_t start_tick = ticks_ms; uint64_t duration = 0; while (duration < delay) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; // Check to see if we've been CTRL-Ced by autoreload or the user. if(MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)) || MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index a2b48065dd..8fa6721e2c 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -78,6 +78,7 @@ // TIMERS #define NRFX_TIMER_ENABLED 1 // Don't enable TIMER0: it's used by the SoftDevice. +#define NRFX_TIMER0_ENABLED 0 #define NRFX_TIMER1_ENABLED 1 #define NRFX_TIMER2_ENABLED 1 diff --git a/ports/nrf/peripherals/nrf/timers.c b/ports/nrf/peripherals/nrf/timers.c index 7f7a003d3b..88f3dd4681 100644 --- a/ports/nrf/peripherals/nrf/timers.c +++ b/ports/nrf/peripherals/nrf/timers.c @@ -36,7 +36,7 @@ STATIC nrfx_timer_t nrfx_timers[] = { #if NRFX_CHECK(NRFX_TIMER0_ENABLED) - // Note that TIMER0 is reserved for use by the SoftDevice, so it should not usually be enabled. + #error NRFX_TIMER0_ENABLED should not be on: TIMER0 is used by the SoftDevice NRFX_TIMER_INSTANCE(0), #endif #if NRFX_CHECK(NRFX_TIMER1_ENABLED) diff --git a/ports/nrf/sd_mutex.c b/ports/nrf/sd_mutex.c index 7682ffa623..b3162e6af9 100644 --- a/ports/nrf/sd_mutex.c +++ b/ports/nrf/sd_mutex.c @@ -37,9 +37,7 @@ void sd_mutex_acquire_check(nrf_mutex_t* p_mutex) { void sd_mutex_acquire_wait(nrf_mutex_t* p_mutex) { while (sd_mutex_acquire(p_mutex) == NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP -#endif + RUN_BACKGROUND_TASKS; } } diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index 8fbf75498f..03f7876247 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -50,6 +50,10 @@ #include "shared-bindings/rtc/__init__.h" +#ifdef CIRCUITPY_AUDIOPWMIO +#include "common-hal/audiopwmio/PWMAudioOut.h" +#endif + static void power_warning_handler(void) { reset_into_safe_mode(BROWNOUT); } @@ -94,6 +98,10 @@ void reset_port(void) { spi_reset(); uart_reset(); +#ifdef CIRCUITPY_AUDIOPWMIO + audiopwmout_reset(); +#endif + #if CIRCUITPY_PULSEIO pwmout_reset(); pulseout_reset(); diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc0..d4733e3383 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -108,6 +108,9 @@ endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +SRC_PATTERNS += audiopwmio/% +endif ifeq ($(CIRCUITPY_AUDIOCORE),1) SRC_PATTERNS += audiocore/% endif @@ -223,10 +226,13 @@ $(filter $(SRC_PATTERNS), \ audiobusio/__init__.c \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ + audiopwmio/__init__.c \ + audiopwmio/PWMAudioOut.c \ audioio/__init__.c \ audioio/AudioOut.c \ bleio/__init__.c \ bleio/Adapter.c \ + bleio/Attribute.c \ bleio/Central.c \ bleio/Characteristic.c \ bleio/CharacteristicBuffer.c \ @@ -276,6 +282,9 @@ $(filter $(SRC_PATTERNS), \ # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + bleio/Address.c \ + bleio/Attribute.c \ + bleio/ScanEntry.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -289,12 +298,6 @@ SRC_BINDINGS_ENUMS += \ help.c \ util.c -SRC_BINDINGS_ENUMS += \ -$(filter $(SRC_PATTERNS), \ - bleio/Address.c \ - bleio/ScanEntry.c \ -) - # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_SHARED_MODULE = \ $(filter $(SRC_PATTERNS), \ @@ -303,6 +306,7 @@ $(filter $(SRC_PATTERNS), \ _stage/Layer.c \ _stage/Text.c \ _stage/__init__.c \ + audiopwmio/__init__.c \ audioio/__init__.c \ audiocore/__init__.c \ audiocore/Mixer.c \ @@ -314,6 +318,7 @@ $(filter $(SRC_PATTERNS), \ bitbangio/__init__.c \ board/__init__.c \ bleio/Address.c \ + bleio/Attribute.c \ bleio/ScanEntry.c \ busio/OneWire.c \ displayio/Bitmap.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 3440eb052a..393b7600c7 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -244,6 +244,13 @@ extern const struct _mp_obj_module_t audioio_module; #define AUDIOIO_MODULE #endif +#if CIRCUITPY_AUDIOPWMIO +#define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module }, +extern const struct _mp_obj_module_t audiopwmio_module; +#else +#define AUDIOPWMIO_MODULE +#endif + #if CIRCUITPY_BITBANGIO #define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }, extern const struct _mp_obj_module_t bitbangio_module; @@ -266,13 +273,7 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI)) #define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX)) -#if BOARD_I2C -#define BOARD_I2C_ROOT_POINTER mp_obj_t shared_i2c_bus; -#else -#define BOARD_I2C_ROOT_POINTER -#endif - -// SPI is always allocated off the heap. +// I2C and SPI are always allocated off the heap. #if BOARD_UART #define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus; @@ -282,7 +283,6 @@ extern const struct _mp_obj_module_t board_module; #else #define BOARD_MODULE -#define BOARD_I2C_ROOT_POINTER #define BOARD_UART_ROOT_POINTER #endif @@ -573,6 +573,7 @@ extern const struct _mp_obj_module_t ustack_module; AUDIOBUSIO_MODULE \ AUDIOCORE_MODULE \ AUDIOIO_MODULE \ + AUDIOPWMIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ @@ -595,8 +596,8 @@ extern const struct _mp_obj_module_t ustack_module; WIZNET_MODULE \ PEW_MODULE \ PIXELBUF_MODULE \ - PULSEIO_MODULE \ PS2IO_MODULE \ + PULSEIO_MODULE \ RANDOM_MODULE \ RE_MODULE \ ROTARYIO_MODULE \ @@ -639,12 +640,12 @@ extern const struct _mp_obj_module_t ustack_module; GAMEPAD_ROOT_POINTERS \ mp_obj_t pew_singleton; \ mp_obj_t terminal_tilegrid_tiles; \ - BOARD_I2C_ROOT_POINTER \ BOARD_UART_ROOT_POINTER \ FLASH_ROOT_POINTERS \ NETWORK_ROOT_POINTERS \ void run_background_tasks(void); +#define RUN_BACKGROUND_TASKS (run_background_tasks()) // TODO: Used in wiznet5k driver, but may not be needed in the long run. #define MICROPY_THREAD_YIELD() diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 772a1c3e1f..ac40223fe0 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -74,9 +74,24 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOIO_COMPAT +CIRCUITPY_AUDIOIO_COMPAT = $(CIRCUITPY_AUDIOIO) +endif +CFLAGS += -DCIRCUITPY_AUDIOIO_COMPAT=$(CIRCUITPY_AUDIOIO_COMPAT) + + +ifndef CIRCUITPY_AUDIOPWMIO +CIRCUITPY_AUDIOPWMIO = 0 +endif +CFLAGS += -DCIRCUITPY_AUDIOPWMIO=$(CIRCUITPY_AUDIOPWMIO) + ifndef CIRCUITPY_AUDIOCORE +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOPWMIO) +else CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO) endif +endif CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) ifndef CIRCUITPY_BITBANGIO diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 5b5ec1c378..8e3835d861 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -180,7 +180,7 @@ def compress(encoding_table, decompressed): if not isinstance(decompressed, bytes): raise TypeError() values, lengths = encoding_table - enc = bytearray(len(decompressed)) + enc = bytearray(len(decompressed) * 2) #print(decompressed) #print(lengths) current_bit = 7 @@ -227,6 +227,8 @@ def compress(encoding_table, decompressed): current_bit -= 1 if current_bit != 7: current_byte += 1 + if current_byte > len(decompressed): + print("Note: compression increased length", repr(decompressed.decode('utf-8')), len(decompressed), current_byte, file=sys.stderr) return enc[:current_byte] def qstr_escape(qst): diff --git a/py/obj.h b/py/obj.h index 6eead377db..c719c2945a 100644 --- a/py/obj.h +++ b/py/obj.h @@ -668,6 +668,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable); mp_obj_t mp_obj_new_dict(size_t n_args); mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); diff --git a/py/objlist.c b/py/objlist.c index 558c4c6115..ea38e64e55 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -68,6 +68,11 @@ STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { return list; } +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable) { + mp_obj_t list = mp_obj_new_list(0, NULL); + return list_extend_from_iter(list, iterable); +} + STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { (void)type_in; mp_arg_check_num(n_args, kw_args, 0, 1, false); diff --git a/py/objstr.c b/py/objstr.c index ebd11d5cc2..afe11f00f8 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -41,6 +41,12 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in); +const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + +const char nibble_to_hex_lower[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + /******************************************************************************/ /* str */ diff --git a/py/objstr.h b/py/objstr.h index 0efe62a801..61a11d0bd6 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -77,6 +77,9 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s mp_obj_t index, bool is_slice); const byte *find_subbytes(const byte *haystack, size_t hlen, const byte *needle, size_t nlen, int direction); +const char nibble_to_hex_upper[16]; +const char nibble_to_hex_lower[16]; + MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); diff --git a/py/objtuple.c b/py/objtuple.c index 474f81c1a5..ed13cdcef2 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -251,7 +251,8 @@ mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items) { } void mp_obj_tuple_get(mp_obj_t self_in, size_t *len, mp_obj_t **items) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + // type check is done on getiter method to allow tuple, namedtuple, attrtuple + mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); *len = self->len; *items = &self->items[0]; diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 9f3f894627..6096f6b6dd 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -50,7 +50,7 @@ //| Layer //| Text //| -//| .. function:: render(x0, y0, x1, y1, layers, buffer, display) +//| .. function:: render(x0, y0, x1, y1, layers, buffer, display[, scale]) //| //| Render and send to the display a fragment of the screen. //| @@ -61,6 +61,7 @@ //| :param list layers: A list of the :py:class:`~_stage.Layer` objects. //| :param bytearray 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. //| //| There are also no sanity checks, outside of the basic overflow //| checking. The caller is responsible for making the passed parameters @@ -89,11 +90,13 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { mp_raise_TypeError(translate("argument num/types mismatch")); } displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display); + uint8_t scale = 1; + if (n_args >= 8) { + scale = mp_obj_get_int(args[7]); + } while (!displayio_display_begin_transaction(display)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } displayio_area_t area; area.x1 = x0; @@ -101,12 +104,15 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { area.x2 = x1; area.y2 = y1; displayio_display_set_region_to_update(display, &area); - render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display); + + display->send(display->bus, true, &display->write_ram_command, 1); + render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, + display, scale); displayio_display_end_transaction(display); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 8, stage_render); STATIC const mp_rom_map_elem_t stage_module_globals_table[] = { diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 980f113929..9bce9c7609 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -56,7 +56,7 @@ //| using `UDA1334 Breakout `_:: //| //| import audiobusio -//| import audioio +//| import audiocore //| import board //| import array //| import time @@ -68,7 +68,7 @@ //| for i in range(length): //| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15) //| -//| sine_wave = audiobusio.RawSample(sine_wave, sample_rate=8000) +//| 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) @@ -78,12 +78,13 @@ //| //| import board //| import audioio +//| import audiocore //| import audiobusio //| import digitalio //| //| //| f = open("cplay-5.1-16bit-16khz.wav", "rb") -//| wav = audioio.WaveFile(f) +//| wav = audiocore.WaveFile(f) //| //| a = audiobusio.I2SOut(board.D1, board.D0, board.D9) //| @@ -163,7 +164,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_i2sout___exit___obj, 4, 4, //| Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| Sample must be an `audioio.WaveFile` or `audioio.RawSample`. +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`. //| //| The sample itself should consist of 8 bit or 16 bit samples. //| diff --git a/shared-bindings/audiocore/Mixer.c b/shared-bindings/audiocore/Mixer.c index b2f0a3fdac..9ab720434b 100644 --- a/shared-bindings/audiocore/Mixer.c +++ b/shared-bindings/audiocore/Mixer.c @@ -36,7 +36,7 @@ #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" -//| .. currentmodule:: audioio +//| .. currentmodule:: audiocore //| //| :class:`Mixer` -- Mixes one or more audio samples together //| =========================================================== @@ -54,15 +54,16 @@ //| //| import board //| import audioio +//| import audiocore //| import digitalio //| //| # Required for CircuitPlayground Express //| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) //| speaker_enable.switch_to_output(value=True) //| -//| music = audioio.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) -//| drum = audioio.WaveFile(open("drum.wav", "rb")) -//| mixer = audioio.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) +//| music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) +//| drum = audiocore.WaveFile(open("drum.wav", "rb")) +//| mixer = audiocore.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) //| a = audioio.AudioOut(board.A0) //| //| print("playing") @@ -151,7 +152,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, aud //| Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`. //| //| The sample must match the Mixer's encoding settings given in the constructor. //| diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c index 912b48bfbb..07f8c683f2 100644 --- a/shared-bindings/audiocore/RawSample.c +++ b/shared-bindings/audiocore/RawSample.c @@ -35,7 +35,7 @@ #include "shared-bindings/audiocore/RawSample.h" #include "supervisor/shared/translate.h" -//| .. currentmodule:: audioio +//| .. currentmodule:: audiocore //| //| :class:`RawSample` -- A raw audio sample buffer //| ======================================================== @@ -55,6 +55,7 @@ //| //| Simple 8ksps 440 Hz sin wave:: //| +//| import audiocore //| import audioio //| import board //| import array @@ -68,7 +69,7 @@ //| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15)) //| //| dac = audioio.AudioOut(board.SPEAKER) -//| sine_wave = audioio.RawSample(sine_wave) +//| sine_wave = audiocore.RawSample(sine_wave) //| dac.play(sine_wave, loop=True) //| time.sleep(1) //| dac.stop() diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 4c1993b7c4..1b3a94ff37 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -33,23 +33,27 @@ #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" -//| .. currentmodule:: audioio +//| .. currentmodule:: audiocore //| //| :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. +//| be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating +//| an internal buffer. //| -//| .. class:: WaveFile(file) +//| .. class:: WaveFile(file[, buffer]) //| //| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`. //| //| :param typing.BinaryIO file: Already opened wave file +//| :param bytearray buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two 512 byte buffers are allocated internally. +//| //| //| Playing a wave file from flash:: //| //| import board +//| import audiocore //| import audioio //| import digitalio //| @@ -58,7 +62,7 @@ //| speaker_enable.switch_to_output(value=True) //| //| data = open("cplay-5.1-16bit-16khz.wav", "rb") -//| wav = audioio.WaveFile(data) +//| wav = audiocore.WaveFile(data) //| a = audioio.AudioOut(board.A0) //| //| print("playing") @@ -68,15 +72,23 @@ //| print("stopped") //| STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 1, false); + mp_arg_check_num(n_args, kw_args, 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)) { - common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0])); - } else { + 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_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0]), + buffer, buffer_size); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiocore/WaveFile.h b/shared-bindings/audiocore/WaveFile.h index d2572318be..f4a1723192 100644 --- a/shared-bindings/audiocore/WaveFile.h +++ b/shared-bindings/audiocore/WaveFile.h @@ -35,7 +35,7 @@ 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); + 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); diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c index 79df66f7dd..af2fce48e3 100644 --- a/shared-bindings/audioio/AudioOut.c +++ b/shared-bindings/audioio/AudioOut.c @@ -55,6 +55,7 @@ //| //| Simple 8ksps 440 Hz sin wave:: //| +//| import audiocore //| import audioio //| import board //| import array @@ -68,7 +69,7 @@ //| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15) //| //| dac = audioio.AudioOut(board.SPEAKER) -//| sine_wave = audioio.RawSample(sine_wave, sample_rate=8000) +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) //| dac.play(sine_wave, loop=True) //| time.sleep(1) //| dac.stop() @@ -84,7 +85,7 @@ //| speaker_enable.switch_to_output(value=True) //| //| data = open("cplay-5.1-16bit-16khz.wav", "rb") -//| wav = audioio.WaveFile(data) +//| wav = audiocore.WaveFile(data) //| a = audioio.AudioOut(board.A0) //| //| print("playing") @@ -162,7 +163,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_audioout___exit___obj, 4, 4, //| Plays the sample once when loop=False and continuously when loop=True. //| Does not block. Use `playing` to block. //| -//| Sample must be an `audioio.WaveFile` or `audioio.RawSample`. +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`. //| //| 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 diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c index 3fecf2708d..bd771dda2e 100644 --- a/shared-bindings/audioio/__init__.c +++ b/shared-bindings/audioio/__init__.c @@ -33,6 +33,12 @@ #include "shared-bindings/audioio/__init__.h" #include "shared-bindings/audioio/AudioOut.h" +#ifdef CIRCUITPY_AUDIOIO_COMPAT +#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" +#endif + //| :mod:`audioio` --- Support for audio input and output //| ====================================================== //| @@ -57,10 +63,19 @@ //| Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved //| to :mod:`audiocore`. //| +//| 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 CicuitPython. +//| 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) }, +#ifdef CIRCUITPY_AUDIOIO_COMPAT + { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, + { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, + { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, +#endif }; STATIC MP_DEFINE_CONST_DICT(audioio_module_globals, audioio_module_globals_table); diff --git a/shared-bindings/audiopwmio/PWMAudioOut.c b/shared-bindings/audiopwmio/PWMAudioOut.c new file mode 100644 index 0000000000..92543d1128 --- /dev/null +++ b/shared-bindings/audiopwmio/PWMAudioOut.c @@ -0,0 +1,294 @@ +/* + * 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 + +#include "lib/utils/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" + +//| .. currentmodule:: audiopwmio +//| +//| :class:`PWMAudioOut` -- Output an analog audio signal +//| ======================================================== +//| +//| AudioOut can be used to output an analog audio signal on a given pin. +//| +//| .. class:: PWMAudioOut(left_channel, *, right_channel=None, quiescent_value=0x8000) +//| +//| 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 / 18) * (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, const mp_obj_t *pos_args, mp_map_t *kw_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(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t left_channel_obj = args[ARG_left_channel].u_obj; + assert_pin(left_channel_obj, false); + const mcu_pin_obj_t *left_channel_pin = MP_OBJ_TO_PTR(left_channel_obj); + + mp_obj_t right_channel_obj = args[ARG_right_channel].u_obj; + const mcu_pin_obj_t *right_channel_pin = NULL; + if (right_channel_obj != mp_const_none) { + assert_pin(right_channel_obj, false); + right_channel_pin = MP_OBJ_TO_PTR(right_channel_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); +} + +//| .. method:: deinit() +//| +//| 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(); + } +} +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| 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__); + + +//| .. method:: play(sample, *, loop=False) +//| +//| 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`, or `audiocore.Mixer`. +//| +//| 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 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); + +//| .. method:: stop() +//| +//| 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); + +//| .. attribute:: playing +//| +//| 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); + +const mp_obj_property_t audiopwmio_pwmaudioout_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_pwmaudioout_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. method:: pause() +//| +//| 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); + +//| .. method:: resume() +//| +//| 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); + +//| .. attribute:: paused +//| +//| 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); + +const mp_obj_property_t audiopwmio_pwmaudioout_paused_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_pwmaudioout_get_paused_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_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/shared-bindings/audiopwmio/PWMAudioOut.h b/shared-bindings/audiopwmio/PWMAudioOut.h new file mode 100644 index 0000000000..22afc70d38 --- /dev/null +++ b/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/shared-bindings/audiopwmio/__init__.c b/shared-bindings/audiopwmio/__init__.c new file mode 100644 index 0000000000..8a2b202b36 --- /dev/null +++ b/shared-bindings/audiopwmio/__init__.c @@ -0,0 +1,71 @@ +/* + * 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 + +#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" + +//| :mod:`audiopwmio` --- Support for audio input and output +//| ======================================================== +//| +//| .. module:: audiopwmio +//| :synopsis: Support for audio output via digital PWM +//| :platform: NRF52 +//| +//| The `audiopwmio` module contains classes to provide access to audio IO. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| PWMAudioOut +//| +//| 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, +}; diff --git a/shared-bindings/audiopwmio/__init__.h b/shared-bindings/audiopwmio/__init__.h new file mode 100644 index 0000000000..e4b7067d11 --- /dev/null +++ b/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_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/shared-bindings/bleio/Adapter.c b/shared-bindings/bleio/Adapter.c index 7b8df51034..2bb7f34653 100644 --- a/shared-bindings/bleio/Adapter.c +++ b/shared-bindings/bleio/Adapter.c @@ -53,12 +53,6 @@ //| //| State of the BLE adapter. //| - -//| .. attribute:: adapter.address -//| -//| MAC address of the BLE adapter. (read-only) -//| - STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) { return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled()); } @@ -80,13 +74,13 @@ const mp_obj_property_t bleio_adapter_enabled_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: adapter.address +//| +//| MAC address of the BLE adapter. (read-only) +//| STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) { - mp_obj_t obj = bleio_address_type.make_new(&bleio_address_type, 1, 0, mp_const_none); - bleio_address_obj_t *address = MP_OBJ_TO_PTR(obj); + return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address()); - common_hal_bleio_adapter_get_address(address); - - return obj; } MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address); @@ -97,9 +91,29 @@ const mp_obj_property_t bleio_adapter_address_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: adapter.default_name +//| +//| default_name of the BLE adapter. (read-only) +//| 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_default_name(mp_obj_t self) { + return common_hal_bleio_adapter_get_default_name(); + +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_default_name_obj, bleio_adapter_get_default_name); + +const mp_obj_property_t bleio_adapter_default_name_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_adapter_get_default_name_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + 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_default_name), MP_ROM_PTR(&bleio_adapter_default_name_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict_table); diff --git a/shared-bindings/bleio/Adapter.h b/shared-bindings/bleio/Adapter.h index de9d1d6db1..72382616ca 100644 --- a/shared-bindings/bleio/Adapter.h +++ b/shared-bindings/bleio/Adapter.h @@ -34,6 +34,7 @@ const mp_obj_type_t bleio_adapter_type; extern bool common_hal_bleio_adapter_get_enabled(void); extern void common_hal_bleio_adapter_set_enabled(bool enabled); -extern void common_hal_bleio_adapter_get_address(bleio_address_obj_t *address); +extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(void); +extern mp_obj_t common_hal_bleio_adapter_get_default_name(void); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c index 37f01042ce..baeb6d7c0a 100644 --- a/shared-bindings/bleio/Address.c +++ b/shared-bindings/bleio/Address.c @@ -83,7 +83,21 @@ STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, //| .. attribute:: address_bytes //| -//| The bytes that make up the device address (read-only) +//| 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:: pycon +//| +//| >>> import bleio +//| >>> bleio.adapter.address +//|
+//| >>> 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); @@ -147,18 +161,13 @@ STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o 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); - if (kind == PRINT_STR) { - 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); + 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, - "%02x:%02x:%02x:%02x:%02x:%02x", - buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); - } else { - mp_printf(print, "
"); - } + const uint8_t *buf = (uint8_t *) buf_info.buf; + mp_printf(print, "
", + buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); } //| .. data:: PUBLIC @@ -179,13 +188,13 @@ STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_pr //| 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) }, + { 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_OBJ_NEW_SMALL_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_OBJ_NEW_SMALL_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(2) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(3) }, + { 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) }, }; diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c new file mode 100644 index 0000000000..2cc9ef6d05 --- /dev/null +++ b/shared-bindings/bleio/Attribute.c @@ -0,0 +1,94 @@ +/* + * 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" + +// + +//| .. currentmodule:: bleio +//| +//| :class:`Attribute` -- BLE 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. +//| +//| .. class:: Attribute() +//| +//| You cannot create an instance of :py:class:`~bleio.Attribute`. +//| + +STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { + +//| .. data:: NO_ACCESS +//| +//| security mode: access not allowed +//| +//| .. data:: OPEN +//| +//| security_mode: no security (link is not encrypted) +//| +//| .. data:: ENCRYPT_NO_MITM +//| +//| security_mode: unauthenticated encryption, without man-in-the-middle protection +//| +//| .. data:: ENCRYPT_WITH_MITM +//| +//| security_mode: authenticated encryption, with man-in-the-middle protection +//| +//| .. data:: LESC_ENCRYPT_WITH_MITM +//| +//| security_mode: LESC encryption, with man-in-the-middle protection +//| +//| .. data:: SIGNED_NO_MITM +//| +//| security_mode: unauthenticated data signing, without man-in-the-middle protection +//| +//| .. data:: SIGNED_WITH_MITM +//| +//| 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/shared-bindings/bleio/Attribute.h b/shared-bindings/bleio/Attribute.h new file mode 100644 index 0000000000..06a6eb5a9a --- /dev/null +++ b/shared-bindings/bleio/Attribute.h @@ -0,0 +1,38 @@ +/* + * 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 "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/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c index fc00bce5cc..1fc455d8db 100644 --- a/shared-bindings/bleio/Central.c +++ b/shared-bindings/bleio/Central.c @@ -56,12 +56,16 @@ //| //| my_entry = None //| for entry in entries: -//| if entry.name is not None and entry.name == 'MyPeripheral': +//| if entry.name is not None and entry.name == 'InterestingPeripheral': //| my_entry = entry //| break //| -//| central = bleio.Central(my_entry.address) -//| central.connect(10.0) # timeout after 10 seconds +//| if not my_entry: +//| raise Exception("'InterestingPeripheral' not found") +//| +//| central = bleio.Central() +//| central.connect(my_entry.address, 10) # timeout after 10 seconds +//| remote_services = central.discover_remote_services() //| //| .. class:: Central() @@ -79,24 +83,11 @@ STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } -//| .. method:: connect(address, timeout, *, service_uuids=None) -//| Attempts a connection to the remote peripheral. If the connection is successful, -//| Do BLE discovery for the listed services, to find their handles and characteristics. -//| The attribute `remote_services` will contain a list of all discovered services. +//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None) +//| Attempts a connection to the remote peripheral. //| //| :param bleio.Address address: The address of the peripheral to connect to //| :param float/int timeout: Try to connect for timeout seconds. -//| :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. -//| If a service in service_uuids is not found during discovery, it will not -//| appear in `remote_services`. -//| -//| 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. (This restriction may be lifted in the future.) //| STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -105,7 +96,6 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args static const mp_arg_t allowed_args[] = { { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_service_uuids_whitelist, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -119,7 +109,7 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); // common_hal_bleio_central_connect() will validate that services is an iterable or None. - common_hal_bleio_central_connect(self, address, timeout, args[ARG_service_uuids_whitelist].u_obj); + common_hal_bleio_central_connect(self, address, timeout); return mp_const_none; } @@ -139,6 +129,46 @@ STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect); +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics, and return the discovered services. +//| `Peripheral.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 services provided by the remote peripheral. +//| +STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_central_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); + + if (!common_hal_bleio_central_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + return MP_OBJ_FROM_PTR(common_hal_bleio_central_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services); + //| .. attribute:: connected //| //| True if connected to a remove peripheral. @@ -157,36 +187,14 @@ const mp_obj_property_t bleio_central_connected_obj = { (mp_obj_t)&mp_const_none_obj }, }; - -//| .. attribute:: remote_services (read-only) -//| -//| A tuple of services provided by the remote peripheral. -//| If the Central is not connected, an empty tuple will be returned. -//| -STATIC mp_obj_t bleio_central_get_remote_services(mp_obj_t self_in) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); - - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *service_list = common_hal_bleio_central_get_remote_services(self); - return mp_obj_new_tuple(service_list->len, service_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_remote_services_obj, bleio_central_get_remote_services); - -const mp_obj_property_t bleio_central_remote_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_central_get_remote_services_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_central_discover_remote_services_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) }, - { MP_ROM_QSTR(MP_QSTR_remote_services), MP_ROM_PTR(&bleio_central_remote_services_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table); diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h index 0e84037f91..cbc437087b 100644 --- a/shared-bindings/bleio/Central.h +++ b/shared-bindings/bleio/Central.h @@ -28,15 +28,16 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H +#include "py/objtuple.h" #include "common-hal/bleio/Central.h" #include "common-hal/bleio/Service.h" extern const mp_obj_type_t bleio_central_type; extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); -extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout, mp_obj_t service_uuids); +extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); -extern mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index 3bf0476ab5..4894ad114a 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -28,7 +28,9 @@ #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" //| .. currentmodule:: bleio @@ -40,30 +42,36 @@ //| and writing of the characteristic's value. //| //| -//| .. class:: Characteristic(uuid, *, broadcast=False, indicate=False, notify=False, read=False, write=False, write_no_response=False) +//| .. class:: Characteristic(uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, descriptors=None) //| //| Create a new Characteristic object identified by the specified UUID. //| //| :param bleio.UUID uuid: The uuid of the characteristic -//| :param bool broadcast: Allowed in advertising packets -//| :param bool indicate: Server will indicate to the client when the value is set and wait for a response -//| :param bool notify: Server will notify the client when the value is set -//| :param bool read: Clients may read this characteristic -//| :param bool write: Clients may write this characteristic; a response will be sent back -//| :param bool write_no_response: Clients may write this characteristic; no response will be sent back +//| :param int properties: 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 iterable descriptors: BLE descriptors for this characteristic. //| STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { - ARG_uuid, ARG_broadcast, ARG_indicate, ARG_notify, ARG_read, ARG_write, ARG_write_no_response, - }; + enum { ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm, + ARG_max_length, ARG_fixed_length, ARG_descriptors }; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_broadcast, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_indicate, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_notify, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_read, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_write, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_write_no_response, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, + { 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_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -76,129 +84,69 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + 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); + + mp_obj_t descriptors = args[ARG_descriptors].u_obj; + if (descriptors == mp_const_none) { + descriptors = mp_const_empty_tuple; + } + bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); self->base.type = &bleio_characteristic_type; - bleio_characteristic_properties_t properties; + // Copy the descriptors list and validate its items. + mp_obj_t desc_list_obj = mp_obj_new_list(0, NULL); + mp_obj_list_t *desc_list = MP_OBJ_TO_PTR(desc_list_obj); - properties.broadcast = args[ARG_broadcast].u_bool; - properties.indicate = args[ARG_indicate].u_bool; - properties.notify = args[ARG_notify].u_bool; - properties.read = args[ARG_read].u_bool; - properties.write = args[ARG_write].u_bool; - properties.write_no_response = args[ARG_write_no_response].u_bool; + // If descriptors is not an iterable, an exception will be thrown. + mp_obj_iter_buf_t iter_buf; + mp_obj_t descriptors_iter = mp_getiter(descriptors, &iter_buf); - // Initialize, with an empty descriptor list. - common_hal_bleio_characteristic_construct(self, uuid, properties, mp_obj_new_list(0, NULL)); + mp_obj_t descriptor_obj; + while ((descriptor_obj = mp_iternext(descriptors_iter)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(descriptor_obj, &bleio_descriptor_type)) { + mp_raise_ValueError(translate("descriptors includes an object that is not a Descriptors")); + } + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(descriptor_obj); + if (common_hal_bleio_descriptor_get_characteristic(descriptor) != MP_OBJ_NULL) { + mp_raise_ValueError(translate("Descriptor is already attached to a Characteristic")); + } + mp_obj_list_append(desc_list_obj, descriptor_obj); + } + + // 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(self, uuid, properties, + read_perm, write_perm, + args[ARG_max_length].u_int, args[ARG_fixed_length].u_bool, + desc_list); return MP_OBJ_FROM_PTR(self); } -//| .. attribute:: broadcast +//| .. attribute:: properties //| -//| A `bool` specifying if the characteristic allows broadcasting its value. (read-only) +//| An int bitmask representing which properties are set. //| -STATIC mp_obj_t bleio_characteristic_get_broadcast(mp_obj_t self_in) { +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_bool(common_hal_bleio_characteristic_get_properties(self).broadcast); + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_broadcast_obj, bleio_characteristic_get_broadcast); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties); -const mp_obj_property_t bleio_characteristic_broadcast_obj = { +const mp_obj_property_t bleio_characteristic_properties_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_broadcast_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: indicate -//| -//| A `bool` specifying if the characteristic allows indicating its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_indicate(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).indicate); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_indicate_obj, bleio_characteristic_get_indicate); - - -const mp_obj_property_t bleio_characteristic_indicate_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_indicate_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: notify -//| -//| A `bool` specifying if the characteristic allows notifying its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_notify(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).notify); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_notify_obj, bleio_characteristic_get_notify); - -const mp_obj_property_t bleio_characteristic_notify_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_notify_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: read -//| -//| A `bool` specifying if the characteristic allows reading its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_read(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).read); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_read_obj, bleio_characteristic_get_read); - -const mp_obj_property_t bleio_characteristic_read_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_read_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: write -//| -//| A `bool` specifying if the characteristic allows writing to its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_write(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_obj, bleio_characteristic_get_write); - -const mp_obj_property_t bleio_characteristic_write_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_write_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: write_no_response -//| -//| A `bool` specifying if the characteristic allows writing to its value without response. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_write_no_response(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write_no_response); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_no_response_obj, bleio_characteristic_get_write_no_response); - -const mp_obj_property_t bleio_characteristic_write_no_response_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_write_no_response_obj, + .proxy = { (mp_obj_t)&bleio_characteristic_get_properties_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; @@ -225,9 +173,7 @@ const mp_obj_property_t bleio_characteristic_uuid_obj = { //| .. attribute:: value //| -//| The value of this characteristic. The value can be written to if the `write` property allows it. -//| If the `read` property allows it, the value can be read. If the `notify` property is set, writing -//| to the value will generate a BLE notification. +//| 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); @@ -274,6 +220,24 @@ const mp_obj_property_t bleio_characteristic_descriptors_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: service (read-only) +//| +//| The Service this Characteristic is a part of. None if not yet assigned to a Service. +//| +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); + +const mp_obj_property_t bleio_characteristic_service_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_service_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + //| .. method:: set_cccd(*, notify=False, indicate=False) //| //| Set the remote characteristic's CCCD to enable or disable notification and indication. @@ -301,16 +265,43 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_ch STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_broadcast), MP_ROM_PTR(&bleio_characteristic_broadcast_obj) }, - { MP_ROM_QSTR(MP_QSTR_descriptors), MP_ROM_PTR(&bleio_characteristic_descriptors_obj) }, - { MP_ROM_QSTR(MP_QSTR_indicate), MP_ROM_PTR(&bleio_characteristic_indicate_obj) }, - { MP_ROM_QSTR(MP_QSTR_notify), MP_ROM_PTR(&bleio_characteristic_notify_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&bleio_characteristic_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_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_write), MP_ROM_PTR(&bleio_characteristic_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_no_response), MP_ROM_PTR(&bleio_characteristic_write_no_response_obj) }, + { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties) }, + { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_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) }, + + // Bitmask constants to represent properties +//| .. data:: BROADCAST +//| +//| property: allowed in advertising packets +//| +//| .. data:: INDICATE +//| +//| property: server will indicate to the client when the value is set and wait for a response +//| +//| .. data:: NOTIFY +//| +//| property: server will notify the client when the value is set +//| +//| .. data:: READ +//| +//| property: clients may read this characteristic +//| +//| .. data:: WRITE +//| +//| property: clients may write this characteristic; a response will be sent back +//| +//| .. data:: WRITE_NO_RESPONSE +//| +//| 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); @@ -330,5 +321,5 @@ const mp_obj_type_t bleio_characteristic_type = { .name = MP_QSTR_Characteristic, .make_new = bleio_characteristic_make_new, .print = bleio_characteristic_print, - .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict + .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict, }; diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h index d450c42b4e..87942c8e90 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -28,17 +28,19 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H +#include "shared-bindings/bleio/Attribute.h" #include "shared-module/bleio/Characteristic.h" #include "common-hal/bleio/Characteristic.h" extern const mp_obj_type_t bleio_characteristic_type; -extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, mp_obj_list_t *descriptor_list); +extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, 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_obj_list_t *descriptor_list); extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); +extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index f2e5aa01df..d7c2a85c74 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -28,6 +28,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/UUID.h" @@ -41,23 +42,30 @@ //| information about the characteristic. //| -//| .. class:: Descriptor(uuid) +//| .. class:: Descriptor(uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`) //| -//| Create a new descriptor object with the UUID uuid. - -//| .. attribute:: handle +//| Create a new descriptor object with the UUID uuid //| -//| The descriptor handle. (read-only) -//| - -//| .. attribute:: uuid -//| -//| The descriptor uuid. (read-only) +//| :param bleio.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 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. //| STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_uuid }; + enum { ARG_uuid, ARG_read_perm, ARG_write_perm, ARG_max_length, ARG_fixed_length }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { 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_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -69,28 +77,28 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar mp_raise_ValueError(translate("Expected a 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); + bleio_descriptor_obj_t *self = m_new_obj(bleio_descriptor_obj_t); self->base.type = type; bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_arg); - common_hal_bleio_descriptor_construct(self, uuid); + + // 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(self, uuid, read_perm, write_perm, + args[ARG_max_length].u_int, args[ARG_fixed_length].u_bool); return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t bleio_descriptor_get_handle(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_int(common_hal_bleio_descriptor_get_handle(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_handle_obj, bleio_descriptor_get_handle); - -const mp_obj_property_t bleio_descriptor_handle_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_descriptor_get_handle_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - +//| .. attribute:: 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); @@ -106,56 +114,59 @@ const mp_obj_property_t bleio_descriptor_uuid_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. attribute:: characteristic (read-only) +//| +//| The Characteristic this Descriptor is a part of. None if not yet assigned to a Characteristic. +//| +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); + +const mp_obj_property_t bleio_descriptor_characteristic_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_descriptor_get_characteristic_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: value +//| +//| 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); + + return common_hal_bleio_descriptor_get_value(self); +} +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); + +const mp_obj_property_t bleio_descriptor_value_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_descriptor_get_value_obj, + (mp_obj_t)&bleio_descriptor_set_value_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { // Properties - { MP_ROM_QSTR(MP_QSTR_handle), MP_ROM_PTR(&bleio_descriptor_handle_obj) }, { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) }, - - // Static variables - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_EXTENDED_PROPERTIES), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_USER_DESCRIPTION), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION) }, - - { MP_ROM_QSTR(MP_QSTR_CLIENT_CHARACTERISTIC_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_SERVER_CHARACTERISTIC_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_PRESENTATION_FORMAT), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_AGGREGATE_FORMAT), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT) }, - - { MP_ROM_QSTR(MP_QSTR_VALID_RANGE), - MP_ROM_INT(DESCRIPTOR_UUID_VALID_RANGE) }, - - { MP_ROM_QSTR(MP_QSTR_EXTERNAL_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_NUMBER_OF_DIGITALS), - MP_ROM_INT(DESCRIPTOR_UUID_NUMBER_OF_DIGITALS) }, - - { MP_ROM_QSTR(MP_QSTR_VALUE_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_MEASUREMENT ), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_TIME_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_TIME_TRIGGER_SETTING) }, + { 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); diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h index fd11ea08cd..430c0d0b62 100644 --- a/shared-bindings/bleio/Descriptor.h +++ b/shared-bindings/bleio/Descriptor.h @@ -28,31 +28,16 @@ #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/Descriptor.h" #include "common-hal/bleio/UUID.h" -enum { - DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900, - DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION = 0x2901, - DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION = 0x2902, - DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION = 0x2903, - DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT = 0x2904, - DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT = 0x2905, - DESCRIPTOR_UUID_VALID_RANGE = 0x2906, - DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE = 0x2907, - DESCRIPTOR_UUID_REPORT_REFERENCE = 0x2908, - DESCRIPTOR_UUID_NUMBER_OF_DIGITALS = 0x2909, - DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING = 0x290A, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION = 0x290B, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT = 0x290C, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING = 0x290D, - DESCRIPTOR_UUID_TIME_TRIGGER_SETTING = 0x290E, -}; - extern const mp_obj_type_t bleio_descriptor_type; -extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid); -extern mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self); -extern mp_obj_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); +extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, 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); +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 mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self); +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/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index 570896d27e..630e6ed364 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -44,8 +44,6 @@ #include "common-hal/bleio/Peripheral.h" -static const char default_name[] = "CIRCUITPY"; - #define ADV_INTERVAL_DEFAULT (1.0f) #define ADV_INTERVAL_MIN (0.0020f) #define ADV_INTERVAL_MIN_STRING "0.0020" @@ -80,14 +78,14 @@ static const char default_name[] = "CIRCUITPY"; //| # Wait for connection. //| pass //| -//| .. class:: Peripheral(services=(), \*, name='CIRCUITPY') +//| .. class:: Peripheral(services=(), \*, name=None) //| //| Create a new Peripheral object. //| //| :param iterable services: the Service objects representing services available from this peripheral, if any. //| A non-connectable peripheral will have no services. -//| :param str name: The name used when advertising this peripheral. Use ``None`` when a name is not needed, -//| such as when the peripheral is a beacon +//| :param str name: The name used when advertising this peripheral. If name is None, +//| bleio.adapter.default_name will be used. //| STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_services, ARG_name }; @@ -107,33 +105,30 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar self->base.type = &bleio_peripheral_type; // Copy the services list and validate its items. - mp_obj_t service_list_obj = mp_obj_new_list(0, NULL); - mp_obj_list_t *service_list = MP_OBJ_FROM_PTR(service_list_obj); + mp_obj_t services_list_obj = mp_obj_new_list(0, NULL); + mp_obj_list_t *services_list = MP_OBJ_FROM_PTR(services_list_obj); mp_obj_t service; while ((service = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (!MP_OBJ_IS_TYPE(service, &bleio_service_type)) { mp_raise_ValueError(translate("non-Service found in services")); } - mp_obj_list_append(service_list, service); + mp_obj_list_append(services_list, service); } - const mp_obj_t name = args[ARG_name].u_obj; - mp_obj_t name_str; + mp_obj_t name = args[ARG_name].u_obj; if (name == MP_OBJ_NULL || name == mp_const_none) { - name_str = mp_obj_new_str(default_name, strlen(default_name)); - } else if (MP_OBJ_IS_STR(name)) { - name_str = name; - } else { + name = common_hal_bleio_adapter_get_default_name(); + } else if (!MP_OBJ_IS_STR(name)) { mp_raise_ValueError(translate("name must be a string")); } - common_hal_bleio_peripheral_construct(self, service_list, name_str); + common_hal_bleio_peripheral_construct(self, services_list, name); return MP_OBJ_FROM_PTR(self); } -//| .. attribute:: connected +//| .. attribute:: connected (read-only) //| //| True if connected to a BLE Central device. //| @@ -158,8 +153,8 @@ const mp_obj_property_t bleio_peripheral_connected_obj = { STATIC mp_obj_t bleio_peripheral_get_services(mp_obj_t self_in) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *service_list = common_hal_bleio_peripheral_get_service_list(self); - return mp_obj_new_tuple(service_list->len, service_list->items); + mp_obj_list_t *services_list = common_hal_bleio_peripheral_get_services(self); + return mp_obj_new_tuple(services_list->len, services_list->items); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services); @@ -265,16 +260,75 @@ STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect); +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics, and return the discovered services. +//| `Peripheral.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.) +//| +//| Thought it is unusual for a peripheral to act as a BLE client, it can do so, and +//| needs to be able to do discovery on its peer (a central). +//| Examples include a peripheral accessing a central that provides Current Time Service, +//| Apple Notification Center Service, or Battery Service. +//| +//| :return: A tuple of services provided by the remote central. +//| +STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_peripheral_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); + + if (!common_hal_bleio_peripheral_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + return MP_OBJ_FROM_PTR(common_hal_bleio_peripheral_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); + +//| .. method:: pair() +//| +//| Request pairing with connected central. +STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_peripheral_pair(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair); + STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_peripheral_discover_remote_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_pair) , MP_ROM_PTR(&bleio_peripheral_pair_obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, - { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_peripheral_locals_dict, bleio_peripheral_locals_dict_table); diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h index 846250a5fc..597b65ce29 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -28,16 +28,19 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H +#include "py/objtuple.h" #include "common-hal/bleio/Peripheral.h" extern const mp_obj_type_t bleio_peripheral_type; extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name); -extern mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self); +extern mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self); extern bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self); extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self); extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device); extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device); +extern mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist); +extern void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *device); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index db06069913..6961b0b522 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -43,12 +43,16 @@ //| .. class:: Service(uuid, characteristics, *, secondary=False) //| //| Create a new Service object identified by the specified UUID. +//| //| To mark the service as secondary, pass `True` as :py:data:`secondary`. //| //| :param bleio.UUID uuid: The uuid of the service //| :param iterable characteristics: the Characteristic objects for this service //| :param bool secondary: If the service is a secondary one //| +//| A Service may be remote (:py:data:`remote` is ``True``), but a remote Service +//| cannot be constructed directly. It is created by `Central.discover_remote_services()` +//| or `Peripheral.discover_remote_services()`. STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_uuid, ARG_characteristics, ARG_secondary }; @@ -92,6 +96,9 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, // The descriptor base UUID doesn't match the characteristic base UUID. mp_raise_ValueError(translate("Characteristic UUID doesn't match Service UUID")); } + if (common_hal_bleio_characteristic_get_service(characteristic) != MP_OBJ_NULL) { + mp_raise_ValueError(translate("Characteristic is already attached to a Service")); + } mp_obj_list_append(char_list_obj, characteristic_obj); } @@ -119,6 +126,24 @@ const mp_obj_property_t bleio_service_characteristics_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: remote +//| +//| 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); + +const mp_obj_property_t bleio_service_remote_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_remote_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + //| .. attribute:: secondary //| //| True if this is a secondary service. (read-only) diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h index f646c81a9b..716c2e8a96 100644 --- a/shared-bindings/bleio/Service.h +++ b/shared-bindings/bleio/Service.h @@ -35,6 +35,7 @@ const mp_obj_type_t bleio_service_type; extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, mp_obj_list_t *characteristic_list, bool is_secondary); extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self); extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(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_all_characteristics(bleio_service_obj_t *self); diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index ba3bae6c75..739f461a58 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -28,24 +28,30 @@ #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Address.h" +#include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Central.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/CharacteristicBuffer.h" -// #include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -//| :mod:`bleio` --- Bluetooth Low Energy functionality +//| :mod:`bleio` --- Bluetooth Low Energy (BLE) communication //| ================================================================ //| //| .. module:: bleio //| :synopsis: Bluetooth Low Energy functionality //| :platform: nRF //| -//| The `bleio` module contains methods for managing the BLE adapter. +//| The `bleio` module provides necessary low-level functionality for communicating +//| using Bluetooth Low Energy (BLE). We recommend you use `bleio` in conjunction +//| with the `adafruit_ble `_ +//| CircuitPython library, which builds on `bleio`, and +//| provides higher-level convenience functionality, including predefined beacons, clients, +//| servers. //| //| Libraries //| @@ -54,6 +60,7 @@ //| //| Address //| Adapter +//| Attribute //| Central //| Characteristic //| CharacteristicBuffer @@ -72,20 +79,21 @@ //| STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, - { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, - { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, - { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, -// { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, - { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, - { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, - { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, + { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_Attribute), MP_ROM_PTR(&bleio_attribute_type) }, + { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, // Properties - { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, + { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h index 4aa6dd45b7..6a4c804f55 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -29,8 +29,24 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H +#include "py/objlist.h" + +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Adapter.h" + #include "common-hal/bleio/Adapter.h" extern const super_adapter_obj_t common_hal_bleio_adapter_obj; +extern void common_hal_bleio_check_connected(uint16_t conn_handle); + +extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); +extern mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device); +extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); + +extern mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle); +extern void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +extern void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); + + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index af64a20286..0d41359eea 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -119,9 +119,7 @@ STATIC mp_obj_t displayio_fourwire_obj_send(mp_obj_t self, mp_obj_t command_obj, // Wait for display bus to be available. while (!common_hal_displayio_fourwire_begin_transaction(self)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } common_hal_displayio_fourwire_send(self, true, &command, 1); common_hal_displayio_fourwire_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 1f74e8c9ec..9ef989d711 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -111,9 +111,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob // Wait for display bus to be available. while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } uint8_t full_command[bufinfo.len + 1]; full_command[0] = command; diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index 00a96d2301..c29c79fffc 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -122,9 +122,7 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o // Wait for display bus to be available. while (!common_hal_displayio_parallelbus_begin_transaction(self)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } common_hal_displayio_parallelbus_send(self, true, &command, 1); common_hal_displayio_parallelbus_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 6ba4914a02..53fbb51c89 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -131,7 +131,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ 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, + 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); @@ -346,7 +347,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v } 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")); + mp_raise_IndexError(translate("Tile index out of bounds")); } if (value_obj == MP_OBJ_SENTINEL) { @@ -357,7 +358,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v } else { mp_int_t value = mp_obj_get_int(value_obj); if (value < 0 || value > 255) { - mp_raise_ValueError(translate("Tile indices must be 0 - 255")); + mp_raise_ValueError(translate("Tile value out of bounds")); } common_hal_displayio_tilegrid_set_tile(self, x, y, value); } diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h index 1f9995a949..8227abfd37 100644 --- a/shared-bindings/displayio/TileGrid.h +++ b/shared-bindings/displayio/TileGrid.h @@ -32,7 +32,8 @@ 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, mp_obj_t pixel_shader, uint16_t width, uint16_t height, + 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); mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self); diff --git a/shared-bindings/i2cslave/I2CSlave.c b/shared-bindings/i2cslave/I2CSlave.c index 2598accbb4..c98ea52e06 100644 --- a/shared-bindings/i2cslave/I2CSlave.c +++ b/shared-bindings/i2cslave/I2CSlave.c @@ -182,7 +182,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request(size_t n_args, const mp_obj_t *pos_ar bool is_read; bool is_restart; - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { return mp_const_none; } @@ -337,7 +337,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request_read(size_t n_args, const mp_obj_t *p uint8_t *buffer = NULL; uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000; while (common_hal_time_monotonic() < timeout_end) { - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { break; } @@ -382,7 +382,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request_write(mp_obj_t self_in, mp_obj_t buf_ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); for (size_t i = 0; i < bufinfo.len; i++) { - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { break; } diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 70c01c2d83..2654de09aa 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -99,16 +99,17 @@ mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp //| //| Structure used to capture a date and time. Note that it takes a tuple! //| -//| :param Tuple[tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst] time_tuple: Tuple of time info. -//| * the year, 2017 for example -//| * the month, range [1, 12] -//| * the day of the month, range [1, 31] -//| * the hour, range [0, 23] -//| * the minute, range [0, 59] -//| * the second, range [0, 61] -//| * the day of the week, range [0, 6], Monday is 0 -//| * the day of the year, range [1, 366], -1 indicates not known -//| * 1 when in daylight savings, 0 when not, -1 if unknown. +//| :param tuple time_tuple: Tuple of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)`` +//| +//| * ``tm_year``: the year, 2017 for example +//| * ``tm_month``: the month, range [1, 12] +//| * ``tm_mday``: the day of the month, range [1, 31] +//| * ``tm_hour``: the hour, range [0, 23] +//| * ``tm_minute``: 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 = { @@ -235,9 +236,16 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { return rtc_get_time_source_time(); } - mp_int_t secs = mp_obj_int_get_checked(args[0]); - if (secs < EPOCH1970_EPOCH2000_DIFF_SECS) + 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 (secs < EPOCH1970_EPOCH2000_DIFF_SECS) { 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); @@ -269,8 +277,9 @@ STATIC mp_obj_t time_mktime(mp_obj_t t) { mp_raise_TypeError(translate("function takes exactly 9 arguments")); } - if (mp_obj_get_int(elem[0]) < 2000) + 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])); diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 1af279e92b..ca71b758e6 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -34,30 +34,35 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display) { + displayio_display_obj_t *display, uint8_t scale) { size_t index = 0; for (uint16_t y = y0; y < y1; ++y) { - for (uint16_t x = x0; x < x1; ++x) { - for (size_t layer = 0; layer < layers_size; ++layer) { + for (uint8_t yscale = 0; yscale < scale; ++yscale) { + for (uint16_t x = x0; x < x1; ++x) { uint16_t c = TRANSPARENT; - layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); - if (obj->base.type == &mp_type_layer) { - c = get_layer_pixel(obj, x, y); - } else if (obj->base.type == &mp_type_text) { - c = get_text_pixel((text_obj_t *)obj, x, y); + for (size_t layer = 0; layer < layers_size; ++layer) { + layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); + if (obj->base.type == &mp_type_layer) { + c = get_layer_pixel(obj, x, y); + } else if (obj->base.type == &mp_type_text) { + c = get_text_pixel((text_obj_t *)obj, x, y); + } + if (c != TRANSPARENT) { + break; + } } - if (c != TRANSPARENT) { + for (uint8_t xscale = 0; xscale < scale; ++xscale) { buffer[index] = c; - break; + index += 1; + // The buffer is full, send it. + if (index >= buffer_size) { + display->send(display->bus, false, ((uint8_t*)buffer), + buffer_size * 2); + index = 0; + } } } - index += 1; - // The buffer is full, send it. - if (index >= buffer_size) { - display->send(display->bus, false, ((uint8_t*)buffer), buffer_size * 2); - index = 0; - } } } // Send the remaining data. diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h index d263302b48..5af2124aeb 100644 --- a/shared-module/_stage/__init__.h +++ b/shared-module/_stage/__init__.h @@ -37,6 +37,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display); + displayio_display_obj_t *display, uint8_t scale); #endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index 810d9c33b4..df5d4b61de 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -46,7 +46,9 @@ struct wave_format_chunk { }; void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, - pyb_file_obj_t* file) { + pyb_file_obj_t* file, + uint8_t *buffer, + size_t buffer_size) { // Load the wave self->file = file; uint8_t chunk_header[16]; @@ -84,7 +86,6 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, } // Get the sample_rate self->sample_rate = format.sample_rate; - self->len = 256; self->channel_count = format.num_channels; self->bits_per_sample = format.bits_per_sample; @@ -111,21 +112,31 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, // Try to allocate two buffers, one will be loaded from file and the other // DMAed to DAC. - self->buffer = m_malloc(self->len, false); - if (self->buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } + if (buffer_size) { + self->len = buffer_size / 2; + self->buffer = buffer; + self->second_buffer = buffer + self->len; + } else { + self->len = 256; + self->buffer = m_malloc(self->len, false); + if (self->buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate first buffer")); + } - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate second buffer")); + } } } void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self) { self->buffer = NULL; + self->second_buffer = NULL; } bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self) { diff --git a/shared-module/audiocore/WaveFile.h b/shared-module/audiocore/WaveFile.h index 97dd6a46f2..3eecbf15ce 100644 --- a/shared-module/audiocore/WaveFile.h +++ b/shared-module/audiocore/WaveFile.h @@ -27,6 +27,7 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H +#include "extmod/vfs_fat.h" #include "py/obj.h" #include "shared-module/audiocore/__init__.h" diff --git a/shared-module/audiopwmio/__init__.c b/shared-module/audiopwmio/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/bleio/__init__.h b/shared-module/audiopwmio/__init__.h similarity index 81% rename from shared-module/bleio/__init__.h rename to shared-module/audiopwmio/__init__.h index 07d1485946..964e4aafe2 100644 --- a/shared-module/bleio/__init__.h +++ b/shared-module/audiopwmio/__init__.h @@ -24,15 +24,9 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H -typedef enum { - GATT_ROLE_NONE, - GATT_ROLE_SERVER, - GATT_ROLE_CLIENT, -} gatt_role_t; +#include "shared-module/audiocore/__init__.h" -extern void bleio_reset(void); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c new file mode 100644 index 0000000000..2275003c93 --- /dev/null +++ b/shared-module/bleio/Attribute.c @@ -0,0 +1,46 @@ +/* + * 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 + +#include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" + +void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SECURITY_MODE_NO_ACCESS: + case SECURITY_MODE_OPEN: + case SECURITY_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: + break; + default: + mp_raise_ValueError(translate("Invalid security_mode")); + break; + } +} diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h new file mode 100644 index 0000000000..a498a14a51 --- /dev/null +++ b/shared-module/bleio/Attribute.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 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION 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_MODULE_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H + +// BLE security modes: 0x +typedef enum { + SECURITY_MODE_NO_ACCESS = 0x00, + SECURITY_MODE_OPEN = 0x11, + SECURITY_MODE_ENC_NO_MITM = 0x21, + SECURITY_MODE_ENC_WITH_MITM = 0x31, + SECURITY_MODE_LESC_ENC_WITH_MITM = 0x41, + SECURITY_MODE_SIGNED_NO_MITM = 0x12, + SECURITY_MODE_SIGNED_WITH_MITM = 0x22, +} bleio_attribute_security_mode_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index 27b43588fa..409a57c76e 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -27,14 +27,17 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -// Flags for each characteristic property. Common across ports. -typedef struct { - bool broadcast : 1; - bool read : 1; - bool write_no_response : 1; - bool write : 1; - bool notify : 1; - bool indicate : 1; -} bleio_characteristic_properties_t; +typedef enum { + CHAR_PROP_NONE = 0, + CHAR_PROP_BROADCAST = 1u << 0, + CHAR_PROP_INDICATE = 1u << 1, + CHAR_PROP_NOTIFY = 1u << 2, + CHAR_PROP_READ = 1u << 3, + CHAR_PROP_WRITE = 1u << 4, + CHAR_PROP_WRITE_NO_RESPONSE = 1u << 5, + CHAR_PROP_ALL = (CHAR_PROP_BROADCAST | CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY | + CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE) +} bleio_characteristic_properties_enum_t; +typedef uint8_t bleio_characteristic_properties_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 5a1dead784..dd07d7190c 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -40,17 +40,25 @@ #endif #if BOARD_I2C +// Statically allocate the I2C object so it can live past the end of the heap and into the next VM. +// That way it can be used by built-in I2CDisplay displays and be accessible through board.I2C(). +STATIC busio_i2c_obj_t i2c_obj; +STATIC mp_obj_t i2c_singleton = NULL; + mp_obj_t common_hal_board_get_i2c(void) { - return MP_STATE_VM(shared_i2c_bus); + return i2c_singleton; } mp_obj_t common_hal_board_create_i2c(void) { - busio_i2c_obj_t *self = m_new_ll_obj(busio_i2c_obj_t); + if (i2c_singleton != NULL) { + return i2c_singleton; + } + busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); - MP_STATE_VM(shared_i2c_bus) = MP_OBJ_FROM_PTR(self); - return MP_STATE_VM(shared_i2c_bus); + i2c_singleton = (mp_obj_t)self; + return i2c_singleton; } #endif @@ -101,7 +109,18 @@ mp_obj_t common_hal_board_create_uart(void) { void reset_board_busses(void) { #if BOARD_I2C - MP_STATE_VM(shared_i2c_bus) = NULL; + bool display_using_i2c = false; + #if CIRCUITPY_DISPLAYIO + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].i2cdisplay_bus.bus == i2c_singleton) { + display_using_i2c = true; + break; + } + } + #endif + if (!display_using_i2c) { + i2c_singleton = NULL; + } #endif #if BOARD_SPI bool display_using_spi = false; diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index f8dc24c15e..59971d25cc 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -63,6 +63,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi } self->x_mask = (1 << self->x_shift) - 1; // Used as a modulus on the x value self->bitmask = (1 << bits_per_value) - 1; + + self->dirty_area.x1 = 0; + self->dirty_area.x2 = width; + self->dirty_area.y1 = 0; + self->dirty_area.y2 = height; } uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self) { @@ -104,6 +109,26 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); } + // Update the dirty area. + if (self->dirty_area.x1 == self->dirty_area.x2) { + self->dirty_area.x1 = x; + self->dirty_area.x2 = x + 1; + self->dirty_area.y1 = y; + self->dirty_area.y2 = y + 1; + } else { + if (x < self->dirty_area.x1) { + self->dirty_area.x1 = x; + } else if (x >= self->dirty_area.x2) { + self->dirty_area.x2 = x + 1; + } + if (y < self->dirty_area.y1) { + self->dirty_area.y1 = y; + } else if (y >= self->dirty_area.y2) { + self->dirty_area.y2 = y + 1; + } + } + + // Update our data int32_t row_start = y * self->stride; uint32_t bytes_per_value = self->bits_per_value / 8; if (bytes_per_value < 1) { @@ -124,3 +149,16 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, } } } + +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail) { + if (self->dirty_area.x1 == self->dirty_area.x2) { + return tail; + } + self->dirty_area.next = tail; + return &self->dirty_area; +} + +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self) { + self->dirty_area.x1 = 0; + self->dirty_area.x2 = 0; +} diff --git a/shared-module/displayio/Bitmap.h b/shared-module/displayio/Bitmap.h index 48ca9e2cf6..f4bd7ce4d3 100644 --- a/shared-module/displayio/Bitmap.h +++ b/shared-module/displayio/Bitmap.h @@ -31,6 +31,7 @@ #include #include "py/obj.h" +#include "shared-module/displayio/area.h" typedef struct { mp_obj_base_t base; @@ -41,8 +42,12 @@ typedef struct { uint8_t bits_per_value; uint8_t x_shift; size_t x_mask; + displayio_area_t dirty_area; uint16_t bitmask; bool read_only; } displayio_bitmap_t; +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self); +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 1d80145756..d11813b8c5 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -85,9 +85,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint32_t i = 0; while (!self->begin_transaction(self->bus)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; @@ -199,19 +197,26 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { if (root_group == NULL) { - root_group = &circuitpython_splash; + if (!circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } else if (self->current_group == &circuitpython_splash) { + return false; + } } if (root_group == self->current_group) { return true; } - if (root_group->in_group) { + if (root_group != NULL && root_group->in_group) { return false; } if (self->current_group != NULL) { self->current_group->in_group = false; } - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; + + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + } self->current_group = root_group; self->full_refresh = true; common_hal_displayio_display_refresh_soon(self); @@ -235,7 +240,7 @@ int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* sel uint64_t last_refresh = self->last_refresh; // Don't try to refresh if we got an exception. while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; } return 0; } @@ -406,6 +411,10 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { } void release_display(displayio_display_obj_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index fee2ae9781..6144f8f994 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -26,6 +26,7 @@ #include "shared-bindings/displayio/TileGrid.h" +#include "py/runtime.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/OnDiskBitmap.h" @@ -33,7 +34,7 @@ #include "shared-bindings/displayio/Shape.h" void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, - uint16_t bitmap_width_in_tiles, + 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) { uint32_t total_tiles = width * height; @@ -54,6 +55,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ self->inline_tiles = false; } self->bitmap_width_in_tiles = bitmap_width_in_tiles; + self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles; self->width_in_tiles = width; self->height_in_tiles = height; self->x = x; @@ -204,6 +206,9 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1 } void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) { + if (tile_index >= self->tiles_in_bitmap) { + mp_raise_ValueError(translate("Tile value out of bounds")); + } uint8_t* tiles = self->tiles; if (self->inline_tiles) { tiles = (uint8_t*) &self->tiles; @@ -462,6 +467,14 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_finish_refresh(self->pixel_shader); } + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_bitmap_finish_refresh(self->bitmap); + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + // TODO: Support shape changes. + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { + // OnDiskBitmap changes will trigger a complete reload so no need to + // track changes. + } // TODO(tannewt): We could double buffer changes to position and move them over here. // That way they won't change during a refresh and tear. } @@ -478,8 +491,21 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel return &self->current_area; } - // We must recheck if our sources require a refresh because needs_refresh may or may not have - // been called. + // If we have an in-memory bitmap, then check it for modifications. + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); + if (refresh_area != tail) { + // Special case a TileGrid that shows a full bitmap and use its + // dirty area. Copy it to ours so we can transform it. + if (self->tiles_in_bitmap == 1) { + displayio_area_copy(refresh_area, &self->dirty_area); + self->partial_change = true; + } else { + self->full_change = true; + } + } + } + self->full_change = self->full_change || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index fb6033e9c7..222aaed19b 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -42,7 +42,8 @@ typedef struct { int16_t y; uint16_t pixel_width; uint16_t pixel_height; - uint16_t bitmap_width_in_tiles; + uint16_t bitmap_width_in_tiles;; + uint8_t tiles_in_bitmap; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t tile_width; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 8f6e650a1a..3e9c4aa2a1 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -163,7 +163,7 @@ void displayio_refresh_displays(void) { void common_hal_displayio_release_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; - if (bus_type == NULL) { + if (bus_type == NULL || bus_type == &mp_type_NoneType) { continue; } else if (bus_type == &displayio_fourwire_type) { common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); @@ -235,12 +235,14 @@ void reset_displays(void) { // Not an active display. continue; } + } + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { // Reset the displayed group. Only the first will get the terminal but // that's ok. displayio_display_obj_t* display = &displays[i].display; display->auto_brightness = true; - common_hal_displayio_display_show(display, &circuitpython_splash); + common_hal_displayio_display_show(display, NULL); } } diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 86c3e903e1..df92a5dc48 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -36,6 +36,12 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d self->tilegrid = tilegrid; self->first_row = 0; + for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) { + for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) { + common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0); + } + } + common_hal_displayio_tilegrid_set_top_left(self->tilegrid, 0, 1); } diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index a5a57419c7..26d70cb822 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,7 +47,11 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; - while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { } + while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP; +#endif + } if ( !tud_hid_ready() ) { mp_raise_msg(&mp_type_OSError, translate("USB Busy")); diff --git a/supervisor/shared/display.h b/supervisor/shared/display.h index d5faa7777d..2a2ccf46df 100644 --- a/supervisor/shared/display.h +++ b/supervisor/shared/display.h @@ -35,11 +35,10 @@ // These are autogenerated resources. // This is fixed so it doesn't need to be in RAM. -extern const displayio_bitmap_t supervisor_terminal_font_bitmap; - extern const fontio_builtinfont_t supervisor_terminal_font; // These will change so they must live in RAM. +extern displayio_bitmap_t supervisor_terminal_font_bitmap; extern displayio_tilegrid_t supervisor_terminal_text_grid; extern terminalio_terminal_obj_t supervisor_terminal; diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index 0678a3a3fc..c1d70c5b0f 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -25,6 +25,7 @@ */ #include "tick.h" +#include "py/objstr.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-module/usb_midi/__init__.h" #include "supervisor/port.h" @@ -43,13 +44,11 @@ void load_serial_number(void) { uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH]; common_hal_mcu_processor_get_uid(raw_id); - static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F'}; for (int i = 0; i < COMMON_HAL_MCU_PROCESSOR_UID_LENGTH; i++) { for (int j = 0; j < 2; j++) { uint8_t nibble = (raw_id[i] >> (j * 4)) & 0xf; // Strings are UTF-16-LE encoded. - usb_serial_number[1 + i * 2 + j] = nibble_to_hex[nibble]; + usb_serial_number[1 + i * 2 + j] = nibble_to_hex_upper[nibble]; } } } diff --git a/tools/check_translations.py b/tools/check_translations.py index 4bea040bfe..7c008d3da7 100644 --- a/tools/check_translations.py +++ b/tools/check_translations.py @@ -16,8 +16,10 @@ for po_filename in po_filenames: po_file = polib.pofile(po_filename) po_ids = set([x.msgid for x in po_file]) - if all_ids - po_ids: + missing = all_ids - po_ids + if missing: print("Missing message id. Please run `make translate`") + print(missing) sys.exit(-1) else: print("ok") diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index a731cbd9cb..0f6b9014b7 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -129,6 +129,7 @@ displayio_tilegrid_t supervisor_terminal_text_grid = {{ .pixel_width = {1}, .pixel_height = {2}, .bitmap_width_in_tiles = {0}, + .tiles_in_bitmap = {0}, .width_in_tiles = 1, .height_in_tiles = 1, .tile_width = {1}, @@ -157,7 +158,7 @@ c_file.write("""\ """) c_file.write("""\ -const displayio_bitmap_t supervisor_terminal_font_bitmap = {{ +displayio_bitmap_t supervisor_terminal_font_bitmap = {{ .base = {{.type = &displayio_bitmap_type }}, .width = {}, .height = {},