From e09a771ab22752982c45007105d6cb98b987c3f1 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 24 May 2021 22:32:57 +0200 Subject: [PATCH 01/38] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/ID.po | 8 ++++---- locale/cs.po | 8 ++++---- locale/de_DE.po | 8 ++++---- locale/el.po | 8 ++++---- locale/en_GB.po | 8 ++++---- locale/es.po | 11 +++++++---- locale/fil.po | 8 ++++---- locale/fr.po | 8 ++++---- locale/hi.po | 8 ++++---- locale/it_IT.po | 8 ++++---- locale/ja.po | 8 ++++---- locale/ko.po | 8 ++++---- locale/nl.po | 8 ++++---- locale/pl.po | 8 ++++---- locale/pt_BR.po | 11 +++++++---- locale/sv.po | 11 +++++++---- locale/zh_Latn_pinyin.po | 8 ++++---- 17 files changed, 77 insertions(+), 68 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index be0217bf96..f0e702b7f0 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -1695,6 +1695,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1718,10 +1722,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/cs.po b/locale/cs.po index de6f46f646..aebc210b81 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1675,6 +1675,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1696,10 +1700,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index aff8c71509..12a9112722 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -1697,6 +1697,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1720,10 +1724,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/el.po b/locale/el.po index f933431230..3430bb0078 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1672,6 +1672,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1693,10 +1697,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/en_GB.po b/locale/en_GB.po index 0e28dad664..0b9eb660c3 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -1689,6 +1689,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1712,10 +1716,6 @@ msgstr "Only one alarm.time alarm can be set." msgid "Only one color can be transparent at a time" msgstr "Only one colour can be transparent at a time" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "Operation or feature not supported" diff --git a/locale/es.po b/locale/es.po index 7f0fe6f404..e3afeae954 100644 --- a/locale/es.po +++ b/locale/es.po @@ -1713,6 +1713,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "Este hardware solo tiene capacidad para detección de borde" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1736,10 +1740,6 @@ msgstr "Solamente una alarm.time puede ser configurada." msgid "Only one color can be transparent at a time" msgstr "Solo un color puede ser transparente a la vez" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "Para ip solo puede con un entero o una cadena" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "Operación no característica no soportada" @@ -4448,6 +4448,9 @@ msgstr "zi debe ser de tipo flotante" msgid "zi must be of shape (n_section, 2)" msgstr "zi debe ser una forma (n_section,2)" +#~ msgid "Only raw int or string supported for ip" +#~ msgstr "Para ip solo puede con un entero o una cadena" + #~ msgid "Only raw int supported for ip" #~ msgstr "Solo se aceptan enteros crudos para ip" diff --git a/locale/fil.po b/locale/fil.po index f9d4beada0..ca689b783e 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -1690,6 +1690,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1711,10 +1715,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/fr.po b/locale/fr.po index c70841c30a..a55d920693 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -1721,6 +1721,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1744,10 +1748,6 @@ msgstr "Seulement une alarme alarm.time peut être réglée." msgid "Only one color can be transparent at a time" msgstr "Une seule couleur peut être transparente à la fois" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "Opération ou fonction non supportée" diff --git a/locale/hi.po b/locale/hi.po index 7dd917e051..ecb7d2d8cc 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1672,6 +1672,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1693,10 +1697,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/it_IT.po b/locale/it_IT.po index 1cfd7b4063..4b58d8d02e 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -1704,6 +1704,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1725,10 +1729,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/ja.po b/locale/ja.po index 0470193ef3..aa9b79ea5b 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -1685,6 +1685,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1706,10 +1710,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index f2091b7fa7..82d4928e9f 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1675,6 +1675,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1696,10 +1700,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/nl.po b/locale/nl.po index df9dc35e11..8ba8094d45 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -1688,6 +1688,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1711,10 +1715,6 @@ msgstr "Slechts één alarm.time alarm kan worden ingesteld." msgid "Only one color can be transparent at a time" msgstr "Er kan maar één kleur per keer transparant zijn" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/pl.po b/locale/pl.po index f23aff57e0..5497efcba3 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -1683,6 +1683,10 @@ msgstr "Wspierane są tylko nieskompresowane pliki BMP: wielkość nagłówka %d msgid "Only edge detection is available on this hardware" msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1704,10 +1708,6 @@ msgstr "" msgid "Only one color can be transparent at a time" msgstr "W danym momencie przezroczysty może być tylko jeden kolor" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 5f1fb323c7..e233ef3479 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -1711,6 +1711,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "Apenas a detecção de borda está disponível neste hardware" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1734,10 +1738,6 @@ msgstr "Apenas um alarme alarm.time pode ser definido." msgid "Only one color can be transparent at a time" msgstr "Apenas uma cor pode ser transparente de cada vez" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "Apenas int ou string bruto é compatível para o ip" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "A operação ou o recurso não é suportado" @@ -4458,6 +4458,9 @@ msgstr "zi deve ser de um tipo float" msgid "zi must be of shape (n_section, 2)" msgstr "zi deve estar na forma (n_section, 2)" +#~ msgid "Only raw int or string supported for ip" +#~ msgstr "Apenas int ou string bruto é compatível para o ip" + #~ msgid "Only raw int supported for ip" #~ msgstr "Apenas o int bruto é compatível para o ip" diff --git a/locale/sv.po b/locale/sv.po index fade5b27a0..a228a6cf11 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -1695,6 +1695,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "Endast kantdetektering är tillgänglig för denna hårdvara" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1718,10 +1722,6 @@ msgstr "Endast ett alarm.time kan ställas in." msgid "Only one color can be transparent at a time" msgstr "Bara en färg kan vara genomskinlig i taget" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "Enbart int eller string stöds för ip" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "Operation eller funktion stöds inte" @@ -4417,6 +4417,9 @@ msgstr "zi måste vara av typ float" msgid "zi must be of shape (n_section, 2)" msgstr "zi måste vara i formen (n_section, 2)" +#~ msgid "Only raw int or string supported for ip" +#~ msgstr "Enbart int eller string stöds för ip" + #~ msgid "Only raw int supported for ip" #~ msgstr "Endast raw int stöds för ip" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 39a40c077d..1ed603ae85 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -1698,6 +1698,10 @@ msgstr "" msgid "Only edge detection is available on this hardware" msgstr "cǐ yìng jiàn shàng jǐn tí gòng biān yuán jiǎn cè" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + #: shared-module/displayio/OnDiskBitmap.c #, c-format msgid "" @@ -1721,10 +1725,6 @@ msgstr "zhǐ néng shè zhì yí gè bào jǐng." msgid "Only one color can be transparent at a time" msgstr "Yīcì zhǐ néng yǒuyī zhǒng yánsè shì tòumíng de" -#: shared-bindings/ipaddress/__init__.c -msgid "Only raw int or string supported for ip" -msgstr "" - #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c msgid "Operation or feature not supported" msgstr "bù zhī chí cāo zuò huò gōng néng" From b8132c5c07e19b1b2227a9f0e6c564eef9cbc9a5 Mon Sep 17 00:00:00 2001 From: Jose David M Date: Mon, 24 May 2021 20:53:55 +0000 Subject: [PATCH 02/38] Translated using Weblate (Spanish) Currently translated at 100.0% (993 of 993 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/es/ --- locale/es.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locale/es.po b/locale/es.po index e3afeae954..fb4c3f5e96 100644 --- a/locale/es.po +++ b/locale/es.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2021-05-22 17:58+0000\n" -"Last-Translator: Alvaro Figueroa \n" +"PO-Revision-Date: 2021-05-24 21:25+0000\n" +"Last-Translator: Jose David M \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" @@ -1715,7 +1715,7 @@ msgstr "Este hardware solo tiene capacidad para detección de borde" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "Solamente int or string son permitados para una ip" #: shared-module/displayio/OnDiskBitmap.c #, c-format From 3b11e6f194d758f10dd7b9fb52d29554182d2c75 Mon Sep 17 00:00:00 2001 From: Jonny Bergdahl Date: Mon, 24 May 2021 20:44:15 +0000 Subject: [PATCH 03/38] Translated using Weblate (Swedish) Currently translated at 100.0% (993 of 993 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/sv/ --- locale/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/sv.po b/locale/sv.po index a228a6cf11..f38f7240af 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2021-05-22 17:58+0000\n" +"PO-Revision-Date: 2021-05-24 21:25+0000\n" "Last-Translator: Jonny Bergdahl \n" "Language-Team: LANGUAGE \n" "Language: sv\n" @@ -1697,7 +1697,7 @@ msgstr "Endast kantdetektering är tillgänglig för denna hårdvara" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "Endast int eller string stöds för ip" #: shared-module/displayio/OnDiskBitmap.c #, c-format From dd3e129802783db3697724e627cf2327eaba2be4 Mon Sep 17 00:00:00 2001 From: Wellington Terumi Uemura Date: Tue, 25 May 2021 12:30:27 +0000 Subject: [PATCH 04/38] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (993 of 993 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/ --- locale/pt_BR.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/pt_BR.po b/locale/pt_BR.po index e233ef3479..14baa40edf 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2021-05-22 17:58+0000\n" +"PO-Revision-Date: 2021-05-25 17:41+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" "Language: pt_BR\n" @@ -1713,7 +1713,7 @@ msgstr "Apenas a detecção de borda está disponível neste hardware" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "Apenas int ou string é suportado para ip" #: shared-module/displayio/OnDiskBitmap.c #, c-format From a7ce8439207540c4e219a581bd0190e5b34cb73c Mon Sep 17 00:00:00 2001 From: hexthat Date: Mon, 24 May 2021 22:05:13 +0000 Subject: [PATCH 05/38] Translated using Weblate (Chinese (Pinyin)) Currently translated at 100.0% (993 of 993 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/zh_Latn/ --- locale/zh_Latn_pinyin.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 1ed603ae85..0f54ddec98 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2021-05-21 17:47+0000\n" +"PO-Revision-Date: 2021-05-25 17:41+0000\n" "Last-Translator: hexthat \n" "Language-Team: Chinese Hanyu Pinyin\n" "Language: zh_Latn_pinyin\n" @@ -1700,7 +1700,7 @@ msgstr "cǐ yìng jiàn shàng jǐn tí gòng biān yuán jiǎn cè" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "jǐn zhī chí IP de zhěng shù huò zì fú chuàn" #: shared-module/displayio/OnDiskBitmap.c #, c-format From 51fc9027eb9c1f5365450f86b72ebc02e6180204 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 26 May 2021 16:01:17 -0400 Subject: [PATCH 06/38] Remove non-product Adafruit boards --- .github/workflows/build.yml | 3 - ports/atmel-samd/boards/pirkey_m0/board.c | 37 ------ .../boards/pirkey_m0/mpconfigboard.h | 58 ---------- .../boards/pirkey_m0/mpconfigboard.mk | 28 ----- ports/atmel-samd/boards/pirkey_m0/pins.c | 11 -- .../atmel-samd/boards/pybadge_airlift/board.c | 105 ------------------ .../boards/pybadge_airlift/mpconfigboard.h | 26 ----- .../boards/pybadge_airlift/mpconfigboard.mk | 17 --- .../atmel-samd/boards/pybadge_airlift/pins.c | 75 ------------- .../atmel-samd/boards/pygamer_advance/board.c | 105 ------------------ .../boards/pygamer_advance/mpconfigboard.h | 28 ----- .../boards/pygamer_advance/mpconfigboard.mk | 17 --- .../atmel-samd/boards/pygamer_advance/pins.c | 77 ------------- 13 files changed, 587 deletions(-) delete mode 100644 ports/atmel-samd/boards/pirkey_m0/board.c delete mode 100644 ports/atmel-samd/boards/pirkey_m0/mpconfigboard.h delete mode 100644 ports/atmel-samd/boards/pirkey_m0/mpconfigboard.mk delete mode 100644 ports/atmel-samd/boards/pirkey_m0/pins.c delete mode 100644 ports/atmel-samd/boards/pybadge_airlift/board.c delete mode 100644 ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.h delete mode 100644 ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk delete mode 100644 ports/atmel-samd/boards/pybadge_airlift/pins.c delete mode 100644 ports/atmel-samd/boards/pygamer_advance/board.c delete mode 100644 ports/atmel-samd/boards/pygamer_advance/mpconfigboard.h delete mode 100644 ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk delete mode 100644 ports/atmel-samd/boards/pygamer_advance/pins.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 165bb43e23..0b23f4538e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -295,16 +295,13 @@ jobs: - "pimoroni_picolipo_4mb" - "pimoroni_picosystem" - "pimoroni_tiny2040" - - "pirkey_m0" - "pitaya_go" - "pyb_nano_v2" - "pybadge" - - "pybadge_airlift" - "pyboard_v11" - "pycubed" - "pycubed_mram" - "pygamer" - - "pygamer_advance" - "pyportal" - "pyportal_titano" - "pyruler" diff --git a/ports/atmel-samd/boards/pirkey_m0/board.c b/ports/atmel-samd/boards/pirkey_m0/board.c deleted file mode 100644 index 84960e73cf..0000000000 --- a/ports/atmel-samd/boards/pirkey_m0/board.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "supervisor/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/pirkey_m0/mpconfigboard.h b/ports/atmel-samd/boards/pirkey_m0/mpconfigboard.h deleted file mode 100644 index 866e21991b..0000000000 --- a/ports/atmel-samd/boards/pirkey_m0/mpconfigboard.h +++ /dev/null @@ -1,58 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "Adafruit pIRKey M0" -#define MICROPY_HW_MCU_NAME "samd21e18" - -#define MICROPY_HW_APA102_MOSI (&pin_PA00) -#define MICROPY_HW_APA102_SCK (&pin_PA01) - -#define MICROPY_PORT_A (PORT_PA00 | PORT_PA01 | PORT_PA24 | PORT_PA25) -#define MICROPY_PORT_B (0) -#define MICROPY_PORT_C (0) - -#define IGNORE_PIN_PA02 1 -#define IGNORE_PIN_PA03 1 -#define IGNORE_PIN_PA04 1 -#define IGNORE_PIN_PA05 1 -#define IGNORE_PIN_PA06 1 -#define IGNORE_PIN_PA07 1 -#define IGNORE_PIN_PA08 1 -#define IGNORE_PIN_PA09 1 -#define IGNORE_PIN_PA10 1 -#define IGNORE_PIN_PA11 1 -#define IGNORE_PIN_PA12 1 -#define IGNORE_PIN_PA13 1 -#define IGNORE_PIN_PA14 1 -#define IGNORE_PIN_PA15 1 -#define IGNORE_PIN_PA16 1 -#define IGNORE_PIN_PA17 1 -#define IGNORE_PIN_PA18 1 -#define IGNORE_PIN_PA19 1 -#define IGNORE_PIN_PA20 1 -#define IGNORE_PIN_PA21 1 -#define IGNORE_PIN_PA22 1 -#define IGNORE_PIN_PA24 1 -#define IGNORE_PIN_PA25 1 -#define IGNORE_PIN_PA27 1 -#define IGNORE_PIN_PA30 1 -#define IGNORE_PIN_PA31 1 -#define IGNORE_PIN_PB00 1 -#define IGNORE_PIN_PB01 1 -#define IGNORE_PIN_PB02 1 -#define IGNORE_PIN_PB03 1 -#define IGNORE_PIN_PB04 1 -#define IGNORE_PIN_PB05 1 -#define IGNORE_PIN_PB06 1 -#define IGNORE_PIN_PB07 1 -#define IGNORE_PIN_PB08 1 -#define IGNORE_PIN_PB09 1 -#define IGNORE_PIN_PB10 1 -#define IGNORE_PIN_PB11 1 -#define IGNORE_PIN_PB12 1 -#define IGNORE_PIN_PB13 1 -#define IGNORE_PIN_PB14 1 -#define IGNORE_PIN_PB15 1 -#define IGNORE_PIN_PB16 1 -#define IGNORE_PIN_PB17 1 -#define IGNORE_PIN_PB22 1 -#define IGNORE_PIN_PB23 1 -#define IGNORE_PIN_PB30 1 -#define IGNORE_PIN_PB31 1 diff --git a/ports/atmel-samd/boards/pirkey_m0/mpconfigboard.mk b/ports/atmel-samd/boards/pirkey_m0/mpconfigboard.mk deleted file mode 100644 index ebbd1b601b..0000000000 --- a/ports/atmel-samd/boards/pirkey_m0/mpconfigboard.mk +++ /dev/null @@ -1,28 +0,0 @@ -USB_VID = 0x239A -USB_PID = 0x8028 -USB_PRODUCT = "pIRKey M0" -USB_MANUFACTURER = "Adafruit Industries LLC" - -CHIP_VARIANT = SAMD21E18A -CHIP_FAMILY = samd21 - -INTERNAL_FLASH_FILESYSTEM = 1 -LONGINT_IMPL = NONE -CIRCUITPY_FULL_BUILD = 0 - -# A number of modules are removed for pIRKey to make room for frozen libraries. -# Many I/O functions are not available. -# math is very large and is also removed. -CIRCUITPY_ANALOGIO = 0 -CIRCUITPY_MATH = 0 -CIRCUITPY_NEOPIXEL_WRITE = 0 -CIRCUITPY_PULSEIO = 1 -CIRCUITPY_ROTARYIO = 0 -CIRCUITPY_RTC = 0 -CIRCUITPY_USB_MIDI = 1 -CIRCUITPY_TOUCHIO = 0 - -# Include these Python libraries in firmware. -# FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DotStar -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_IRRemote diff --git a/ports/atmel-samd/boards/pirkey_m0/pins.c b/ports/atmel-samd/boards/pirkey_m0/pins.c deleted file mode 100644 index 74e135827e..0000000000 --- a/ports/atmel-samd/boards/pirkey_m0/pins.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "shared-bindings/board/__init__.h" - -STATIC const mp_rom_map_elem_t board_global_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_REMOTEIN), MP_ROM_PTR(&pin_PA28) }, - - { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_PA00) }, - { MP_ROM_QSTR(MP_QSTR_DOTSTAR_DATA), MP_ROM_PTR(&pin_PA00) }, - { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_PA01) }, - { MP_ROM_QSTR(MP_QSTR_DOTSTAR_CLOCK), MP_ROM_PTR(&pin_PA01) }, -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c deleted file mode 100644 index fe3549a64a..0000000000 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 "supervisor/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 "supervisor/shared/board.h" - -displayio_fourwire_obj_t board_display_obj; - -#define DELAY 0x80 - -uint8_t display_init_sequence[] = { - 0x01, 0 | DELAY, 150, // SWRESET - 0x11, 0 | DELAY, 255, // SLPOUT - 0x36, 1, 0x08, // _MADCTL bottom to top refresh in vsync aligned order. - 0x3a, 1, 0x55, // COLMOD - 16bit color - 0x21, 0 | DELAY, 10, // _INVON - 0x13, 0 | DELAY, 10, // _NORON - 0x29, 0 | DELAY, 255, // _DISPON -}; - -void board_init(void) { - busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus; - common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL); - 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_PB07, // TFT_RST Reset - 60000000, // Baudrate - 0, // Polarity - 0); // Phase - - displayio_display_obj_t *display = &displays[0].display; - display->base.type = &displayio_display_type; - common_hal_displayio_display_construct(display, - bus, - 320, // Width (after rotation) - 240, // Height (after rotation) - 0, // column start - 0, // row start - 90, // rotation - 16, // Color depth - false, // grayscale - false, // pixels in byte share row. Only used for depth < 8 - 1, // bytes per cell. Only valid for depths < 8 - false, // reverse_pixels_in_byte. Only valid for depths < 8 - true, // reverse_pixels_in_word - 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_PA01, // backlight pin - NO_BRIGHTNESS_COMMAND, - 1.0f, // brightness (ignored) - true, // auto_brightness - false, // single_byte_bounds - false, // data_as_commands - true, // auto_refresh - 60, // native_frames_per_second - true, // backlight_on_high - false); // SH1107_addressing -} - -bool board_requests_safe_mode(void) { - return false; -} - -void reset_board(void) { - board_reset_user_neopixels(&pin_PA15, 5); -} diff --git a/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.h b/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.h deleted file mode 100644 index 921669d8cb..0000000000 --- a/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.h +++ /dev/null @@ -1,26 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "Adafruit Pybadge Airlift" -#define MICROPY_HW_MCU_NAME "samd51j20" - -#define CIRCUITPY_MCU_FAMILY samd51 - -// This is for Rev B -#define MICROPY_HW_LED_STATUS (&pin_PA23) - -// These are pins not to reset. -// QSPI Data pins -#define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) -// DotStar pins, QSPI CS, and QSPI SCK -#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) -#define MICROPY_PORT_C (0) -#define MICROPY_PORT_D (0) - -#define DEFAULT_I2C_BUS_SCL (&pin_PA13) -#define DEFAULT_I2C_BUS_SDA (&pin_PA12) - -#define DEFAULT_SPI_BUS_SCK (&pin_PA17) -#define DEFAULT_SPI_BUS_MOSI (&pin_PB23) -#define DEFAULT_SPI_BUS_MISO (&pin_PB22) - -// 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/pybadge_airlift/mpconfigboard.mk b/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk deleted file mode 100644 index a88e5e5e5b..0000000000 --- a/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk +++ /dev/null @@ -1,17 +0,0 @@ -USB_VID = 0x239A -USB_PID = 0x8043 -USB_PRODUCT = "PyBadge AirLift" -USB_MANUFACTURER = "Adafruit Industries LLC" - -CHIP_VARIANT = SAMD51J20A -CHIP_FAMILY = samd51 - -QSPI_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = GD25Q16C -LONGINT_IMPL = MPZ - -CIRCUITPY_GAMEPAD = 1 -CIRCUITPY_GAMEPADSHIFT = 1 -CIRCUITPY_STAGE = 1 - -FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge diff --git a/ports/atmel-samd/boards/pybadge_airlift/pins.c b/ports/atmel-samd/boards/pybadge_airlift/pins.c deleted file mode 100644 index 1fbe63e8eb..0000000000 --- a/ports/atmel-samd/boards/pybadge_airlift/pins.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "shared-bindings/board/__init__.h" - -#include "supervisor/board.h" -#include "shared-module/displayio/__init__.h" - -STATIC const mp_rom_map_elem_t board_global_dict_table[] = { - {MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA05)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB08)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB09)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA04)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PA06)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_PB01)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_PB04)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_PB03)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_PB02)}, - - {MP_OBJ_NEW_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PB17)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PB16)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PB03)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PB02)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA14)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA16)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA18)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB14)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA15)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA19)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA20)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA21)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA22)}, - - {MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PA23)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA23)}, - - // I2C - {MP_OBJ_NEW_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA12)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA13)}, - - // SPI - {MP_OBJ_NEW_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PA17)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB22)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB23)}, - - // Special named pins - {MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA15)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_PB04)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_PB14)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_PA27)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_LATCH), MP_ROM_PTR(&pin_PB00)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_OUT), MP_ROM_PTR(&pin_PB30)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_CLOCK), MP_ROM_PTR(&pin_PB31)}, - - // ESP control - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_CS), MP_ROM_PTR(&pin_PA14)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_GPIO0), MP_ROM_PTR(&pin_PA31)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_BUSY), MP_ROM_PTR(&pin_PA00)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RESET), MP_ROM_PTR(&pin_PB12)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_TX), MP_ROM_PTR(&pin_PB16)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RX), MP_ROM_PTR(&pin_PB17)}, - - // TFT control pins - {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(&pin_PA01)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_PB15)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_PB13)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_PB07)}, - {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_I2C), MP_ROM_PTR(&board_i2c_obj)}, - {MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj)}, - - {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/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c deleted file mode 100644 index 0711c4298a..0000000000 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 "supervisor/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 "supervisor/shared/board.h" - -displayio_fourwire_obj_t board_display_obj; - -#define DELAY 0x80 - -uint8_t display_init_sequence[] = { - 0x01, 0 | DELAY, 150, // SWRESET - 0x11, 0 | DELAY, 255, // SLPOUT - 0x36, 1, 0x00, // _MADCTL bottom to top refresh in vsync aligned order. - 0x3a, 1, 0x55, // COLMOD - 16bit color - 0x21, 0 | DELAY, 10, // _INVON - 0x13, 0 | DELAY, 10, // _NORON - 0x29, 0 | DELAY, 255, // _DISPON -}; - -void board_init(void) { - busio_spi_obj_t *spi = &displays[0].fourwire_bus.inline_bus; - common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB12, NULL); - 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_PA00, // TFT_DC Command or data - &pin_PB15, // TFT_CS Chip select - &pin_PB05, // TFT_RST Reset - 60000000, // Baudrate - 0, // Polarity - 0); // Phase - - displayio_display_obj_t *display = &displays[0].display; - display->base.type = &displayio_display_type; - common_hal_displayio_display_construct(display, - bus, - 320, // Width (after rotation) - 240, // Height (after rotation) - 0, // column start - 0, // row start - 90, // rotation - 16, // Color depth - false, // Grayscale - false, // pixels in a byte share a row. Only valid for depths < 8 - 1, // bytes per cell. Only valid for depths < 8 - false, // reverse_pixels_in_byte. Only valid for depths < 8 - true, // reverse_pixels_in_word - 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_PA01, // backlight pin - NO_BRIGHTNESS_COMMAND, - 1.0f, // brightness (ignored) - true, // auto_brightness - false, // single_byte_bounds - false, // data_as_commands - true, // auto_refresh - 60, // native_frames_per_second - true, // backlight_on_high - false); // SH1107_addressing -} - -bool board_requests_safe_mode(void) { - return false; -} - -void reset_board(void) { - board_reset_user_neopixels(&pin_PA15, 5); -} diff --git a/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.h b/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.h deleted file mode 100644 index fbe946b72f..0000000000 --- a/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.h +++ /dev/null @@ -1,28 +0,0 @@ -#define MICROPY_HW_BOARD_NAME "Adafruit PyGamer" -#define MICROPY_HW_MCU_NAME "samd51j20" - -#define CIRCUITPY_MCU_FAMILY samd51 - -#define MICROPY_HW_LED_STATUS (&pin_PA23) - -// These are pins not to reset. -// QSPI Data pins -#define MICROPY_PORT_A (PORT_PA08 | PORT_PA09 | PORT_PA10 | PORT_PA11) -// DotStar pins, QSPI CS, and QSPI SCK -#define MICROPY_PORT_B (PORT_PB10 | PORT_PB11) -#define MICROPY_PORT_C (0) -#define MICROPY_PORT_D (0) - -#define DEFAULT_I2C_BUS_SCL (&pin_PA13) -#define DEFAULT_I2C_BUS_SDA (&pin_PA12) - -#define DEFAULT_SPI_BUS_SCK (&pin_PA17) -#define DEFAULT_SPI_BUS_MOSI (&pin_PB23) -#define DEFAULT_SPI_BUS_MISO (&pin_PB22) - -#define DEFAULT_UART_BUS_RX (&pin_PB17) -#define DEFAULT_UART_BUS_TX (&pin_PB16) - -// 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/pygamer_advance/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk deleted file mode 100644 index a58e016542..0000000000 --- a/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk +++ /dev/null @@ -1,17 +0,0 @@ -USB_VID = 0x239A -USB_PID = 0x803E -USB_PRODUCT = "PyGamer Advance" -USB_MANUFACTURER = "Adafruit Industries LLC" - -CHIP_VARIANT = SAMD51J20A -CHIP_FAMILY = samd51 - -QSPI_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = GD25Q64C -LONGINT_IMPL = MPZ - -CIRCUITPY_GAMEPAD = 1 -CIRCUITPY_GAMEPADSHIFT = 1 -CIRCUITPY_STAGE = 1 - -FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge diff --git a/ports/atmel-samd/boards/pygamer_advance/pins.c b/ports/atmel-samd/boards/pygamer_advance/pins.c deleted file mode 100644 index 57a38e6947..0000000000 --- a/ports/atmel-samd/boards/pygamer_advance/pins.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "shared-bindings/board/__init__.h" - -#include "supervisor/board.h" -#include "shared-module/displayio/__init__.h" - -STATIC const mp_rom_map_elem_t board_global_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA05) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB08) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB09) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA04) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PA06) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_PB01) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_PB04) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_PB03) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_PB02) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PB17) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PB16) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PB03) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PB02) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PA14) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA16) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA18) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB14) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PA15) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA19) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA20) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA21) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA22) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PA23) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA23) }, - - // UART - { MP_OBJ_NEW_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PB17) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PB16) }, - - // I2C - { MP_OBJ_NEW_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA13) }, - - // SPI - { MP_OBJ_NEW_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PA17) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB22) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB23) }, - - // SDCS, dup of D4 - { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_PA14) }, - - // Special named pins - { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA15) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_PB04) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_PB14) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_PA27) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_LATCH), MP_ROM_PTR(&pin_PB00) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_OUT), MP_ROM_PTR(&pin_PB30) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON_CLOCK), MP_ROM_PTR(&pin_PB31) }, - - // TFT control pins - { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(&pin_PA01) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_PB12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_PB13) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_PB05) }, - { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_PB15) }, - { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_PA00) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_JOYSTICK_X), MP_ROM_PTR(&pin_PB07) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_JOYSTICK_Y), MP_ROM_PTR(&pin_PB06) }, - - { 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_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); From 050b5f4cf098ca97bf44f4c0611ab3a873ba1e20 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 27 May 2021 21:29:38 -0400 Subject: [PATCH 07/38] fix check of usb_hid.Device out_report_length --- locale/circuitpython.pot | 6 +++++- shared-bindings/usb_hid/Device.c | 17 +++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index eb75d2da6f..fbb6402051 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -87,6 +87,10 @@ msgstr "" msgid "%q list must be a list" msgstr "" +#: shared-bindings/usb_hid/Device.c +msgid "%q must be 0-255" +msgstr "" + #: shared-bindings/usb_hid/Device.c msgid "%q must be 1-255" msgstr "" @@ -104,7 +108,7 @@ msgid "%q must be >= 1" msgstr "" #: shared-bindings/usb_hid/Device.c -msgid "%q must be None or 1-255" +msgid "%q must be None or between 1 and len(report_descriptor)-1" msgstr "" #: shared-module/vectorio/Polygon.c diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c index 38556e5c13..64803f8e13 100644 --- a/shared-bindings/usb_hid/Device.c +++ b/shared-bindings/usb_hid/Device.c @@ -69,16 +69,16 @@ STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args { MP_QSTR_usage_page, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_usage, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_in_report_length, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_out_report_length, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = 0 } }, + { MP_QSTR_out_report_length, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } }, { MP_QSTR_report_id_index, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_report_descriptor].u_obj, &bufinfo, MP_BUFFER_READ); - mp_obj_t descriptor = mp_obj_new_bytearray(bufinfo.len, bufinfo.buf); + mp_buffer_info_t descriptor_bufinfo; + mp_get_buffer_raise(args[ARG_report_descriptor].u_obj, &descriptor_bufinfo, MP_BUFFER_READ); + mp_obj_t descriptor = mp_obj_new_bytearray(descriptor_bufinfo.len, descriptor_bufinfo.buf); const mp_int_t usage_page_arg = args[ARG_usage_page].u_int; if (usage_page_arg <= 0 || usage_page_arg > 255) { @@ -99,8 +99,8 @@ STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args const uint8_t in_report_length = in_report_length_arg; const mp_int_t out_report_length_arg = args[ARG_out_report_length].u_int; - if (out_report_length_arg <= 0 || out_report_length_arg > 255) { - mp_raise_ValueError_varg(translate("%q must be 1-255"), MP_QSTR_out_report_length); + if (out_report_length_arg < 0 || out_report_length_arg > 255) { + mp_raise_ValueError_varg(translate("%q must be 0-255"), MP_QSTR_out_report_length); } const uint8_t out_report_length = out_report_length_arg; @@ -108,8 +108,9 @@ STATIC mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args uint8_t report_id_index = 0; if (report_id_index_arg != mp_const_none) { const mp_int_t report_id_index_int = mp_obj_int_get_checked(report_id_index_arg); - if (report_id_index_int <= 0 || report_id_index_int > 255) { - mp_raise_ValueError_varg(translate("%q must be None or 1-255"), MP_QSTR_report_id_index); + if (report_id_index_int <= 0 || (uint32_t)report_id_index_int >= descriptor_bufinfo.len) { + mp_raise_ValueError_varg(translate("%q must be None or between 1 and len(report_descriptor)-1"), + MP_QSTR_report_id_index); } report_id_index = report_id_index_int; } From 44b876f7693ba181c90dd813692f65e4a05266f8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 28 May 2021 23:00:07 -0400 Subject: [PATCH 08/38] Inital keypad work: Keys working: one pin per key keypad.Buttons and keypad.State Buttons -> Keys; further work wip wip wip: compiles about to try keypad.Keys working --- locale/circuitpython.pot | 5 +- py/circuitpy_defns.mk | 12 +- py/circuitpy_mpconfig.h | 24 ++-- py/circuitpy_mpconfig.mk | 9 +- shared-bindings/keypad/Keys.c | 175 ++++++++++++++++++++++++++++++ shared-bindings/keypad/Keys.h | 41 +++++++ shared-bindings/keypad/State.c | 75 +++++++++++++ shared-bindings/keypad/State.h | 44 ++++++++ shared-bindings/keypad/__init__.c | 53 +++++++++ shared-bindings/keypad/__init__.h | 41 +++++++ shared-module/keypad/Keys.c | 127 ++++++++++++++++++++++ shared-module/keypad/Keys.h | 44 ++++++++ shared-module/keypad/State.c | 0 shared-module/keypad/__init__.c | 0 shared-module/keypad/__init__.h | 30 +++++ 15 files changed, 664 insertions(+), 16 deletions(-) create mode 100644 shared-bindings/keypad/Keys.c create mode 100644 shared-bindings/keypad/Keys.h create mode 100644 shared-bindings/keypad/State.c create mode 100644 shared-bindings/keypad/State.h create mode 100644 shared-bindings/keypad/__init__.c create mode 100644 shared-bindings/keypad/__init__.h create mode 100644 shared-module/keypad/Keys.c create mode 100644 shared-module/keypad/Keys.h create mode 100644 shared-module/keypad/State.c create mode 100644 shared-module/keypad/__init__.c create mode 100644 shared-module/keypad/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index fbb6402051..f80bfd4eb3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -116,7 +116,7 @@ msgid "%q must be a tuple of length 2" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: shared-bindings/canio/Match.c +#: shared-bindings/canio/Match.c shared-bindings/keypad/Keys.c msgid "%q out of range" msgstr "" @@ -905,7 +905,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c #: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c -#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c +#: shared-bindings/busio/SPI.c shared-bindings/keypad/Keys.c +#: shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 41f8d71abd..6b3dd7f17a 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -178,6 +178,9 @@ endif ifeq ($(CIRCUITPY_FRAMEBUFFERIO),1) SRC_PATTERNS += framebufferio/% endif +ifeq ($(CIRCUITPY__EVE),1) +SRC_PATTERNS += _eve/% +endif ifeq ($(CIRCUITPY_FREQUENCYIO),1) SRC_PATTERNS += frequencyio/% endif @@ -196,12 +199,12 @@ endif ifeq ($(CIRCUITPY_IPADDRESS),1) SRC_PATTERNS += ipaddress/% endif +ifeq ($(CIRCUITPY_KEYPAD),1) +SRC_PATTERNS += keypad/% +endif ifeq ($(CIRCUITPY_MATH),1) SRC_PATTERNS += math/% endif -ifeq ($(CIRCUITPY__EVE),1) -SRC_PATTERNS += _eve/% -endif ifeq ($(CIRCUITPY_MEMORYMONITOR),1) SRC_PATTERNS += memorymonitor/% endif @@ -512,6 +515,9 @@ SRC_SHARED_MODULE_ALL = \ framebufferio/__init__.c \ ipaddress/IPv4Address.c \ ipaddress/__init__.c \ + keypad/__init__.c \ + keypad/Keys.c \ + keypad/State.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ gamepad/GamePad.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c71cad6aeb..21c91bfac6 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -439,6 +439,13 @@ extern const struct _mp_obj_module_t espidf_module; #define ESPIDF_MODULE #endif +#if CIRCUITPY__EVE +extern const struct _mp_obj_module_t _eve_module; +#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module }, +#else +#define _EVE_MODULE +#endif + #if CIRCUITPY_FRAMEBUFFERIO extern const struct _mp_obj_module_t framebufferio_module; #define FRAMEBUFFERIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_framebufferio), (mp_obj_t)&framebufferio_module }, @@ -522,6 +529,13 @@ extern const struct _mp_obj_module_t ipaddress_module; #define JSON_MODULE #endif +#if CIRCUITPY_KEYPAD +extern const struct _mp_obj_module_t keypad_module; +#define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module }, +#else +#define KEYPAD_MODULE +#endif + #if CIRCUITPY_MATH extern const struct _mp_obj_module_t math_module; #define MATH_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, @@ -529,13 +543,6 @@ extern const struct _mp_obj_module_t math_module; #define MATH_MODULE #endif -#if CIRCUITPY__EVE -extern const struct _mp_obj_module_t _eve_module; -#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module }, -#else -#define _EVE_MODULE -#endif - #if CIRCUITPY_MEMORYMONITOR extern const struct _mp_obj_module_t memorymonitor_module; #define MEMORYMONITOR_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_memorymonitor), (mp_obj_t)&memorymonitor_module }, @@ -876,6 +883,7 @@ extern const struct _mp_obj_module_t msgpack_module; VECTORIO_MODULE \ ERRNO_MODULE \ ESPIDF_MODULE \ + _EVE_MODULE \ FRAMEBUFFERIO_MODULE \ FREQUENCYIO_MODULE \ GAMEPAD_MODULE \ @@ -885,8 +893,8 @@ extern const struct _mp_obj_module_t msgpack_module; IPADDRESS_MODULE \ IMAGECAPTURE_MODULE \ JSON_MODULE \ + KEYPAD_MODULE \ MATH_MODULE \ - _EVE_MODULE \ MEMORYMONITOR_MODULE \ MICROCONTROLLER_MODULE \ MSGPACK_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 077470d936..9c9e84321e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -178,6 +178,9 @@ CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO) CIRCUITPY_ESPIDF ?= 0 CFLAGS += -DCIRCUITPY_ESPIDF=$(CIRCUITPY_ESPIDF) +CIRCUITPY__EVE ?= 0 +CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE) + CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO) @@ -199,12 +202,12 @@ CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS) CIRCUITPY_JSON ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON) +CIRCUITPY_KEYPAD ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_KEYPAD=$(CIRCUITPY_KEYPAD) + CIRCUITPY_MATH ?= 1 CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) -CIRCUITPY__EVE ?= 0 -CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE) - CIRCUITPY_MEMORYMONITOR ?= 0 CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c new file mode 100644 index 0000000000..118328abe9 --- /dev/null +++ b/shared-bindings/keypad/Keys.c @@ -0,0 +1,175 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/enum.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "py/runtime.h" + +//| class Keys: +//| """Manage a set of independent keys.""" +//| +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True) -> None: +//| """ +//| Create a `Keys` object that will scan keys attached to the given sequence of pins. +//| Each key is independent and attached to its own pin. +//| +//| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys. +//| The key numbers correspond to indices into this sequence. +//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. +//| ``False`` if the pin reads low (is grounded) when the key is pressed. +//| All the pins must be connected in the same way. +//| :param bool pull: ``True`` if an internal pull-up or pull-down should be +//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``; +//| a pull-down will be used if it is ``True``. +//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. +//| However, enabling an internal pull when an external one is already present is not a problem; +//| it simply uses slightly more current. +//| +//| Calls `scan()` once before returning, to initialize internal state. +//| """ +//| ... + +STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t); + self->base.type = &keypad_keys_type; + enum { ARG_pins, ARG_value_when_pressed, ARG_pull }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, + { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + mp_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 pins = args[ARG_pins].u_obj; + const mp_uint_t num_pins = mp_obj_int_get_uint_checked(mp_obj_len(pins)); + const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; + + mcu_pin_obj_t *pins_array[num_pins]; + + for (mp_uint_t i = 0; i < num_pins; i++) { + mcu_pin_obj_t *pin = + validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + pins_array[i] = pin; + } + + common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| def scan(self) -> None: +//| """Scan the keys and record which are newly pressed, still pressed, +//| newly released, and still released. For convenient activity checking, +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_scan(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keys_scan(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); + +//| def state(self, key_num: int) -> keypad.State: +//| """Return the state for the given ``key_num``, based +//| on the results of the most recent `scan()`. +//| +//| :param int key_num: Key number: corresponds to the sequence of pins +//| :return: state of key number ``key_num`` +//| :rtype: keypad.State: One of `State.JUST_PRESSED`, `State.STILL_PRESSED`, +//| `State.JUST_RELEASED`, or `State.STILL_RELEASED`. +//| The inclusive states `State.PRESSED` and `State.RELEASED` will *not* be returned. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_state(mp_obj_t self_in, mp_obj_t key_num_obj) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t key_num = mp_obj_int_get_checked(key_num_obj); + if (key_num < 0 || key_num >= common_hal_keypad_keys_length(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return cp_enum_find(&keypad_state_type, common_hal_keypad_keys_state(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_state_obj, keypad_keys_state); + +//| def keys_with_state(self, state: State, into_list: List[Optional[int]]) -> None: +//| """Store key numbers of keys with state ``state`` in ``into_list``. +//| The states checked are based on the results of the most recent `scan()`. +//| +//| You can use the inclusive states `State.PRESSED` and `State.RELEASED`. +//| `State.PRESSED` includes states `State.JUST_PRESSED` and `State.STILL_PRESSED`. +//| `State.RELEASED` includes `State.JUST_RELEASED` and `State.STILL_RELEASED`. +//| +//| The key numbers are stored in ``into_list`` consecutively, up to ``len(into_list)``. +//| The ``into_list`` is not extended if there are more keys with the given +//| state than list slots. Instead, leftover key numbers are discarded. +//| If there are fewer keys with the given state, the rest of ``into_list`` +//| is padded with ``None``. For example, +//| if four keys are being monitored, and only key numbers 0 and 2 have the given state, +//| ``into_list`` will be set to ``[0, 2, None, None]``. You can iterate over +//| ``into_list`` and stop when you find the first ``None``. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_keys_with_state(mp_obj_t self_in, mp_obj_t state_in, mp_obj_t into_list_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!mp_obj_is_type(state_in, &keypad_state_type)) { + mp_raise_ValueError_varg(translate("Expected a %q"), keypad_state_type.name); + } + + if (!mp_obj_is_type(into_list_in, &mp_type_list)) { + mp_raise_ValueError_varg(translate("Expected a %q"), mp_type_list.name); + } + + int state = cp_enum_value(&keypad_state_type, state_in); + mp_obj_list_t *into_list = MP_OBJ_TO_PTR(into_list_in); + + common_hal_keypad_keys_keys_with_state(self, state, into_list); + + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_3(keypad_keys_keys_with_state_obj, keypad_keys_keys_with_state); + +STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_keys_with_state), MP_ROM_PTR(&keypad_keys_keys_with_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&keypad_keys_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&keypad_keys_state_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); + +const mp_obj_type_t keypad_keys_type = { + { &mp_type_type }, + .name = MP_QSTR_Keys, + .make_new = keypad_keys_make_new, + .locals_dict = (mp_obj_t)&keypad_keys_locals_dict, +}; diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h new file mode 100644 index 0000000000..f7d33a78c1 --- /dev/null +++ b/shared-bindings/keypad/Keys.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H + +#include "py/objlist.h" +#include "shared-module/keypad/Keys.h" + +extern const mp_obj_type_t keypad_keys_type; + +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull); +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, mp_int_t state, mp_obj_list_t *into); +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self); +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self); +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/State.c b/shared-bindings/keypad/State.c new file mode 100644 index 0000000000..8e35d09a83 --- /dev/null +++ b/shared-bindings/keypad/State.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/enum.h" + +#include "shared-bindings/keypad/State.h" + +// Defines enum values like +// const cp_enum_obj_t state_JUST_PRESSED = ... +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_PRESSED, STATE_JUST_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_PRESSED, STATE_STILL_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, PRESSED, STATE_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_RELEASED, STATE_JUST_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_RELEASED, STATE_STILL_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, RELEASED, STATE_RELEASED); + +//| class State: +//| """The state of a key, based on the last call to ``scan()``.""" +//| +//| JUST_PRESSED: State +//| """The key transitioned from released to pressed.""" +//| +//| STILL_PRESSED: State +//| """The key was already pressed, and continues to be pressed.""" +//| +//| PRESSED: State +//| """The key is now pressed. Used to indicate states `JUST_PRESSED` and `STILL_PRESSED` inclusively.""" +//| +//| JUST_RELEASED: State +//| """The key transitioned from pressed to released.""" +//| +//| STILL_RELEASED: State +//| """The key was already released, and continues to be released.""" +//| +//| RELEASED: State +//| """The key is now released. Used to indicate states `JUST_RELEASED` and `STILL_RELEASED` inclusively.""" +//| +MAKE_ENUM_MAP(keypad_state) { + MAKE_ENUM_MAP_ENTRY(state, JUST_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, STILL_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, PRESSED), + MAKE_ENUM_MAP_ENTRY(state, JUST_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, STILL_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, RELEASED), +}; +STATIC MP_DEFINE_CONST_DICT(keypad_state_locals_dict, keypad_state_locals_table); + +MAKE_PRINTER(keypad, keypad_state); + +// Defines keypad_state_type. +MAKE_ENUM_TYPE(keypad, State, keypad_state); diff --git a/shared-bindings/keypad/State.h b/shared-bindings/keypad/State.h new file mode 100644 index 0000000000..1b6316b001 --- /dev/null +++ b/shared-bindings/keypad/State.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H + +#include "py/obj.h" +#include "py/enum.h" + +typedef enum { + STATE_JUST_PRESSED, + STATE_STILL_PRESSED, + STATE_PRESSED, + STATE_JUST_RELEASED, + STATE_STILL_RELEASED, + STATE_RELEASED, +} keypad_state_t; + +extern const mp_obj_type_t keypad_state_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c new file mode 100644 index 0000000000..4ca66b531a --- /dev/null +++ b/shared-bindings/keypad/__init__.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2011 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#include "shared-bindings/keypad/__init__.h" +// #include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" + +//| """Support for scanning keys and key matrices +//| +//| The `keypad` module provides native support to scan sets of keys or buttons, +//| connected independently to individual pins, or connected in a row-and-column matrix. +//| """ +//| + +STATIC mp_map_elem_t keypad_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, +// { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_key_matrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR_State), MP_OBJ_FROM_PTR(&keypad_state_type) }, +}; + +STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table); + +const mp_obj_module_t keypad_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&keypad_module_globals, +}; diff --git a/shared-bindings/keypad/__init__.h b/shared-bindings/keypad/__init__.h new file mode 100644 index 0000000000..5e484dc5ed --- /dev/null +++ b/shared-bindings/keypad/__init__.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SHARED_BINDINGS_KEYPAD_H +#define SHARED_BINDINGS_KEYPAD_H + +#include "py/obj.h" +#include "py/objtuple.h" +#include "shared-module/keypad/__init__.h" + +extern mp_obj_tuple_t common_hal_keypad_devices; + +void keypad_set_devices(mp_obj_t devices); + +bool common_hal_keypad_disable(void); +bool common_hal_keypad_enable(const mp_obj_t devices_seq); + +#endif // SHARED_BINDINGS_KEYPAD_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c new file mode 100644 index 0000000000..ca1dca42ef --- /dev/null +++ b/shared-module/keypad/Keys.c @@ -0,0 +1,127 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/gc.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "py/runtime.h" + +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull) { + mp_obj_t dios[num_pins]; + + for (size_t i = 0; i < num_pins; i++) { + digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); + dio->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(dio, pins[i]); + if (pull) { + common_hal_digitalio_digitalinout_set_pull(dio, value_when_pressed ? PULL_DOWN : PULL_UP); + } + dios[i] = dio; + } + + self->digitalinouts = mp_obj_new_tuple(num_pins, dios); + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); + self->value_when_pressed = value_when_pressed; + +} + +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, int state, mp_obj_list_t *list_into) { + const size_t list_length = list_into->len; + + size_t next_list_slot = 0; + + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + if (next_list_slot >= list_length) { + // List is full. + break; + } + + bool store_key = false; + switch (state) { + case STATE_JUST_PRESSED: + store_key = !self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_STILL_PRESSED: + store_key = self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_PRESSED: + store_key = self->currently_pressed[key_num]; + break; + case STATE_JUST_RELEASED: + store_key = self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_STILL_RELEASED: + store_key = !self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_RELEASED: + store_key = !self->currently_pressed[key_num]; + break; + } + + if (store_key) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(next_list_slot), + MP_OBJ_NEW_SMALL_INT(key_num)); + next_list_slot++; + } + + for (size_t unused_slot = next_list_slot; unused_slot < list_length; unused_slot++) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(unused_slot), + MP_ROM_NONE); + } + } +} + +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { + return self->digitalinouts->len; +} + +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + self->previously_pressed[key_num] = self->currently_pressed[key_num]; + self->currently_pressed[key_num] = + common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + self->value_when_pressed; + } +} + +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num) { + if (self->currently_pressed[key_num]) { + if (self->previously_pressed[key_num]) { + return STATE_STILL_PRESSED; + } else { + return STATE_JUST_PRESSED; + } + } else { + if (self->previously_pressed[key_num]) { + return STATE_JUST_RELEASED; + } else { + return STATE_STILL_RELEASED; + } + } +} diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h new file mode 100644 index 0000000000..077b981dd6 --- /dev/null +++ b/shared-module/keypad/Keys.h @@ -0,0 +1,44 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H + +#include "common-hal/digitalio/DigitalInOut.h" + +#include "py/obj.h" +#include "py/objtuple.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_tuple_t *digitalinouts; + bool value_when_pressed; + bool *previously_pressed; + bool *currently_pressed; +} keypad_keys_obj_t; + + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H diff --git a/shared-module/keypad/State.c b/shared-module/keypad/State.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h new file mode 100644 index 0000000000..4220a3df63 --- /dev/null +++ b/shared-module/keypad/__init__.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SHARED_MODULE_KEYPAD_H +#define SHARED_MODULE_KEYPAD_H + +#endif // SHARED_MODULE_KEYPAD_H From 7d23206018e04bbc4db4d408afbe07ad96e45ff3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 28 May 2021 23:00:07 -0400 Subject: [PATCH 09/38] Inital keypad work: Keys working: one pin per key keypad.Buttons and keypad.State Buttons -> Keys; further work wip wip wip: compiles about to try keypad.Keys working --- locale/circuitpython.pot | 5 +- py/circuitpy_defns.mk | 12 +- py/circuitpy_mpconfig.h | 24 ++-- py/circuitpy_mpconfig.mk | 9 +- shared-bindings/keypad/Keys.c | 175 ++++++++++++++++++++++++++++++ shared-bindings/keypad/Keys.h | 41 +++++++ shared-bindings/keypad/State.c | 75 +++++++++++++ shared-bindings/keypad/State.h | 44 ++++++++ shared-bindings/keypad/__init__.c | 53 +++++++++ shared-bindings/keypad/__init__.h | 41 +++++++ shared-module/keypad/Keys.c | 127 ++++++++++++++++++++++ shared-module/keypad/Keys.h | 44 ++++++++ shared-module/keypad/State.c | 0 shared-module/keypad/__init__.c | 0 shared-module/keypad/__init__.h | 30 +++++ 15 files changed, 664 insertions(+), 16 deletions(-) create mode 100644 shared-bindings/keypad/Keys.c create mode 100644 shared-bindings/keypad/Keys.h create mode 100644 shared-bindings/keypad/State.c create mode 100644 shared-bindings/keypad/State.h create mode 100644 shared-bindings/keypad/__init__.c create mode 100644 shared-bindings/keypad/__init__.h create mode 100644 shared-module/keypad/Keys.c create mode 100644 shared-module/keypad/Keys.h create mode 100644 shared-module/keypad/State.c create mode 100644 shared-module/keypad/__init__.c create mode 100644 shared-module/keypad/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index fbb6402051..f80bfd4eb3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -116,7 +116,7 @@ msgid "%q must be a tuple of length 2" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: shared-bindings/canio/Match.c +#: shared-bindings/canio/Match.c shared-bindings/keypad/Keys.c msgid "%q out of range" msgstr "" @@ -905,7 +905,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c #: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c -#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c +#: shared-bindings/busio/SPI.c shared-bindings/keypad/Keys.c +#: shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 41f8d71abd..6b3dd7f17a 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -178,6 +178,9 @@ endif ifeq ($(CIRCUITPY_FRAMEBUFFERIO),1) SRC_PATTERNS += framebufferio/% endif +ifeq ($(CIRCUITPY__EVE),1) +SRC_PATTERNS += _eve/% +endif ifeq ($(CIRCUITPY_FREQUENCYIO),1) SRC_PATTERNS += frequencyio/% endif @@ -196,12 +199,12 @@ endif ifeq ($(CIRCUITPY_IPADDRESS),1) SRC_PATTERNS += ipaddress/% endif +ifeq ($(CIRCUITPY_KEYPAD),1) +SRC_PATTERNS += keypad/% +endif ifeq ($(CIRCUITPY_MATH),1) SRC_PATTERNS += math/% endif -ifeq ($(CIRCUITPY__EVE),1) -SRC_PATTERNS += _eve/% -endif ifeq ($(CIRCUITPY_MEMORYMONITOR),1) SRC_PATTERNS += memorymonitor/% endif @@ -512,6 +515,9 @@ SRC_SHARED_MODULE_ALL = \ framebufferio/__init__.c \ ipaddress/IPv4Address.c \ ipaddress/__init__.c \ + keypad/__init__.c \ + keypad/Keys.c \ + keypad/State.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ gamepad/GamePad.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 009b428645..86321d5d02 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -440,6 +440,13 @@ extern const struct _mp_obj_module_t espidf_module; #define ESPIDF_MODULE #endif +#if CIRCUITPY__EVE +extern const struct _mp_obj_module_t _eve_module; +#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module }, +#else +#define _EVE_MODULE +#endif + #if CIRCUITPY_FRAMEBUFFERIO extern const struct _mp_obj_module_t framebufferio_module; #define FRAMEBUFFERIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_framebufferio), (mp_obj_t)&framebufferio_module }, @@ -523,6 +530,13 @@ extern const struct _mp_obj_module_t ipaddress_module; #define JSON_MODULE #endif +#if CIRCUITPY_KEYPAD +extern const struct _mp_obj_module_t keypad_module; +#define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module }, +#else +#define KEYPAD_MODULE +#endif + #if CIRCUITPY_MATH extern const struct _mp_obj_module_t math_module; #define MATH_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, @@ -530,13 +544,6 @@ extern const struct _mp_obj_module_t math_module; #define MATH_MODULE #endif -#if CIRCUITPY__EVE -extern const struct _mp_obj_module_t _eve_module; -#define _EVE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__eve), (mp_obj_t)&_eve_module }, -#else -#define _EVE_MODULE -#endif - #if CIRCUITPY_MEMORYMONITOR extern const struct _mp_obj_module_t memorymonitor_module; #define MEMORYMONITOR_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_memorymonitor), (mp_obj_t)&memorymonitor_module }, @@ -877,6 +884,7 @@ extern const struct _mp_obj_module_t msgpack_module; VECTORIO_MODULE \ ERRNO_MODULE \ ESPIDF_MODULE \ + _EVE_MODULE \ FRAMEBUFFERIO_MODULE \ FREQUENCYIO_MODULE \ GAMEPAD_MODULE \ @@ -886,8 +894,8 @@ extern const struct _mp_obj_module_t msgpack_module; IPADDRESS_MODULE \ IMAGECAPTURE_MODULE \ JSON_MODULE \ + KEYPAD_MODULE \ MATH_MODULE \ - _EVE_MODULE \ MEMORYMONITOR_MODULE \ MICROCONTROLLER_MODULE \ MSGPACK_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 077470d936..9c9e84321e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -178,6 +178,9 @@ CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO) CIRCUITPY_ESPIDF ?= 0 CFLAGS += -DCIRCUITPY_ESPIDF=$(CIRCUITPY_ESPIDF) +CIRCUITPY__EVE ?= 0 +CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE) + CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO) @@ -199,12 +202,12 @@ CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS) CIRCUITPY_JSON ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_JSON=$(CIRCUITPY_JSON) +CIRCUITPY_KEYPAD ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_KEYPAD=$(CIRCUITPY_KEYPAD) + CIRCUITPY_MATH ?= 1 CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) -CIRCUITPY__EVE ?= 0 -CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE) - CIRCUITPY_MEMORYMONITOR ?= 0 CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c new file mode 100644 index 0000000000..118328abe9 --- /dev/null +++ b/shared-bindings/keypad/Keys.c @@ -0,0 +1,175 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/enum.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "py/runtime.h" + +//| class Keys: +//| """Manage a set of independent keys.""" +//| +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True) -> None: +//| """ +//| Create a `Keys` object that will scan keys attached to the given sequence of pins. +//| Each key is independent and attached to its own pin. +//| +//| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys. +//| The key numbers correspond to indices into this sequence. +//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. +//| ``False`` if the pin reads low (is grounded) when the key is pressed. +//| All the pins must be connected in the same way. +//| :param bool pull: ``True`` if an internal pull-up or pull-down should be +//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``; +//| a pull-down will be used if it is ``True``. +//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. +//| However, enabling an internal pull when an external one is already present is not a problem; +//| it simply uses slightly more current. +//| +//| Calls `scan()` once before returning, to initialize internal state. +//| """ +//| ... + +STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t); + self->base.type = &keypad_keys_type; + enum { ARG_pins, ARG_value_when_pressed, ARG_pull }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, + { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + mp_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 pins = args[ARG_pins].u_obj; + const mp_uint_t num_pins = mp_obj_int_get_uint_checked(mp_obj_len(pins)); + const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; + + mcu_pin_obj_t *pins_array[num_pins]; + + for (mp_uint_t i = 0; i < num_pins; i++) { + mcu_pin_obj_t *pin = + validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + pins_array[i] = pin; + } + + common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| def scan(self) -> None: +//| """Scan the keys and record which are newly pressed, still pressed, +//| newly released, and still released. For convenient activity checking, +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_scan(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keys_scan(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); + +//| def state(self, key_num: int) -> keypad.State: +//| """Return the state for the given ``key_num``, based +//| on the results of the most recent `scan()`. +//| +//| :param int key_num: Key number: corresponds to the sequence of pins +//| :return: state of key number ``key_num`` +//| :rtype: keypad.State: One of `State.JUST_PRESSED`, `State.STILL_PRESSED`, +//| `State.JUST_RELEASED`, or `State.STILL_RELEASED`. +//| The inclusive states `State.PRESSED` and `State.RELEASED` will *not* be returned. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_state(mp_obj_t self_in, mp_obj_t key_num_obj) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t key_num = mp_obj_int_get_checked(key_num_obj); + if (key_num < 0 || key_num >= common_hal_keypad_keys_length(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return cp_enum_find(&keypad_state_type, common_hal_keypad_keys_state(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_state_obj, keypad_keys_state); + +//| def keys_with_state(self, state: State, into_list: List[Optional[int]]) -> None: +//| """Store key numbers of keys with state ``state`` in ``into_list``. +//| The states checked are based on the results of the most recent `scan()`. +//| +//| You can use the inclusive states `State.PRESSED` and `State.RELEASED`. +//| `State.PRESSED` includes states `State.JUST_PRESSED` and `State.STILL_PRESSED`. +//| `State.RELEASED` includes `State.JUST_RELEASED` and `State.STILL_RELEASED`. +//| +//| The key numbers are stored in ``into_list`` consecutively, up to ``len(into_list)``. +//| The ``into_list`` is not extended if there are more keys with the given +//| state than list slots. Instead, leftover key numbers are discarded. +//| If there are fewer keys with the given state, the rest of ``into_list`` +//| is padded with ``None``. For example, +//| if four keys are being monitored, and only key numbers 0 and 2 have the given state, +//| ``into_list`` will be set to ``[0, 2, None, None]``. You can iterate over +//| ``into_list`` and stop when you find the first ``None``. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_keys_with_state(mp_obj_t self_in, mp_obj_t state_in, mp_obj_t into_list_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!mp_obj_is_type(state_in, &keypad_state_type)) { + mp_raise_ValueError_varg(translate("Expected a %q"), keypad_state_type.name); + } + + if (!mp_obj_is_type(into_list_in, &mp_type_list)) { + mp_raise_ValueError_varg(translate("Expected a %q"), mp_type_list.name); + } + + int state = cp_enum_value(&keypad_state_type, state_in); + mp_obj_list_t *into_list = MP_OBJ_TO_PTR(into_list_in); + + common_hal_keypad_keys_keys_with_state(self, state, into_list); + + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_3(keypad_keys_keys_with_state_obj, keypad_keys_keys_with_state); + +STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_keys_with_state), MP_ROM_PTR(&keypad_keys_keys_with_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&keypad_keys_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&keypad_keys_state_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); + +const mp_obj_type_t keypad_keys_type = { + { &mp_type_type }, + .name = MP_QSTR_Keys, + .make_new = keypad_keys_make_new, + .locals_dict = (mp_obj_t)&keypad_keys_locals_dict, +}; diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h new file mode 100644 index 0000000000..f7d33a78c1 --- /dev/null +++ b/shared-bindings/keypad/Keys.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H + +#include "py/objlist.h" +#include "shared-module/keypad/Keys.h" + +extern const mp_obj_type_t keypad_keys_type; + +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull); +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, mp_int_t state, mp_obj_list_t *into); +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self); +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self); +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/State.c b/shared-bindings/keypad/State.c new file mode 100644 index 0000000000..8e35d09a83 --- /dev/null +++ b/shared-bindings/keypad/State.c @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/enum.h" + +#include "shared-bindings/keypad/State.h" + +// Defines enum values like +// const cp_enum_obj_t state_JUST_PRESSED = ... +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_PRESSED, STATE_JUST_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_PRESSED, STATE_STILL_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, PRESSED, STATE_PRESSED); +MAKE_ENUM_VALUE(keypad_state_type, state, JUST_RELEASED, STATE_JUST_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, STILL_RELEASED, STATE_STILL_RELEASED); +MAKE_ENUM_VALUE(keypad_state_type, state, RELEASED, STATE_RELEASED); + +//| class State: +//| """The state of a key, based on the last call to ``scan()``.""" +//| +//| JUST_PRESSED: State +//| """The key transitioned from released to pressed.""" +//| +//| STILL_PRESSED: State +//| """The key was already pressed, and continues to be pressed.""" +//| +//| PRESSED: State +//| """The key is now pressed. Used to indicate states `JUST_PRESSED` and `STILL_PRESSED` inclusively.""" +//| +//| JUST_RELEASED: State +//| """The key transitioned from pressed to released.""" +//| +//| STILL_RELEASED: State +//| """The key was already released, and continues to be released.""" +//| +//| RELEASED: State +//| """The key is now released. Used to indicate states `JUST_RELEASED` and `STILL_RELEASED` inclusively.""" +//| +MAKE_ENUM_MAP(keypad_state) { + MAKE_ENUM_MAP_ENTRY(state, JUST_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, STILL_PRESSED), + MAKE_ENUM_MAP_ENTRY(state, PRESSED), + MAKE_ENUM_MAP_ENTRY(state, JUST_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, STILL_RELEASED), + MAKE_ENUM_MAP_ENTRY(state, RELEASED), +}; +STATIC MP_DEFINE_CONST_DICT(keypad_state_locals_dict, keypad_state_locals_table); + +MAKE_PRINTER(keypad, keypad_state); + +// Defines keypad_state_type. +MAKE_ENUM_TYPE(keypad, State, keypad_state); diff --git a/shared-bindings/keypad/State.h b/shared-bindings/keypad/State.h new file mode 100644 index 0000000000..1b6316b001 --- /dev/null +++ b/shared-bindings/keypad/State.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H + +#include "py/obj.h" +#include "py/enum.h" + +typedef enum { + STATE_JUST_PRESSED, + STATE_STILL_PRESSED, + STATE_PRESSED, + STATE_JUST_RELEASED, + STATE_STILL_RELEASED, + STATE_RELEASED, +} keypad_state_t; + +extern const mp_obj_type_t keypad_state_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c new file mode 100644 index 0000000000..4ca66b531a --- /dev/null +++ b/shared-bindings/keypad/__init__.c @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2011 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#include "shared-bindings/keypad/__init__.h" +// #include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" + +//| """Support for scanning keys and key matrices +//| +//| The `keypad` module provides native support to scan sets of keys or buttons, +//| connected independently to individual pins, or connected in a row-and-column matrix. +//| """ +//| + +STATIC mp_map_elem_t keypad_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, +// { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_key_matrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR_State), MP_OBJ_FROM_PTR(&keypad_state_type) }, +}; + +STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table); + +const mp_obj_module_t keypad_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&keypad_module_globals, +}; diff --git a/shared-bindings/keypad/__init__.h b/shared-bindings/keypad/__init__.h new file mode 100644 index 0000000000..5e484dc5ed --- /dev/null +++ b/shared-bindings/keypad/__init__.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SHARED_BINDINGS_KEYPAD_H +#define SHARED_BINDINGS_KEYPAD_H + +#include "py/obj.h" +#include "py/objtuple.h" +#include "shared-module/keypad/__init__.h" + +extern mp_obj_tuple_t common_hal_keypad_devices; + +void keypad_set_devices(mp_obj_t devices); + +bool common_hal_keypad_disable(void); +bool common_hal_keypad_enable(const mp_obj_t devices_seq); + +#endif // SHARED_BINDINGS_KEYPAD_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c new file mode 100644 index 0000000000..ca1dca42ef --- /dev/null +++ b/shared-module/keypad/Keys.c @@ -0,0 +1,127 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/gc.h" +#include "py/objproperty.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/State.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "py/runtime.h" + +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull) { + mp_obj_t dios[num_pins]; + + for (size_t i = 0; i < num_pins; i++) { + digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); + dio->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(dio, pins[i]); + if (pull) { + common_hal_digitalio_digitalinout_set_pull(dio, value_when_pressed ? PULL_DOWN : PULL_UP); + } + dios[i] = dio; + } + + self->digitalinouts = mp_obj_new_tuple(num_pins, dios); + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); + self->value_when_pressed = value_when_pressed; + +} + +void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, int state, mp_obj_list_t *list_into) { + const size_t list_length = list_into->len; + + size_t next_list_slot = 0; + + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + if (next_list_slot >= list_length) { + // List is full. + break; + } + + bool store_key = false; + switch (state) { + case STATE_JUST_PRESSED: + store_key = !self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_STILL_PRESSED: + store_key = self->previously_pressed[key_num] && self->currently_pressed[key_num]; + break; + case STATE_PRESSED: + store_key = self->currently_pressed[key_num]; + break; + case STATE_JUST_RELEASED: + store_key = self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_STILL_RELEASED: + store_key = !self->previously_pressed[key_num] && !self->currently_pressed[key_num]; + break; + case STATE_RELEASED: + store_key = !self->currently_pressed[key_num]; + break; + } + + if (store_key) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(next_list_slot), + MP_OBJ_NEW_SMALL_INT(key_num)); + next_list_slot++; + } + + for (size_t unused_slot = next_list_slot; unused_slot < list_length; unused_slot++) { + mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(unused_slot), + MP_ROM_NONE); + } + } +} + +size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { + return self->digitalinouts->len; +} + +void common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { + self->previously_pressed[key_num] = self->currently_pressed[key_num]; + self->currently_pressed[key_num] = + common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + self->value_when_pressed; + } +} + +mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num) { + if (self->currently_pressed[key_num]) { + if (self->previously_pressed[key_num]) { + return STATE_STILL_PRESSED; + } else { + return STATE_JUST_PRESSED; + } + } else { + if (self->previously_pressed[key_num]) { + return STATE_JUST_RELEASED; + } else { + return STATE_STILL_RELEASED; + } + } +} diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h new file mode 100644 index 0000000000..077b981dd6 --- /dev/null +++ b/shared-module/keypad/Keys.h @@ -0,0 +1,44 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H + +#include "common-hal/digitalio/DigitalInOut.h" + +#include "py/obj.h" +#include "py/objtuple.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_tuple_t *digitalinouts; + bool value_when_pressed; + bool *previously_pressed; + bool *currently_pressed; +} keypad_keys_obj_t; + + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H diff --git a/shared-module/keypad/State.c b/shared-module/keypad/State.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h new file mode 100644 index 0000000000..4220a3df63 --- /dev/null +++ b/shared-module/keypad/__init__.h @@ -0,0 +1,30 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SHARED_MODULE_KEYPAD_H +#define SHARED_MODULE_KEYPAD_H + +#endif // SHARED_MODULE_KEYPAD_H From bdb70669a1391cebad0e525e821d40c236754990 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 9 Jun 2021 23:47:49 -0400 Subject: [PATCH 10/38] fix bad merge --- .../boards/sparkfun_samd51_micromod/board.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ports/atmel-samd/boards/sparkfun_samd51_micromod/board.c b/ports/atmel-samd/boards/sparkfun_samd51_micromod/board.c index 1a8f297928..5fca974e9e 100644 --- a/ports/atmel-samd/boards/sparkfun_samd51_micromod/board.c +++ b/ports/atmel-samd/boards/sparkfun_samd51_micromod/board.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * 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 @@ -24,12 +24,15 @@ * THE SOFTWARE. */ - << << << < HEAD: shared - module / keypad / __init__.h -#ifndef SHARED_MODULE_KEYPAD_H -#define SHARED_MODULE_KEYPAD_H -== == == = #include "supervisor/board.h" #include "mpconfigboard.h" - >> >> >> > adafruit / main: ports / atmel - samd / boards / sparkfun_samd51_micromod / board.c -#endif // SHARED_MODULE_KEYPAD_H +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { +} From d3d9e0a487f2d19831921473e4ee26aeee81aac0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 10 Jun 2021 00:07:23 -0400 Subject: [PATCH 11/38] add debouncing --- shared-bindings/keypad/Keys.c | 13 +++++++++---- shared-bindings/keypad/Keys.h | 2 +- shared-module/keypad/Keys.c | 14 +++++++++++++- shared-module/keypad/Keys.h | 1 + 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 118328abe9..f1a83a64bd 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -80,20 +80,25 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c } common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool); + common_hal_keypad_keys_scan(self); return MP_OBJ_FROM_PTR(self); } -//| def scan(self) -> None: +//| def scan(self) -> bool: //| """Scan the keys and record which are newly pressed, still pressed, -//| newly released, and still released. For convenient activity checking, +//| newly released, and still released. If not enough time has elapsed since +//| the last scan for debouncing, do nothing and return ``False``. +//| +//| :return: ``True`` if sufficient time has elapsed for debouncing (about 20 msecs), +//| otherwise ``False``. +//| :rtype: bool //| """ //| ... //| STATIC mp_obj_t keypad_keys_scan(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_keypad_keys_scan(self); - return MP_ROM_NONE; + return mp_obj_new_bool(common_hal_keypad_keys_scan(self)); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index f7d33a78c1..694a560238 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -35,7 +35,7 @@ extern const mp_obj_type_t keypad_keys_type; void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull); void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, mp_int_t state, mp_obj_list_t *into); size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self); -void common_hal_keypad_keys_scan(keypad_keys_obj_t *self); +bool common_hal_keypad_keys_scan(keypad_keys_obj_t *self); mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index ca1dca42ef..05faeafb0a 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -30,6 +30,9 @@ #include "shared-bindings/keypad/State.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "py/runtime.h" +#include "supervisor/port.h" + +#define DEBOUNCE_TICKS (20) void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull) { mp_obj_t dios[num_pins]; @@ -101,13 +104,22 @@ size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { return self->digitalinouts->len; } -void common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { +bool common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { + uint64_t now = port_get_raw_ticks(NULL); + uint64_t last_scan_ticks = self->last_scan_ticks; + self->last_scan_ticks = now; + if (now - last_scan_ticks < DEBOUNCE_TICKS) { + // Too soon. + return false; + } + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { self->previously_pressed[key_num] = self->currently_pressed[key_num]; self->currently_pressed[key_num] = common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == self->value_when_pressed; } + return true; } mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num) { diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 077b981dd6..898a937632 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -35,6 +35,7 @@ typedef struct { mp_obj_base_t base; mp_obj_tuple_t *digitalinouts; + uint64_t last_scan_ticks; bool value_when_pressed; bool *previously_pressed; bool *currently_pressed; From 01a8a95b2c99274df9983ed15cfa225189548dd4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 10 Jun 2021 01:14:16 -0400 Subject: [PATCH 12/38] fix signed/unsigned compilation problem --- shared-bindings/keypad/Keys.c | 2 +- shared-module/keypad/Keys.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index f1a83a64bd..4a878ba247 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -117,7 +117,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); STATIC mp_obj_t keypad_keys_state(mp_obj_t self_in, mp_obj_t key_num_obj) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t key_num = mp_obj_int_get_checked(key_num_obj); - if (key_num < 0 || key_num >= common_hal_keypad_keys_length(self)) { + if (key_num < 0 || (mp_uint_t)key_num >= common_hal_keypad_keys_length(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); } diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 05faeafb0a..c09317d1f9 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -106,13 +106,13 @@ size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { bool common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); - uint64_t last_scan_ticks = self->last_scan_ticks; - self->last_scan_ticks = now; - if (now - last_scan_ticks < DEBOUNCE_TICKS) { + if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { // Too soon. return false; } + self->last_scan_ticks = now; + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { self->previously_pressed[key_num] = self->currently_pressed[key_num]; self->currently_pressed[key_num] = From c6e2237ac74e331fa8dda602b22057734563fa65 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 10 Jun 2021 09:05:19 -0400 Subject: [PATCH 13/38] fix non-longint builds --- shared-bindings/keypad/Keys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 4a878ba247..68a91e9243 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -68,7 +68,8 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t pins = args[ARG_pins].u_obj; - const mp_uint_t num_pins = mp_obj_int_get_uint_checked(mp_obj_len(pins)); + // mp_obj_len() will be >= 0. + const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins)); const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; mcu_pin_obj_t *pins_array[num_pins]; From b815164bdf15269e39c0af67a5d765ec27a1509d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 10 Jun 2021 10:09:55 -0400 Subject: [PATCH 14/38] Turn off keypad on a few small builds --- ports/stm/boards/espruino_pico/mpconfigboard.mk | 1 + ports/stm/boards/espruino_wifi/mpconfigboard.mk | 1 + ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.mk | 1 + 3 files changed, 3 insertions(+) diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.mk b/ports/stm/boards/espruino_pico/mpconfigboard.mk index bc415f07ec..3f3e81d553 100644 --- a/ports/stm/boards/espruino_pico/mpconfigboard.mk +++ b/ports/stm/boards/espruino_pico/mpconfigboard.mk @@ -22,6 +22,7 @@ CIRCUITPY_AUDIOPWMIO = 0 CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MIDI = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_ULAB = 0 diff --git a/ports/stm/boards/espruino_wifi/mpconfigboard.mk b/ports/stm/boards/espruino_wifi/mpconfigboard.mk index a2ceb1ae38..bb74ca8105 100644 --- a/ports/stm/boards/espruino_wifi/mpconfigboard.mk +++ b/ports/stm/boards/espruino_wifi/mpconfigboard.mk @@ -15,3 +15,4 @@ LD_FILE = boards/STM32F411_fs.ld # Too big for the flash CIRCUITPY_AUDIOCORE = 0 CIRCUITPY_AUDIOPWMIO = 0 +CIRCUITPY_KEYPAD = 0 diff --git a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.mk b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.mk index bfb88ab0ea..013d16dd6c 100644 --- a/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.mk +++ b/ports/stm/boards/stm32f411ce_blackpill/mpconfigboard.mk @@ -19,3 +19,4 @@ LD_FILE = boards/STM32F411_fs.ld # Too big for the flash CIRCUITPY_AUDIOCORE = 0 CIRCUITPY_AUDIOPWMIO = 0 +CIRCUITPY_KEYPAD = 0 From 627c426259f9eab4271cfa492873422d7433bdd3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 14 Jun 2021 16:00:15 -0400 Subject: [PATCH 15/38] wip --- locale/circuitpython.pot | 13 +- py/circuitpy_defns.mk | 3 +- shared-bindings/keypad/Event.c | 125 ++++++++++++++++ shared-bindings/keypad/Event.h | 41 ++++++ shared-bindings/keypad/Keys.c | 135 +++++++----------- shared-bindings/keypad/Keys.h | 14 +- shared-bindings/keypad/State.c | 75 ---------- shared-bindings/keypad/__init__.c | 8 +- shared-module/keypad/Event.c | 44 ++++++ .../State.h => shared-module/keypad/Event.h | 23 ++- shared-module/keypad/Keys.c | 120 +++++++--------- shared-module/keypad/Keys.h | 2 + shared-module/keypad/State.c | 0 13 files changed, 347 insertions(+), 256 deletions(-) create mode 100644 shared-bindings/keypad/Event.c create mode 100644 shared-bindings/keypad/Event.h delete mode 100644 shared-bindings/keypad/State.c create mode 100644 shared-module/keypad/Event.c rename shared-bindings/keypad/State.h => shared-module/keypad/Event.h (71%) delete mode 100644 shared-module/keypad/State.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c42a94ce98..0fe6299964 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -95,13 +95,18 @@ msgstr "" msgid "%q must be 1-255" msgstr "" +#: shared-bindings/keypad/Event.c +msgid "%q must be > 0" +msgstr "" + #: shared-bindings/memorymonitor/AllocationAlarm.c msgid "%q must be >= 0" msgstr "" #: shared-bindings/_bleio/CharacteristicBuffer.c #: shared-bindings/_bleio/PacketBuffer.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/Shape.c +#: shared-bindings/displayio/Shape.c shared-bindings/keypad/KeyMatrix.c +#: shared-bindings/keypad/Keys.c #: shared-bindings/memorymonitor/AllocationAlarm.c #: shared-bindings/vectorio/Circle.c shared-bindings/vectorio/Rectangle.c msgid "%q must be >= 1" @@ -116,7 +121,8 @@ msgid "%q must be a tuple of length 2" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: shared-bindings/canio/Match.c shared-bindings/keypad/Keys.c +#: shared-bindings/canio/Match.c shared-bindings/keypad/KeyMatrix.c +#: shared-bindings/keypad/Keys.c msgid "%q out of range" msgstr "" @@ -905,8 +911,7 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c py/enum.c #: shared-bindings/_bleio/__init__.c shared-bindings/aesio/aes.c -#: shared-bindings/busio/SPI.c shared-bindings/keypad/Keys.c -#: shared-bindings/microcontroller/Pin.c +#: shared-bindings/busio/SPI.c shared-bindings/microcontroller/Pin.c #: shared-bindings/neopixel_write/__init__.c #: shared-bindings/terminalio/Terminal.c msgid "Expected a %q" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 6b3dd7f17a..43ae46ac00 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -516,8 +516,9 @@ SRC_SHARED_MODULE_ALL = \ ipaddress/IPv4Address.c \ ipaddress/__init__.c \ keypad/__init__.c \ + keypad/Event.c \ + keypad/KeyMatrix.c \ keypad/Keys.c \ - keypad/State.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ gamepad/GamePad.c \ diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c new file mode 100644 index 0000000000..218da5b82e --- /dev/null +++ b/shared-bindings/keypad/Event.c @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/keypad/Event.h" + +//| class Event: +//| """A key transition event.""" +//| def __init__(self, key_num: int, pressed: bool) -> None: +//| """Create a key transition event, which reports a key-pressed or key-released transition. +//| +//| :param int key_num: the key number +//| :param bool pressed: ``True`` if the key was pressed; ``False`` if it was released. +//| """ +//| ... +//| + +STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + keypad_event_obj_t *self = m_new_obj(keypad_event_obj_t); + self->base.type = &keypad_event_type; + enum { ARG_key_num, ARG_pressed }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key_num, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pressed, MP_ARG_REQUIRED | MP_ARG_BOOL }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_int_t key_num = args[ARG_key_num].u_int; + if (key_num < 0) { + mp_raise_ValueError_varg(translate("%q must be > 0"), MP_QSTR_key_num); + } + + common_hal_keypad_event_construct(self, (mp_uint_t)key_num, args[ARG_pressed].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| key_num: int +//| """The key number.""" +//| +STATIC mp_obj_t keypad_event_obj_get_key_num(mp_obj_t self_in) { + keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_num(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_num_obj, keypad_event_obj_get_key_num); + +const mp_obj_property_t keypad_event_key_num_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_event_get_key_num_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +//| pressed: bool +//| """True if event represents a key down (pressed) transition.""" +//| +STATIC mp_obj_t keypad_event_obj_get_pressed(mp_obj_t self_in) { + keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_keypad_event_get_pressed(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_obj_get_pressed); + +const mp_obj_property_t keypad_event_pressed_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_event_get_pressed_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +//| released: bool +//| """True if event represents a key up (released) transition.""" +//| +STATIC mp_obj_t keypad_event_obj_get_released(mp_obj_t self_in) { + keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_keypad_event_get_released(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_obj_get_released); + +const mp_obj_property_t keypad_event_released_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_event_get_released_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = { + // Properties + { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_event_key_num_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table); + +const mp_obj_type_t keypad_event_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .make_new = keypad_event_make_new, + .locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict, +}; diff --git a/shared-bindings/keypad/Event.h b/shared-bindings/keypad/Event.h new file mode 100644 index 0000000000..03e04eb6ee --- /dev/null +++ b/shared-bindings/keypad/Event.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H + +#include "py/obj.h" +#include "shared-module/keypad/Event.h" + +extern const mp_obj_type_t keypad_event_type; + +void common_hal_keypad_event_construct(keypad_event_obj_t *self, uint16_t key_num, bool pressed); +mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self); +bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self); +bool common_hal_keypad_event_get_released(keypad_event_obj_t *self); + + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 68a91e9243..e92d91ce14 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -24,17 +24,15 @@ * THE SOFTWARE. */ -#include "py/enum.h" -#include "py/objproperty.h" +#include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" -#include "shared-bindings/keypad/State.h" #include "shared-bindings/microcontroller/Pin.h" #include "py/runtime.h" //| class Keys: //| """Manage a set of independent keys.""" //| -//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True) -> None: +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, max_events: int = 16) -> None: //| """ //| Create a `Keys` object that will scan keys attached to the given sequence of pins. //| Each key is independent and attached to its own pin. @@ -45,24 +43,27 @@ //| ``False`` if the pin reads low (is grounded) when the key is pressed. //| All the pins must be connected in the same way. //| :param bool pull: ``True`` if an internal pull-up or pull-down should be -//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``; -//| a pull-down will be used if it is ``True``. -//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. -//| However, enabling an internal pull when an external one is already present is not a problem; -//| it simply uses slightly more current. -//| -//| Calls `scan()` once before returning, to initialize internal state. +//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``; +//| a pull-down will be used if it is ``True``. +//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. +//| However, enabling an internal pull when an external one is already present is not a problem; +//| it simply uses slightly more current. +//| :param int max_events: Size of key event queue: +//| maximum number of key transition events that are saved. +//| Must be >= 1. +//| If a new event arrives when the queue is full, the oldest event is discarded. //| """ //| ... STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t); self->base.type = &keypad_keys_type; - enum { ARG_pins, ARG_value_when_pressed, ARG_pull }; + enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, }; 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); @@ -70,8 +71,14 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c mp_obj_t pins = args[ARG_pins].u_obj; // mp_obj_len() will be >= 0. const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins)); + const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; + if (args[ARG_max_events].u_int < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); + } + const size_t max_events = (size_t)args[ARG_max_events].u_int; + mcu_pin_obj_t *pins_array[num_pins]; for (mp_uint_t i = 0; i < num_pins; i++) { @@ -80,95 +87,61 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c pins_array[i] = pin; } - common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool); - common_hal_keypad_keys_scan(self); + common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, max_events); return MP_OBJ_FROM_PTR(self); } -//| def scan(self) -> bool: -//| """Scan the keys and record which are newly pressed, still pressed, -//| newly released, and still released. If not enough time has elapsed since -//| the last scan for debouncing, do nothing and return ``False``. +//| def next_event(self) -> Optional[Event]: +//| """Return the next key transition event. Return ``None` if no events are pending. //| -//| :return: ``True`` if sufficient time has elapsed for debouncing (about 20 msecs), -//| otherwise ``False``. -//| :rtype: bool +//| Note that the queue size is limited; see ``max_events`` in the constructor. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| +//| :return: the next queued key transition `Event` +//| :rtype: Optional[Event] //| """ //| ... //| -STATIC mp_obj_t keypad_keys_scan(mp_obj_t self_in) { +STATIC mp_obj_t keypad_keys_next_event(mp_obj_t self_in, mp_obj_t event_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_keypad_keys_scan(self)); + return common_hal_keypad_keys_next_event(self); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_scan_obj, keypad_keys_scan); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_next_event_obj, keypad_keys_next_event); -//| def state(self, key_num: int) -> keypad.State: -//| """Return the state for the given ``key_num``, based -//| on the results of the most recent `scan()`. -//| -//| :param int key_num: Key number: corresponds to the sequence of pins -//| :return: state of key number ``key_num`` -//| :rtype: keypad.State: One of `State.JUST_PRESSED`, `State.STILL_PRESSED`, -//| `State.JUST_RELEASED`, or `State.STILL_RELEASED`. -//| The inclusive states `State.PRESSED` and `State.RELEASED` will *not* be returned. +//| def clear_events(self) -> None: +//| """Clear any queued key transition events. //| """ //| ... //| -STATIC mp_obj_t keypad_keys_state(mp_obj_t self_in, mp_obj_t key_num_obj) { +STATIC mp_obj_t keypad_keys_clear_events(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_int_t key_num = mp_obj_int_get_checked(key_num_obj); - if (key_num < 0 || (mp_uint_t)key_num >= common_hal_keypad_keys_length(self)) { + + common_hal_keypad_keys_clear_events(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_clear_events_obj, keypad_keys_clear_events); + +//| def pressed(self, key_num: int) -> None: +//| """Return ``True`` if the given key is pressed. This is a debounced read +//| of the key state which bypasses the event queue. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t key_num = mp_obj_get_int(key_num_in); + if (key_num < 0 || key_num >= common_hal_keypad_keys_num_keys(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); } - return cp_enum_find(&keypad_state_type, common_hal_keypad_keys_state(self, (mp_uint_t)key_num)); + return mp_obj_new_bool(common_hal_keypad_keys_pressed(self, (mp_uint_t)key_num)); } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_state_obj, keypad_keys_state); - -//| def keys_with_state(self, state: State, into_list: List[Optional[int]]) -> None: -//| """Store key numbers of keys with state ``state`` in ``into_list``. -//| The states checked are based on the results of the most recent `scan()`. -//| -//| You can use the inclusive states `State.PRESSED` and `State.RELEASED`. -//| `State.PRESSED` includes states `State.JUST_PRESSED` and `State.STILL_PRESSED`. -//| `State.RELEASED` includes `State.JUST_RELEASED` and `State.STILL_RELEASED`. -//| -//| The key numbers are stored in ``into_list`` consecutively, up to ``len(into_list)``. -//| The ``into_list`` is not extended if there are more keys with the given -//| state than list slots. Instead, leftover key numbers are discarded. -//| If there are fewer keys with the given state, the rest of ``into_list`` -//| is padded with ``None``. For example, -//| if four keys are being monitored, and only key numbers 0 and 2 have the given state, -//| ``into_list`` will be set to ``[0, 2, None, None]``. You can iterate over -//| ``into_list`` and stop when you find the first ``None``. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keys_keys_with_state(mp_obj_t self_in, mp_obj_t state_in, mp_obj_t into_list_in) { - keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (!mp_obj_is_type(state_in, &keypad_state_type)) { - mp_raise_ValueError_varg(translate("Expected a %q"), keypad_state_type.name); - } - - if (!mp_obj_is_type(into_list_in, &mp_type_list)) { - mp_raise_ValueError_varg(translate("Expected a %q"), mp_type_list.name); - } - - int state = cp_enum_value(&keypad_state_type, state_in); - mp_obj_list_t *into_list = MP_OBJ_TO_PTR(into_list_in); - - common_hal_keypad_keys_keys_with_state(self, state, into_list); - - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_3(keypad_keys_keys_with_state_obj, keypad_keys_keys_with_state); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_keys_with_state), MP_ROM_PTR(&keypad_keys_keys_with_state_obj) }, - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&keypad_keys_scan_obj) }, - { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&keypad_keys_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_events), MP_ROM_PTR(&keypad_keys_clear_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_next_event), MP_ROM_PTR(&keypad_keys_next_event_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 694a560238..e9ab0b91e5 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -32,10 +32,14 @@ extern const mp_obj_type_t keypad_keys_type; -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull); -void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, mp_int_t state, mp_obj_list_t *into); -size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self); -bool common_hal_keypad_keys_scan(keypad_keys_obj_t *self); -mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num); +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events); + +mp_uint_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self); +bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); + +mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self); +void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self); + +void keypad_keys_scan(keypad_keys_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/State.c b/shared-bindings/keypad/State.c deleted file mode 100644 index 8e35d09a83..0000000000 --- a/shared-bindings/keypad/State.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2021 Dan Halbert for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/obj.h" -#include "py/enum.h" - -#include "shared-bindings/keypad/State.h" - -// Defines enum values like -// const cp_enum_obj_t state_JUST_PRESSED = ... -MAKE_ENUM_VALUE(keypad_state_type, state, JUST_PRESSED, STATE_JUST_PRESSED); -MAKE_ENUM_VALUE(keypad_state_type, state, STILL_PRESSED, STATE_STILL_PRESSED); -MAKE_ENUM_VALUE(keypad_state_type, state, PRESSED, STATE_PRESSED); -MAKE_ENUM_VALUE(keypad_state_type, state, JUST_RELEASED, STATE_JUST_RELEASED); -MAKE_ENUM_VALUE(keypad_state_type, state, STILL_RELEASED, STATE_STILL_RELEASED); -MAKE_ENUM_VALUE(keypad_state_type, state, RELEASED, STATE_RELEASED); - -//| class State: -//| """The state of a key, based on the last call to ``scan()``.""" -//| -//| JUST_PRESSED: State -//| """The key transitioned from released to pressed.""" -//| -//| STILL_PRESSED: State -//| """The key was already pressed, and continues to be pressed.""" -//| -//| PRESSED: State -//| """The key is now pressed. Used to indicate states `JUST_PRESSED` and `STILL_PRESSED` inclusively.""" -//| -//| JUST_RELEASED: State -//| """The key transitioned from pressed to released.""" -//| -//| STILL_RELEASED: State -//| """The key was already released, and continues to be released.""" -//| -//| RELEASED: State -//| """The key is now released. Used to indicate states `JUST_RELEASED` and `STILL_RELEASED` inclusively.""" -//| -MAKE_ENUM_MAP(keypad_state) { - MAKE_ENUM_MAP_ENTRY(state, JUST_PRESSED), - MAKE_ENUM_MAP_ENTRY(state, STILL_PRESSED), - MAKE_ENUM_MAP_ENTRY(state, PRESSED), - MAKE_ENUM_MAP_ENTRY(state, JUST_RELEASED), - MAKE_ENUM_MAP_ENTRY(state, STILL_RELEASED), - MAKE_ENUM_MAP_ENTRY(state, RELEASED), -}; -STATIC MP_DEFINE_CONST_DICT(keypad_state_locals_dict, keypad_state_locals_table); - -MAKE_PRINTER(keypad, keypad_state); - -// Defines keypad_state_type. -MAKE_ENUM_TYPE(keypad, State, keypad_state); diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c index 4ca66b531a..20f60a5137 100644 --- a/shared-bindings/keypad/__init__.c +++ b/shared-bindings/keypad/__init__.c @@ -27,9 +27,9 @@ #include "py/obj.h" #include "shared-bindings/keypad/__init__.h" -// #include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/Event.h" +#include "shared-bindings/keypad/KeyMatrix.h" #include "shared-bindings/keypad/Keys.h" -#include "shared-bindings/keypad/State.h" //| """Support for scanning keys and key matrices //| @@ -40,9 +40,9 @@ STATIC mp_map_elem_t keypad_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, -// { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_key_matrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) }, + { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) }, { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, - { MP_ROM_QSTR(MP_QSTR_State), MP_OBJ_FROM_PTR(&keypad_state_type) }, }; STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table); diff --git a/shared-module/keypad/Event.c b/shared-module/keypad/Event.c new file mode 100644 index 0000000000..6556d1f5a3 --- /dev/null +++ b/shared-module/keypad/Event.c @@ -0,0 +1,44 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/keypad/Event.h" + +void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_num, bool pressed) { + self->key_num = key_num; + self->pressed = true; +} + +mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self) { + return self->key_num; +} + +bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self) { + return self->pressed; +} + +bool common_hal_keypad_event_get_released(keypad_event_obj_t *self) { + return !self->pressed; +} diff --git a/shared-bindings/keypad/State.h b/shared-module/keypad/Event.h similarity index 71% rename from shared-bindings/keypad/State.h rename to shared-module/keypad/Event.h index 1b6316b001..4780df0aa2 100644 --- a/shared-bindings/keypad/State.h +++ b/shared-module/keypad/Event.h @@ -1,5 +1,5 @@ /* - * This file is part of the MicroPython project, http://micropython.org/ + * This file is part of the Micro Python project, http://micropython.org/ * * The MIT License (MIT) * @@ -24,21 +24,16 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H -#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H #include "py/obj.h" -#include "py/enum.h" -typedef enum { - STATE_JUST_PRESSED, - STATE_STILL_PRESSED, - STATE_PRESSED, - STATE_JUST_RELEASED, - STATE_STILL_RELEASED, - STATE_RELEASED, -} keypad_state_t; +typedef struct { + mp_obj_base_t base; + uint16_t key_num; + bool pressed; +} keypad_event_obj_t; -extern const mp_obj_type_t keypad_state_type; -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_STATE__H +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENT_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index c09317d1f9..582668bce9 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -25,16 +25,20 @@ */ #include "py/gc.h" -#include "py/objproperty.h" +#include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" -#include "shared-bindings/keypad/State.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "py/runtime.h" #include "supervisor/port.h" #define DEBOUNCE_TICKS (20) -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull) { +// Top bit of 16-bit event indicates pressed or released. Rest is key_num. +#define EVENT_PRESSED (1 << 15) +#define EVENT_RELEASED (0) +#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) + +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events) { mp_obj_t dios[num_pins]; for (size_t i = 0; i < num_pins; i++) { @@ -52,88 +56,60 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); self->value_when_pressed = value_when_pressed; + // Event queue is 16-bit values. + ringbuf_alloc(self->encoded_events, max_events * 2, false); } -void common_hal_keypad_keys_keys_with_state(keypad_keys_obj_t *self, int state, mp_obj_list_t *list_into) { - const size_t list_length = list_into->len; - - size_t next_list_slot = 0; - - for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { - if (next_list_slot >= list_length) { - // List is full. - break; - } - - bool store_key = false; - switch (state) { - case STATE_JUST_PRESSED: - store_key = !self->previously_pressed[key_num] && self->currently_pressed[key_num]; - break; - case STATE_STILL_PRESSED: - store_key = self->previously_pressed[key_num] && self->currently_pressed[key_num]; - break; - case STATE_PRESSED: - store_key = self->currently_pressed[key_num]; - break; - case STATE_JUST_RELEASED: - store_key = self->previously_pressed[key_num] && !self->currently_pressed[key_num]; - break; - case STATE_STILL_RELEASED: - store_key = !self->previously_pressed[key_num] && !self->currently_pressed[key_num]; - break; - case STATE_RELEASED: - store_key = !self->currently_pressed[key_num]; - break; - } - - if (store_key) { - mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(next_list_slot), - MP_OBJ_NEW_SMALL_INT(key_num)); - next_list_slot++; - } - - for (size_t unused_slot = next_list_slot; unused_slot < list_length; unused_slot++) { - mp_obj_list_store(list_into, MP_OBJ_NEW_SMALL_INT(unused_slot), - MP_ROM_NONE); - } - } -} - -size_t common_hal_keypad_keys_length(keypad_keys_obj_t *self) { +size_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self) { return self->digitalinouts->len; } -bool common_hal_keypad_keys_scan(keypad_keys_obj_t *self) { +void keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { - // Too soon. - return false; + // Too soon. Wait longer to debounce. + return; } self->last_scan_ticks = now; - for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_length(self); key_num++) { - self->previously_pressed[key_num] = self->currently_pressed[key_num]; - self->currently_pressed[key_num] = - common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_num_keys(self); key_num++) { + // Remember the previous up/down state. + const bool previous = self->currently_pressed[key_num]; + self->previously_pressed[key_num] = previous; + + // Get the current state. + const bool current = common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == self->value_when_pressed; + self->currently_pressed[key_num] = current; + + // Record any transitions. + if (previous != current) { + if (ringbuf_num_empty(self->encoded_events) == 0) { + // Discard oldest if full. + ringbuf_get16(self->encoded_events); + } + ringbuf_put16(self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + } } - return true; } -mp_int_t common_hal_keypad_keys_state(keypad_keys_obj_t *self, mp_uint_t key_num) { - if (self->currently_pressed[key_num]) { - if (self->previously_pressed[key_num]) { - return STATE_STILL_PRESSED; - } else { - return STATE_JUST_PRESSED; - } - } else { - if (self->previously_pressed[key_num]) { - return STATE_JUST_RELEASED; - } else { - return STATE_STILL_RELEASED; - } - } +bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) { + return self->currently_pressed[key_num]; +} + +mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self) { + int encoded_event = ringbuf_get16(self->encoded_events); + if (encoded_event == -1) { + return MP_ROM_NONE; + } + + keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); + self->base.type = &keypad_event_type; + common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); + return MP_OBJ_FROM_PTR(event); +} + +void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { + ringbuf_clear(self->encoded_events); } diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 898a937632..67822dd6d9 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -31,6 +31,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "py/ringbuf.h" typedef struct { mp_obj_base_t base; @@ -39,6 +40,7 @@ typedef struct { bool value_when_pressed; bool *previously_pressed; bool *currently_pressed; + ringbuf_t *encoded_events; } keypad_keys_obj_t; diff --git a/shared-module/keypad/State.c b/shared-module/keypad/State.c deleted file mode 100644 index e69de29bb2..0000000000 From 32eec8523074b298aec0ace1aa6f0833895f50e5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 14 Jun 2021 20:54:43 -0400 Subject: [PATCH 16/38] compiles --- lib/utils/linked_list.h | 36 +++++ main.c | 10 ++ py/circuitpy_mpconfig.h | 13 ++ shared-bindings/keypad/KeyMatrix.c | 228 +++++++++++++++++++++++++++++ shared-bindings/keypad/KeyMatrix.h | 49 +++++++ shared-bindings/keypad/Keys.c | 50 ++++++- shared-bindings/keypad/Keys.h | 4 +- shared-module/keypad/KeyMatrix.c | 225 ++++++++++++++++++++++++++++ shared-module/keypad/KeyMatrix.h | 51 +++++++ shared-module/keypad/Keys.c | 101 +++++++++++-- shared-module/keypad/Keys.h | 6 +- shared-module/keypad/__init__.c | 38 +++++ shared-module/keypad/__init__.h | 3 + supervisor/shared/lock.c | 51 +++++++ supervisor/shared/lock.h | 36 +++++ supervisor/shared/tick.c | 11 ++ supervisor/supervisor.mk | 1 + 17 files changed, 893 insertions(+), 20 deletions(-) create mode 100644 lib/utils/linked_list.h create mode 100644 shared-bindings/keypad/KeyMatrix.c create mode 100644 shared-bindings/keypad/KeyMatrix.h create mode 100644 shared-module/keypad/KeyMatrix.c create mode 100644 shared-module/keypad/KeyMatrix.h create mode 100644 supervisor/shared/lock.c create mode 100644 supervisor/shared/lock.h diff --git a/lib/utils/linked_list.h b/lib/utils/linked_list.h new file mode 100644 index 0000000000..cd5ea0fc7c --- /dev/null +++ b/lib/utils/linked_list.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_LINKED_LIST_H +#define MICROPY_INCLUDED_LINKED_LIST_H + +#define LINKED_LIST_PREPEND(LIST_HEAD, OBJECT, NEXT_FIELD) \ + OBJECT->NEXT_FIELD = LIST_HEAD; \ + LIST_HEAD = OBJECT; + +#define LINKED_LIST_DELETE(LIST_HEAD, OBJECT, + +#endif // MICROPY_INCLUDED_LINKED_LIST_H diff --git a/main.c b/main.c index 94d35fb8d7..a11157a5fb 100755 --- a/main.c +++ b/main.c @@ -86,6 +86,10 @@ #include "shared-module/displayio/__init__.h" #endif +#if CIRCUITPY_KEYPAD +#include "shared-module/keypad/__init__.h" +#endif + #if CIRCUITPY_MEMORYMONITOR #include "shared-module/memorymonitor/__init__.h" #endif @@ -230,9 +234,11 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) { #if CIRCUITPY_DISPLAYIO reset_displays(); #endif + #if CIRCUITPY_MEMORYMONITOR memorymonitor_reset(); #endif + filesystem_flush(); stop_mp(); free_memory(heap); @@ -242,6 +248,10 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) { common_hal_canio_reset(); #endif + #if CIRCUITPY_KEYPAD + keypad_reset(); + #endif + // reset_board_busses() first because it may release pins from the never_reset state, so that // reset_port() can reset them. #if CIRCUITPY_BOARD diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 86321d5d02..4b6585c2a4 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -533,8 +533,20 @@ extern const struct _mp_obj_module_t ipaddress_module; #if CIRCUITPY_KEYPAD extern const struct _mp_obj_module_t keypad_module; #define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module }, +#define KEYPAD_ROOT_POINTERS \ + mp_obj_t keypad_keys_linked_list; \ + mp_obj_t keypad_keymatrix_linked_list; #else #define KEYPAD_MODULE +#define KEYPAD_ROOT_POINTERS +#endif + +#if CIRCUITPY_GAMEPAD || CIRCUITPY_GAMEPADSHIFT +// Scan gamepad every 32ms +#define CIRCUITPY_GAMEPAD_TICKS 0x1f +#define GAMEPAD_ROOT_POINTERS mp_obj_t gamepad_singleton; +#else +#define GAMEPAD_ROOT_POINTERS #endif #if CIRCUITPY_MATH @@ -962,6 +974,7 @@ struct _supervisor_allocation_node; vstr_t *repl_line; \ mp_obj_t rtc_time_source; \ GAMEPAD_ROOT_POINTERS \ + KEYPAD_ROOT_POINTERS \ mp_obj_t pew_singleton; \ BOARD_UART_ROOT_POINTER \ FLASH_ROOT_POINTERS \ diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c new file mode 100644 index 0000000000..b6b09a9a0a --- /dev/null +++ b/shared-bindings/keypad/KeyMatrix.c @@ -0,0 +1,228 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "shared-bindings/keypad/Event.h" +#include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" + +//| class KeyMatrix: +//| """Manage a 2D matrix of keys with row and column pins.""" +//| +//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], max_events: int = 16) -> None: +//| """ +//| Create a `Keys` object that will scan key matrix attached to the given row and column pins. +//| If the matrix uses diodes, the diode anodes should be connected to the column pins, +//| and the cathodes should be connected to the row pins. +//| +//| The keys are numbered sequentially from zero. A key number can be computed +//| by ``col * len(row_pins) + row``. +//| +//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to rows. +//| :param Sequence[microcontroller.Pin] col_pins: The pins attached to rows. +//| :param int max_events: Size of key event queue: +//| maximum number of key transition events that are saved. +//| Must be >= 1. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| """ +//| ... + +STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t); + self->base.type = &keypad_keymatrix_type; + enum { ARG_row_pins, ARG_col_pins, ARG_max_events }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + }; + 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 row_pins = args[ARG_row_pins].u_obj; + // mp_obj_len() will be >= 0. + const size_t num_row_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_pins)); + + mp_obj_t col_pins = args[ARG_col_pins].u_obj; + const size_t num_col_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(col_pins)); + + if (args[ARG_max_events].u_int < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); + } + const size_t max_events = (size_t)args[ARG_max_events].u_int; + + mcu_pin_obj_t *row_pins_array[num_row_pins]; + mcu_pin_obj_t *col_pins_array[num_col_pins]; + + for (mp_uint_t i = 0; i < num_row_pins; i++) { + mcu_pin_obj_t *pin = + validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + row_pins_array[i] = pin; + } + + for (mp_uint_t i = 0; i < num_col_pins; i++) { + mcu_pin_obj_t *pin = + validate_obj_is_free_pin(mp_obj_subscr(col_pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + col_pins_array[i] = pin; + } + + common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, max_events); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Stop scanning and release the pins.""" +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_deinit(mp_obj_t self_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_keypad_keymatrix_deinit(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_deinit_obj, keypad_keymatrix_deinit); + +//| def __enter__(self) -> KeyMatrix: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t keypad_keymatrix___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_keypad_keymatrix_deinit(args[0]); + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keymatrix___exit___obj, 4, 4, keypad_keymatrix___exit__); + +STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { + if (common_hal_keypad_keymatrix_deinited(self)) { + raise_deinited_error(); + } +} + +//| def next_event(self) -> Optional[Event]: +//| """Return the next key transition event. Return ``None` if no events are pending. +//| +//| Note that the queue size is limited; see ``max_events`` in the constructor. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| +//| :return: the next queued key transition `Event` +//| :rtype: Optional[Event] +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_next_event(mp_obj_t self_in, mp_obj_t event_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + return common_hal_keypad_keymatrix_next_event(self); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_next_event_obj, keypad_keymatrix_next_event); + +//| def clear_events(self) -> None: +//| """Clear any queued key transition events. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_clear_events(mp_obj_t self_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + common_hal_keypad_keymatrix_clear_events(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_clear_events_obj, keypad_keymatrix_clear_events); + +//| def pressed(self, key_num: int) -> None: +//| """Return ``True`` if the given key is pressed. This is a debounced read +//| of the key state which bypasses the event queue. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_int_t key_num = mp_obj_get_int(key_num_in); + if (key_num < 0 || key_num >= common_hal_keypad_keymatrix_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed); + +//| def key_num(self, row: int, col: int) -> int: +//| """Return the key number for a given row and column. +//| The key number is calculated by `row * number_of_columns + col`. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t col_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + const mp_int_t row = mp_obj_get_int(row_in); + if (row < 0 || row >= common_hal_keypad_keymatrix_num_rows(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_row_num); + } + + const mp_int_t col = mp_obj_get_int(col_in); + if (col < 0 || col >= common_hal_keypad_keymatrix_num_cols(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_col_num); + } + + return MP_OBJ_NEW_SMALL_INT( + (mp_int_t)common_hal_keypad_keymatrix_key_num(self, (mp_uint_t)row, (mp_uint_t)col)); +} +MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_key_num_obj, keypad_keymatrix_key_num); + +STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_clear_events), MP_ROM_PTR(&keypad_keymatrix_clear_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_keymatrix_key_num_obj) }, + { MP_ROM_QSTR(MP_QSTR_next_event), MP_ROM_PTR(&keypad_keymatrix_next_event_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table); + +const mp_obj_type_t keypad_keymatrix_type = { + { &mp_type_type }, + .name = MP_QSTR_Keys, + .make_new = keypad_keymatrix_make_new, + .locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict, +}; diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h new file mode 100644 index 0000000000..f0ce8761bc --- /dev/null +++ b/shared-bindings/keypad/KeyMatrix.h @@ -0,0 +1,49 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H + +#include "py/objlist.h" +#include "shared-module/keypad/KeyMatrix.h" + +extern const mp_obj_type_t keypad_keymatrix_type; + +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events); +void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); +bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); + +mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col); + +mp_uint_t common_hal_keypad_keymatrix_num_keys(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_num_rows(keypad_keymatrix_obj_t *self); + +bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num); +mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self); +void common_hal_keypad_keymatrix_clear_events(keypad_keymatrix_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index e92d91ce14..a54cff0ba9 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -24,10 +24,12 @@ * THE SOFTWARE. */ +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" #include "shared-bindings/microcontroller/Pin.h" -#include "py/runtime.h" +#include "shared-bindings/util.h" //| class Keys: //| """Manage a set of independent keys.""" @@ -88,9 +90,46 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c } common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, max_events); + return MP_OBJ_FROM_PTR(self); } +//| def deinit(self) -> None: +//| """Stop scanning and release the pins.""" +//| ... +//| +STATIC mp_obj_t keypad_keys_deinit(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keys_deinit(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_deinit_obj, keypad_keys_deinit); + +//| def __enter__(self) -> Keys: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t keypad_keys___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_keypad_keys_deinit(args[0]); + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keys___exit___obj, 4, 4, keypad_keys___exit__); + +STATIC void check_for_deinit(keypad_keys_obj_t *self) { + if (common_hal_keypad_keys_deinited(self)) { + raise_deinited_error(); + } +} + //| def next_event(self) -> Optional[Event]: //| """Return the next key transition event. Return ``None` if no events are pending. //| @@ -104,6 +143,8 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c //| STATIC mp_obj_t keypad_keys_next_event(mp_obj_t self_in, mp_obj_t event_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_keypad_keys_next_event(self); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_next_event_obj, keypad_keys_next_event); @@ -115,6 +156,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_next_event_obj, keypad_keys_next_event); //| STATIC mp_obj_t keypad_keys_clear_events(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); common_hal_keypad_keys_clear_events(self); return MP_ROM_NONE; @@ -129,6 +171,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_clear_events_obj, keypad_keys_clear_events //| STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + mp_int_t key_num = mp_obj_get_int(key_num_in); if (key_num < 0 || key_num >= common_hal_keypad_keys_num_keys(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); @@ -139,6 +183,10 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_events), MP_ROM_PTR(&keypad_keys_clear_events_obj) }, { MP_ROM_QSTR(MP_QSTR_next_event), MP_ROM_PTR(&keypad_keys_next_event_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index e9ab0b91e5..f7ec2302d8 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -33,6 +33,8 @@ extern const mp_obj_type_t keypad_keys_type; void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events); +void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); +bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); mp_uint_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self); bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); @@ -40,6 +42,4 @@ bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self); void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self); -void keypad_keys_scan(keypad_keys_obj_t *self); - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c new file mode 100644 index 0000000000..4164de050f --- /dev/null +++ b/shared-module/keypad/KeyMatrix.c @@ -0,0 +1,225 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/keypad/Event.h" +#include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" +#include "supervisor/shared/lock.h" +#include "supervisor/shared/tick.h" + +static supervisor_lock_t keypad_keymatrix_linked_list_lock; + +#define DEBOUNCE_TICKS (20) + +// Top bit of 16-bit event indicates pressed or released. Rest is key_num. +#define EVENT_PRESSED (1 << 15) +#define EVENT_RELEASED (0) +#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) + +static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { + return row * self->col_digitalinouts->len + col; +} + +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events) { + + mp_obj_t row_dios[num_row_pins]; + for (size_t i = 0; i < num_row_pins; i++) { + digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); + dio->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(dio, row_pins[i]); + common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); + row_dios[i] = dio; + } + self->row_digitalinouts = mp_obj_new_tuple(num_col_pins, row_dios); + + mp_obj_t col_dios[num_col_pins]; + for (size_t i = 0; i < num_col_pins; i++) { + digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); + dio->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(dio, col_pins[i]); + common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); + col_dios[i] = dio; + } + self->col_digitalinouts = mp_obj_new_tuple(num_row_pins, col_dios); + + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); + + // Event queue is 16-bit values. + ringbuf_alloc(self->encoded_events, max_events * 2, false); + + // Add self to the list of active Keys objects. + + supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock); + self->next = MP_STATE_VM(keypad_keymatrix_linked_list); + MP_STATE_VM(keypad_keymatrix_linked_list) = self; + supervisor_release_lock(&keypad_keymatrix_linked_list_lock); +} + +void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { + if (common_hal_keypad_keymatrix_deinited(self)) { + return; + } + + for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) { + common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]); + } + self->row_digitalinouts = MP_ROM_NONE; + + for (size_t col = 0; col < common_hal_keypad_keymatrix_num_cols(self); col++) { + common_hal_digitalio_digitalinout_deinit(self->col_digitalinouts->items[col]); + } + self->col_digitalinouts = MP_ROM_NONE; + + // Remove self from the list of active KeyMatrix objects. + + supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock); + if (MP_STATE_VM(keypad_keymatrix_linked_list) == self) { + // I'm at the front; splice myself out. + MP_STATE_VM(keypad_keymatrix_linked_list) = self->next; + } else { + keypad_keymatrix_obj_t *current = MP_STATE_VM(keypad_keymatrix_linked_list); + while (current) { + if (current->next == self) { + // Splice myself out. + current->next = self->next; + break; + } + current = current->next; + } + } + supervisor_release_lock(&keypad_keymatrix_linked_list_lock); +} + +bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) { + return self->row_digitalinouts == MP_ROM_NONE; +} + +size_t common_hal_keypad_keymatrix_num_keys(keypad_keymatrix_obj_t *self) { + return common_hal_keypad_keymatrix_num_rows(self) * common_hal_keypad_keymatrix_num_cols(self); +} + +size_t common_hal_keypad_keymatrix_num_rows(keypad_keymatrix_obj_t *self) { + return self->row_digitalinouts->len; +} + +size_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self) { + return self->col_digitalinouts->len; +} + +bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num) { + return self->currently_pressed[key_num]; +} + +mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self) { + int encoded_event = ringbuf_get16(self->encoded_events); + if (encoded_event == -1) { + return MP_ROM_NONE; + } + + keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); + self->base.type = &keypad_event_type; + common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); + return MP_OBJ_FROM_PTR(event); +} + +void common_hal_keypad_keymatrix_clear_events(keypad_keymatrix_obj_t *self) { + ringbuf_clear(self->encoded_events); +} + +mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { + return row_col_to_key_num(self, row, col); +} + +static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { + uint64_t now = port_get_raw_ticks(NULL); + if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { + // Too soon. Wait longer to debounce. + return; + } + + self->last_scan_ticks = now; + + // On entry, all pins are set to inputs with a pull-up. + for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) { + // Switch this row to an output and set to low. + common_hal_digitalio_digitalinout_switch_to_output( + self->row_digitalinouts->items[row], false, DRIVE_MODE_PUSH_PULL); + + for (size_t col = 0; col < common_hal_keypad_keymatrix_num_cols(self); col++) { + mp_uint_t key_num = row_col_to_key_num(self, row, col); + const bool previous = self->currently_pressed[key_num]; + self->previously_pressed[key_num] = previous; + + // Get the current state, by reading whether the col got pulled down or not. + const bool current = + common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[key_num]); + self->currently_pressed[key_num] = current; + + // Record any transitions. + if (previous != current) { + if (ringbuf_num_empty(self->encoded_events) == 0) { + // Discard oldest if full. + ringbuf_get16(self->encoded_events); + } + ringbuf_put16(self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + } + + } + + // Switch the row back to an input, pulled up. + common_hal_digitalio_digitalinout_switch_to_input(self->row_digitalinouts->items[row], PULL_UP); + } +} + +void keypad_keymatrix_tick(void) { + // Fast path. + if (!MP_STATE_VM(keypad_keymatrix_linked_list)) { + return; + } + + if (supervisor_try_lock(&keypad_keymatrix_linked_list_lock)) { + keypad_keymatrix_obj_t *keypad_keymatrix = MP_STATE_VM(keypad_keymatrix_linked_list); + while (keypad_keymatrix) { + keypad_keymatrix_scan(keypad_keymatrix); + keypad_keymatrix = keypad_keymatrix->next; + } + supervisor_release_lock(&keypad_keymatrix_linked_list_lock); + } +} + +void keypad_keymatrix_reset(void) { + if (MP_STATE_VM(keypad_keymatrix_linked_list)) { + supervisor_disable_tick(); + } + + MP_STATE_VM(keypad_keys_linked_list) = NULL; + keypad_keymatrix_linked_list_lock = false; +} diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h new file mode 100644 index 0000000000..d598f3941e --- /dev/null +++ b/shared-module/keypad/KeyMatrix.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H + +#include "common-hal/digitalio/DigitalInOut.h" + +#include "py/obj.h" +#include "py/objtuple.h" +#include "py/ringbuf.h" + +typedef struct _keypad_keymatrix_obj_t { + mp_obj_base_t base; + mp_obj_tuple_t *row_digitalinouts; + mp_obj_tuple_t *col_digitalinouts; + uint64_t last_scan_ticks; + bool *previously_pressed; + bool *currently_pressed; + ringbuf_t *encoded_events; + // Keep a linked list of active KeyMatrix objects. + struct _keypad_keymatrix_obj_t *next; +} keypad_keymatrix_obj_t; + +void keypad_keymatrix_tick(); +void keypad_keymatrix_reset(); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 582668bce9..d7e0288907 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -25,11 +25,15 @@ */ #include "py/gc.h" +#include "py/runtime.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" #include "shared-bindings/digitalio/DigitalInOut.h" -#include "py/runtime.h" #include "supervisor/port.h" +#include "supervisor/shared/lock.h" +#include "supervisor/shared/tick.h" + +static supervisor_lock_t keypad_keys_linked_list_lock; #define DEBOUNCE_TICKS (20) @@ -58,13 +62,73 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin // Event queue is 16-bit values. ringbuf_alloc(self->encoded_events, max_events * 2, false); + + // Add self to the list of active Keys objects. + + supervisor_acquire_lock(&keypad_keys_linked_list_lock); + self->next = MP_STATE_VM(keypad_keys_linked_list); + MP_STATE_VM(keypad_keys_linked_list) = self; + supervisor_release_lock(&keypad_keys_linked_list_lock); +} + +void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) { + if (common_hal_keypad_keys_deinited(self)) { + return; + } + + for (size_t key = 0; key < common_hal_keypad_keys_num_keys(self); key++) { + common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]); + } + self->digitalinouts = MP_ROM_NONE; + + // Remove self from the list of active Keys objects. + + supervisor_acquire_lock(&keypad_keys_linked_list_lock); + if (MP_STATE_VM(keypad_keys_linked_list) == self) { + // I'm at the front; splice myself out. + MP_STATE_VM(keypad_keys_linked_list) = self->next; + } else { + keypad_keys_obj_t *current = MP_STATE_VM(keypad_keys_linked_list); + while (current) { + if (current->next == self) { + // Splice myself out. + current->next = self->next; + break; + } + current = current->next; + } + } + supervisor_release_lock(&keypad_keys_linked_list_lock); +} + +bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) { + return self->digitalinouts == MP_ROM_NONE; } size_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self) { return self->digitalinouts->len; } +bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) { + return self->currently_pressed[key_num]; +} -void keypad_keys_scan(keypad_keys_obj_t *self) { +mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self) { + int encoded_event = ringbuf_get16(self->encoded_events); + if (encoded_event == -1) { + return MP_ROM_NONE; + } + + keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); + self->base.type = &keypad_event_type; + common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); + return MP_OBJ_FROM_PTR(event); +} + +void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { + ringbuf_clear(self->encoded_events); +} + +static void keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { // Too soon. Wait longer to debounce. @@ -94,22 +158,27 @@ void keypad_keys_scan(keypad_keys_obj_t *self) { } } -bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) { - return self->currently_pressed[key_num]; -} - -mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self) { - int encoded_event = ringbuf_get16(self->encoded_events); - if (encoded_event == -1) { - return MP_ROM_NONE; +void keypad_keys_tick(void) { + // Fast path. + if (!MP_STATE_VM(keypad_keys_linked_list)) { + return; } - keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); - self->base.type = &keypad_event_type; - common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); - return MP_OBJ_FROM_PTR(event); + if (supervisor_try_lock(&keypad_keys_linked_list_lock)) { + keypad_keys_obj_t *keypad_keys = MP_STATE_VM(keypad_keys_linked_list); + while (keypad_keys) { + keypad_keys_scan(keypad_keys); + keypad_keys = keypad_keys->next; + } + supervisor_release_lock(&keypad_keys_linked_list_lock); + } } -void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { - ringbuf_clear(self->encoded_events); +void keypad_keys_reset(void) { + if (MP_STATE_VM(keypad_keys_linked_list)) { + supervisor_disable_tick(); + } + + MP_STATE_VM(keypad_keys_linked_list) = NULL; + keypad_keys_linked_list_lock = false; } diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 67822dd6d9..556f465a98 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -33,7 +33,7 @@ #include "py/objtuple.h" #include "py/ringbuf.h" -typedef struct { +typedef struct _keypad_keys_obj_t { mp_obj_base_t base; mp_obj_tuple_t *digitalinouts; uint64_t last_scan_ticks; @@ -41,7 +41,11 @@ typedef struct { bool *previously_pressed; bool *currently_pressed; ringbuf_t *encoded_events; + // Keep a linked list of active Keys objects. + struct _keypad_keys_obj_t *next; } keypad_keys_obj_t; +void keypad_keys_tick(); +void keypad_keys_reset(); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index e69de29bb2..9b08dc9bb5 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/keypad/Keys.h" +#include "shared-module/keypad/KeyMatrix.h" + +void keypad_tick(void) { + keypad_keys_tick(); + keypad_keymatrix_tick(); +} + +void keypad_reset(void) { + keypad_keys_reset(); + keypad_keymatrix_reset(); +} diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h index 4220a3df63..2dc3fdca8e 100644 --- a/shared-module/keypad/__init__.h +++ b/shared-module/keypad/__init__.h @@ -27,4 +27,7 @@ #ifndef SHARED_MODULE_KEYPAD_H #define SHARED_MODULE_KEYPAD_H +void keypad_tick(void); +void keypad_reset(void); + #endif // SHARED_MODULE_KEYPAD_H diff --git a/supervisor/shared/lock.c b/supervisor/shared/lock.c new file mode 100644 index 0000000000..36971badad --- /dev/null +++ b/supervisor/shared/lock.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/__init__.h" +#include "supervisor/shared/lock.h" + +void supervisor_acquire_lock(supervisor_lock_t *lock) { + while (!supervisor_try_lock(lock)) { + RUN_BACKGROUND_TASKS; + } +} + +bool supervisor_try_lock(supervisor_lock_t *lock) { + bool grabbed_lock = false; + common_hal_mcu_disable_interrupts(); + if (!*lock) { + *lock = true; + grabbed_lock = true; + } + common_hal_mcu_enable_interrupts(); + return grabbed_lock; +} + +void supervisor_release_lock(supervisor_lock_t *lock) { + common_hal_mcu_disable_interrupts(); + *lock = false; + common_hal_mcu_enable_interrupts(); +} diff --git a/supervisor/shared/lock.h b/supervisor/shared/lock.h new file mode 100644 index 0000000000..89f81cfdfb --- /dev/null +++ b/supervisor/shared/lock.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SUPERVISOR_LOCK_H +#define MICROPY_INCLUDED_SUPERVISOR_LOCK_H + +typedef volatile bool supervisor_lock_t; + +void supervisor_acquire_lock(supervisor_lock_t *lock); +bool supervisor_try_lock(supervisor_lock_t *lock); +void supervisor_release_lock(supervisor_lock_t *lock); + +#endif // MICROPY_INCLUDED_SUPERVISOR_LOCK_H diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index f40151988e..77cdf8aba2 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -53,6 +53,10 @@ #include "shared-module/gamepadshift/__init__.h" #endif +#if CIRCUITPY_KEYPAD +#include "shared-module/keypad/__init__.h" +#endif + #if CIRCUITPY_NETWORK #include "shared-module/network/__init__.h" #endif @@ -108,9 +112,11 @@ void supervisor_tick(void) { #if CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS > 0 filesystem_tick(); #endif + #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS autoreload_tick(); #endif + #ifdef CIRCUITPY_GAMEPAD_TICKS if (!(port_get_raw_ticks(NULL) & CIRCUITPY_GAMEPAD_TICKS)) { #if CIRCUITPY_GAMEPAD @@ -121,6 +127,11 @@ void supervisor_tick(void) { #endif } #endif + + #if CIRCUITPY_KEYPAD + keypad_tick(); + #endif + background_callback_add(&tick_callback, supervisor_background_tasks, NULL); } diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 0815a9ffc4..d32436cdb0 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -7,6 +7,7 @@ SRC_SUPERVISOR = \ supervisor/shared/cpu.c \ supervisor/shared/filesystem.c \ supervisor/shared/flash.c \ + supervisor/shared/lock.c \ supervisor/shared/memory.c \ supervisor/shared/micropython.c \ supervisor/shared/safe_mode.c \ From 350652ee214a0c3fed1c6c3394886728a48a9fa8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 14 Jun 2021 22:59:17 -0400 Subject: [PATCH 17/38] Keys works; more testing to do --- shared-bindings/keypad/Event.c | 10 +++++++++- shared-bindings/keypad/Event.h | 2 +- shared-bindings/keypad/KeyMatrix.c | 6 +++--- shared-bindings/keypad/Keys.c | 6 +++--- shared-module/keypad/Event.c | 2 +- shared-module/keypad/KeyMatrix.c | 12 ++++++------ shared-module/keypad/KeyMatrix.h | 6 +++--- shared-module/keypad/Keys.c | 21 ++++++++++++--------- shared-module/keypad/Keys.h | 6 +++--- 9 files changed, 41 insertions(+), 30 deletions(-) diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 218da5b82e..787b09d83b 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -117,9 +117,17 @@ STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = { }; STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table); +STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "", + common_hal_keypad_event_get_key_num(self), + common_hal_keypad_event_get_pressed(self) ? "pressed" : "released"); +} + const mp_obj_type_t keypad_event_type = { { &mp_type_type }, - .name = MP_QSTR_UART, + .name = MP_QSTR_Event, .make_new = keypad_event_make_new, + .print = keypad_event_print, .locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict, }; diff --git a/shared-bindings/keypad/Event.h b/shared-bindings/keypad/Event.h index 03e04eb6ee..23017f1dc5 100644 --- a/shared-bindings/keypad/Event.h +++ b/shared-bindings/keypad/Event.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_event_type; -void common_hal_keypad_event_construct(keypad_event_obj_t *self, uint16_t key_num, bool pressed); +void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_num, bool pressed); mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self); bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self); bool common_hal_keypad_event_get_released(keypad_event_obj_t *self); diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index b6b09a9a0a..4e2038aa37 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -174,7 +174,7 @@ STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) check_for_deinit(self); mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || key_num >= common_hal_keypad_keymatrix_num_keys(self)) { + if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keymatrix_num_keys(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); } @@ -193,12 +193,12 @@ STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_o check_for_deinit(self); const mp_int_t row = mp_obj_get_int(row_in); - if (row < 0 || row >= common_hal_keypad_keymatrix_num_rows(self)) { + if (row < 0 || (size_t)row >= common_hal_keypad_keymatrix_num_rows(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_row_num); } const mp_int_t col = mp_obj_get_int(col_in); - if (col < 0 || col >= common_hal_keypad_keymatrix_num_cols(self)) { + if (col < 0 || (size_t)col >= common_hal_keypad_keymatrix_num_cols(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_col_num); } diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index a54cff0ba9..849e2a639e 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -141,13 +141,13 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { //| """ //| ... //| -STATIC mp_obj_t keypad_keys_next_event(mp_obj_t self_in, mp_obj_t event_in) { +STATIC mp_obj_t keypad_keys_next_event(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); return common_hal_keypad_keys_next_event(self); } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_next_event_obj, keypad_keys_next_event); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_next_event_obj, keypad_keys_next_event); //| def clear_events(self) -> None: //| """Clear any queued key transition events. @@ -174,7 +174,7 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { check_for_deinit(self); mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || key_num >= common_hal_keypad_keys_num_keys(self)) { + if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keys_num_keys(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); } diff --git a/shared-module/keypad/Event.c b/shared-module/keypad/Event.c index 6556d1f5a3..21b4ad18d3 100644 --- a/shared-module/keypad/Event.c +++ b/shared-module/keypad/Event.c @@ -28,7 +28,7 @@ void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_num, bool pressed) { self->key_num = key_num; - self->pressed = true; + self->pressed = pressed; } mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self) { diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 4164de050f..04cb84facb 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -73,7 +73,7 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); // Event queue is 16-bit values. - ringbuf_alloc(self->encoded_events, max_events * 2, false); + ringbuf_alloc(&self->encoded_events, max_events * 2, false); // Add self to the list of active Keys objects. @@ -139,7 +139,7 @@ bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t } mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self) { - int encoded_event = ringbuf_get16(self->encoded_events); + int encoded_event = ringbuf_get16(&self->encoded_events); if (encoded_event == -1) { return MP_ROM_NONE; } @@ -151,7 +151,7 @@ mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self) { } void common_hal_keypad_keymatrix_clear_events(keypad_keymatrix_obj_t *self) { - ringbuf_clear(self->encoded_events); + ringbuf_clear(&self->encoded_events); } mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { @@ -185,11 +185,11 @@ static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { // Record any transitions. if (previous != current) { - if (ringbuf_num_empty(self->encoded_events) == 0) { + if (ringbuf_num_empty(&self->encoded_events) == 0) { // Discard oldest if full. - ringbuf_get16(self->encoded_events); + ringbuf_get16(&self->encoded_events); } - ringbuf_put16(self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + ringbuf_put16(&self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); } } diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index d598f3941e..2051536898 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -40,12 +40,12 @@ typedef struct _keypad_keymatrix_obj_t { uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; - ringbuf_t *encoded_events; + ringbuf_t encoded_events; // Keep a linked list of active KeyMatrix objects. struct _keypad_keymatrix_obj_t *next; } keypad_keymatrix_obj_t; -void keypad_keymatrix_tick(); -void keypad_keymatrix_reset(); +void keypad_keymatrix_tick(void); +void keypad_keymatrix_reset(void); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index d7e0288907..84e77e91eb 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -59,9 +59,10 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); self->value_when_pressed = value_when_pressed; + self->last_scan_ticks = port_get_raw_ticks(NULL); // Event queue is 16-bit values. - ringbuf_alloc(self->encoded_events, max_events * 2, false); + ringbuf_alloc(&self->encoded_events, max_events * 2, false); // Add self to the list of active Keys objects. @@ -69,6 +70,8 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->next = MP_STATE_VM(keypad_keys_linked_list); MP_STATE_VM(keypad_keys_linked_list) = self; supervisor_release_lock(&keypad_keys_linked_list_lock); + + supervisor_enable_tick(); } void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) { @@ -113,19 +116,19 @@ bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) } mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self) { - int encoded_event = ringbuf_get16(self->encoded_events); + int encoded_event = ringbuf_get16(&self->encoded_events); if (encoded_event == -1) { return MP_ROM_NONE; } keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); - self->base.type = &keypad_event_type; + event->base.type = &keypad_event_type; common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); return MP_OBJ_FROM_PTR(event); } void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { - ringbuf_clear(self->encoded_events); + ringbuf_clear(&self->encoded_events); } static void keypad_keys_scan(keypad_keys_obj_t *self) { @@ -143,17 +146,17 @@ static void keypad_keys_scan(keypad_keys_obj_t *self) { self->previously_pressed[key_num] = previous; // Get the current state. - const bool current = common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + const bool current = + common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == self->value_when_pressed; self->currently_pressed[key_num] = current; - // Record any transitions. if (previous != current) { - if (ringbuf_num_empty(self->encoded_events) == 0) { + if (ringbuf_num_empty(&self->encoded_events) == 0) { // Discard oldest if full. - ringbuf_get16(self->encoded_events); + ringbuf_get16(&self->encoded_events); } - ringbuf_put16(self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + ringbuf_put16(&self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); } } } diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 556f465a98..ecf8165b9e 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -40,12 +40,12 @@ typedef struct _keypad_keys_obj_t { bool value_when_pressed; bool *previously_pressed; bool *currently_pressed; - ringbuf_t *encoded_events; + ringbuf_t encoded_events; // Keep a linked list of active Keys objects. struct _keypad_keys_obj_t *next; } keypad_keys_obj_t; -void keypad_keys_tick(); -void keypad_keys_reset(); +void keypad_keys_tick(void); +void keypad_keys_reset(void); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H From 1803a6a71d84822d59e0c8fadb613f78675d9549 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 15 Jun 2021 11:15:09 -0400 Subject: [PATCH 18/38] both Keys and KeyMatrix work --- shared-bindings/keypad/Event.c | 67 ++++++++++++++++++++++++++---- shared-bindings/keypad/KeyMatrix.c | 39 +++++++++-------- shared-bindings/keypad/Keys.c | 8 ++-- shared-module/keypad/KeyMatrix.c | 23 +++++----- 4 files changed, 97 insertions(+), 40 deletions(-) diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 787b09d83b..807f0c6af5 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -78,7 +78,9 @@ const mp_obj_property_t keypad_event_key_num_obj = { }; //| pressed: bool -//| """True if event represents a key down (pressed) transition.""" +//| """True if event represents a key down (pressed) transition. +//| The opposite of `released`. +//| """ //| STATIC mp_obj_t keypad_event_obj_get_pressed(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -94,7 +96,9 @@ const mp_obj_property_t keypad_event_pressed_obj = { }; //| released: bool -//| """True if event represents a key up (released) transition.""" +//| """True if event represents a key up (released) transition. +//| The opposite of `pressed`. +//| """ //| STATIC mp_obj_t keypad_event_obj_get_released(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -109,13 +113,48 @@ const mp_obj_property_t keypad_event_released_obj = { MP_ROM_NONE}, }; -STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = { - // Properties - { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_event_key_num_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table); +//| def __eq__(self, other: object) -> bool: +//| """Two Event objects are equal if their `key_num` +//| and `pressed`/`released` values are equal. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + case MP_BINARY_OP_EQUAL: + if (mp_obj_is_type(rhs_in, &keypad_event_type)) { + keypad_event_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); + keypad_event_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); + return mp_obj_new_bool( + (common_hal_keypad_event_get_key_num(lhs) == + common_hal_keypad_event_get_key_num(rhs)) && + (common_hal_keypad_event_get_pressed(lhs) == + common_hal_keypad_event_get_pressed(rhs))); + } else { + return mp_const_false; + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +//| def __hash__(self) -> int: +//| """Returns a hash for the Event, so it can be used in dictionaries, etc..""" +//| ... +//| +STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + keypad_event_obj_t *self = MP_OBJ_TO_PTR(self); + switch (op) { + case MP_UNARY_OP_HASH: { + const mp_int_t key_num = common_hal_keypad_event_get_key_num(self); + const bool pressed = common_hal_keypad_event_get_pressed(self); + return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_num); + } + default: + return MP_OBJ_NULL; // op not supported + } +} STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -124,10 +163,20 @@ STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_pri common_hal_keypad_event_get_pressed(self) ? "pressed" : "released"); } +STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = { + // Properties + { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_event_key_num_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table); + const mp_obj_type_t keypad_event_type = { { &mp_type_type }, .name = MP_QSTR_Event, .make_new = keypad_event_make_new, .print = keypad_event_print, + .unary_op = keypad_event_unary_op, + .binary_op = keypad_event_binary_op, .locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict, }; diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 4e2038aa37..5820c9ea39 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -34,17 +34,20 @@ //| class KeyMatrix: //| """Manage a 2D matrix of keys with row and column pins.""" //| -//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], max_events: int = 16) -> None: +//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], max_events: int = 64) -> None: //| """ -//| Create a `Keys` object that will scan key matrix attached to the given row and column pins. +//| Create a `Keys` object that will scan the key matrix attached to the given row and column pins. //| If the matrix uses diodes, the diode anodes should be connected to the column pins, -//| and the cathodes should be connected to the row pins. +//| and the cathodes should be connected to the row pins. If your diodes are reversed, +//| simply exchange the row and column pin sequences. //| //| The keys are numbered sequentially from zero. A key number can be computed -//| by ``col * len(row_pins) + row``. +//| by ``row * len(col_pins) + col``. //| -//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to rows. -//| :param Sequence[microcontroller.Pin] col_pins: The pins attached to rows. +//| The keys are debounced by waiting about 20 msecs before reporting a transition. +//| +//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows. +//| :param Sequence[microcontroller.Pin] col_pins: The pins attached to the colums. //| :param int max_events: Size of key event queue: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -58,8 +61,8 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar enum { ARG_row_pins, ARG_col_pins, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, - { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -79,16 +82,16 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar mcu_pin_obj_t *row_pins_array[num_row_pins]; mcu_pin_obj_t *col_pins_array[num_col_pins]; - for (mp_uint_t i = 0; i < num_row_pins; i++) { + for (size_t row = 0; row < num_row_pins; row++) { mcu_pin_obj_t *pin = - validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); - row_pins_array[i] = pin; + validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(row), MP_OBJ_SENTINEL)); + row_pins_array[row] = pin; } - for (mp_uint_t i = 0; i < num_col_pins; i++) { + for (size_t col = 0; col < num_col_pins; col++) { mcu_pin_obj_t *pin = - validate_obj_is_free_pin(mp_obj_subscr(col_pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); - col_pins_array[i] = pin; + validate_obj_is_free_pin(mp_obj_subscr(col_pins, MP_OBJ_NEW_SMALL_INT(col), MP_OBJ_SENTINEL)); + col_pins_array[col] = pin; } common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, max_events); @@ -131,7 +134,7 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { } //| def next_event(self) -> Optional[Event]: -//| """Return the next key transition event. Return ``None` if no events are pending. +//| """Return the next key transition event. Return ``None`` if no events are pending. //| //| Note that the queue size is limited; see ``max_events`` in the constructor. //| If a new event arrives when the queue is full, the oldest event is discarded. @@ -141,13 +144,13 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { //| """ //| ... //| -STATIC mp_obj_t keypad_keymatrix_next_event(mp_obj_t self_in, mp_obj_t event_in) { +STATIC mp_obj_t keypad_keymatrix_next_event(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); return common_hal_keypad_keymatrix_next_event(self); } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_next_event_obj, keypad_keymatrix_next_event); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_next_event_obj, keypad_keymatrix_next_event); //| def clear_events(self) -> None: //| """Clear any queued key transition events. @@ -184,7 +187,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed //| def key_num(self, row: int, col: int) -> int: //| """Return the key number for a given row and column. -//| The key number is calculated by `row * number_of_columns + col`. +//| The key number is calculated by ``row * len(col_pins) + col``. //| """ //| ... //| diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 849e2a639e..ad8a1b9e03 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -34,11 +34,13 @@ //| class Keys: //| """Manage a set of independent keys.""" //| -//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, max_events: int = 16) -> None: +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to the given sequence of pins. //| Each key is independent and attached to its own pin. //| +//| The keys are debounced by waiting about 20 msecs before reporting a transition. +//| //| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys. //| The key numbers correspond to indices into this sequence. //| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. @@ -65,7 +67,7 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -131,7 +133,7 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { } //| def next_event(self) -> Optional[Event]: -//| """Return the next key transition event. Return ``None` if no events are pending. +//| """Return the next key transition event. Return ``None`` if no events are pending. //| //| Note that the queue size is limited; see ``max_events`` in the constructor. //| If a new event arrives when the queue is full, the oldest event is discarded. diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 04cb84facb..8ad08d0eb8 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -50,24 +50,24 @@ static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events) { mp_obj_t row_dios[num_row_pins]; - for (size_t i = 0; i < num_row_pins; i++) { + for (size_t row = 0; row < num_row_pins; row++) { digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); dio->base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(dio, row_pins[i]); + common_hal_digitalio_digitalinout_construct(dio, row_pins[row]); common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); - row_dios[i] = dio; + row_dios[row] = dio; } - self->row_digitalinouts = mp_obj_new_tuple(num_col_pins, row_dios); + self->row_digitalinouts = mp_obj_new_tuple(num_row_pins, row_dios); mp_obj_t col_dios[num_col_pins]; - for (size_t i = 0; i < num_col_pins; i++) { + for (size_t col = 0; col < num_col_pins; col++) { digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); dio->base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(dio, col_pins[i]); + common_hal_digitalio_digitalinout_construct(dio, col_pins[col]); common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); - col_dios[i] = dio; + col_dios[col] = dio; } - self->col_digitalinouts = mp_obj_new_tuple(num_row_pins, col_dios); + self->col_digitalinouts = mp_obj_new_tuple(num_col_pins, col_dios); self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); @@ -81,6 +81,8 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->next = MP_STATE_VM(keypad_keymatrix_linked_list); MP_STATE_VM(keypad_keymatrix_linked_list) = self; supervisor_release_lock(&keypad_keymatrix_linked_list_lock); + + supervisor_enable_tick(); } void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { @@ -145,7 +147,7 @@ mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self) { } keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); - self->base.type = &keypad_event_type; + event->base.type = &keypad_event_type; common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); return MP_OBJ_FROM_PTR(event); } @@ -179,8 +181,9 @@ static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { self->previously_pressed[key_num] = previous; // Get the current state, by reading whether the col got pulled down or not. + // If low, the key is pressed. const bool current = - common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[key_num]); + !common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[col]); self->currently_pressed[key_num] = current; // Record any transitions. From f97e0ec631835ef59f2b6a54575154893e8b0aa3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 15 Jun 2021 11:39:40 -0400 Subject: [PATCH 19/38] fix ulab commit --- extmod/ulab | 2 +- lib/utils/linked_list.h | 36 ------------------- locale/circuitpython.pot | 17 ++++----- .../stm/boards/espruino_pico/mpconfigboard.mk | 1 - supervisor/supervisor.mk | 2 +- 5 files changed, 11 insertions(+), 47 deletions(-) delete mode 100644 lib/utils/linked_list.h diff --git a/extmod/ulab b/extmod/ulab index e3bf07cabb..161a728848 160000 --- a/extmod/ulab +++ b/extmod/ulab @@ -1 +1 @@ -Subproject commit e3bf07cabb728ecfa2b78ea5e468179f94dbf933 +Subproject commit 161a7288482200c884623ed3cb59dd91f53be91a diff --git a/lib/utils/linked_list.h b/lib/utils/linked_list.h deleted file mode 100644 index cd5ea0fc7c..0000000000 --- a/lib/utils/linked_list.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2021 Dan Halbert for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef MICROPY_INCLUDED_LINKED_LIST_H -#define MICROPY_INCLUDED_LINKED_LIST_H - -#define LINKED_LIST_PREPEND(LIST_HEAD, OBJECT, NEXT_FIELD) \ - OBJECT->NEXT_FIELD = LIST_HEAD; \ - LIST_HEAD = OBJECT; - -#define LINKED_LIST_DELETE(LIST_HEAD, OBJECT, - -#endif // MICROPY_INCLUDED_LINKED_LIST_H diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 906c51b698..d2c2dbe8b4 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3058,6 +3058,10 @@ msgstr "" msgid "first argument to super() must be type" msgstr "" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "flattening order must be either 'C', or 'F'" msgstr "" @@ -3237,10 +3241,11 @@ msgid "input matrix is asymmetric" msgstr "" #: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c msgid "input matrix is singular" msgstr "" -#: extmod/ulab/code/user/user.c +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c msgid "input must be a dense ndarray" msgstr "" @@ -3281,7 +3286,7 @@ msgid "integer required" msgstr "" #: extmod/ulab/code/numpy/approx/approx.c -msgid "interp is defined for 1D arrays of equal length" +msgid "interp is defined for 1D iterables of equal length" msgstr "" #: shared-bindings/_bleio/Adapter.c @@ -4137,11 +4142,11 @@ msgid "too many values to unpack (expected %d)" msgstr "" #: extmod/ulab/code/numpy/approx/approx.c -msgid "trapz is defined for 1D arrays" +msgid "trapz is defined for 1D arrays of equal length" msgstr "" #: extmod/ulab/code/numpy/approx/approx.c -msgid "trapz is defined for 1D arrays of equal length" +msgid "trapz is defined for 1D iterables" msgstr "" #: py/obj.c @@ -4324,10 +4329,6 @@ msgstr "" msgid "wrong number of values to unpack" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "wrong operand type" -msgstr "" - #: extmod/ulab/code/numpy/vector/vector.c msgid "wrong output type" msgstr "" diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.mk b/ports/stm/boards/espruino_pico/mpconfigboard.mk index 3f3e81d553..bc415f07ec 100644 --- a/ports/stm/boards/espruino_pico/mpconfigboard.mk +++ b/ports/stm/boards/espruino_pico/mpconfigboard.mk @@ -22,7 +22,6 @@ CIRCUITPY_AUDIOPWMIO = 0 CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_FRAMEBUFFERIO = 0 -CIRCUITPY_KEYPAD = 0 CIRCUITPY_MIDI = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_ULAB = 0 diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index d32436cdb0..d36b975c21 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -8,7 +8,7 @@ SRC_SUPERVISOR = \ supervisor/shared/filesystem.c \ supervisor/shared/flash.c \ supervisor/shared/lock.c \ - supervisor/shared/memory.c \ + supervisor/shared/memory.c \ supervisor/shared/micropython.c \ supervisor/shared/safe_mode.c \ supervisor/shared/stack.c \ From 4655a71793eee46d567c7be63646ddf27d7d54eb Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 15 Jun 2021 14:11:04 -0400 Subject: [PATCH 20/38] Turn off keypad on some builds to avoid overflow --- .../boards/circuitplayground_express_crickit/mpconfigboard.mk | 1 + .../boards/circuitplayground_express_displayio/mpconfigboard.mk | 1 + ports/atmel-samd/boards/stringcar_m0_express/mpconfigboard.mk | 2 ++ ports/nrf/boards/pca10100/mpconfigboard.mk | 1 + ports/stm/boards/espruino_pico/mpconfigboard.mk | 1 + ports/stm/boards/pyb_nano_v2/mpconfigboard.mk | 1 + ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk | 1 + 7 files changed, 8 insertions(+) diff --git a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk index 902e9594e3..fb65d7cd0a 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.mk @@ -14,6 +14,7 @@ LONGINT_IMPL = NONE CIRCUITPY_BUSDEVICE = 1 CIRCUITPY_DISPLAYIO = 0 +CIRCUITPY_KEYPAD = 0 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_CircuitPlayground diff --git a/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.mk index 68fb51ab00..3a97c39830 100644 --- a/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.mk @@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C" # Turn off features and optimizations for displayio build to make room for additional frozen libs. LONGINT_IMPL = NONE +CIRCUITPY_KEYPAD = 0 CIRCUITPY_PIXELBUF = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 diff --git a/ports/atmel-samd/boards/stringcar_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/stringcar_m0_express/mpconfigboard.mk index 53aeda3c50..a863248ca7 100644 --- a/ports/atmel-samd/boards/stringcar_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/stringcar_m0_express/mpconfigboard.mk @@ -11,4 +11,6 @@ SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = AT25SF161 LONGINT_IMPL = MPZ +CIRCUITPY_KEYPAD = 0 + CIRCUITPY_BITBANG_APA102 = 1 diff --git a/ports/nrf/boards/pca10100/mpconfigboard.mk b/ports/nrf/boards/pca10100/mpconfigboard.mk index 9fae5ccc4d..3a7407861b 100644 --- a/ports/nrf/boards/pca10100/mpconfigboard.mk +++ b/ports/nrf/boards/pca10100/mpconfigboard.mk @@ -18,6 +18,7 @@ CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_JSON = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_NEOPIXEL_WRITE = 0 CIRCUITPY_NVM = 0 diff --git a/ports/stm/boards/espruino_pico/mpconfigboard.mk b/ports/stm/boards/espruino_pico/mpconfigboard.mk index bc415f07ec..3f3e81d553 100644 --- a/ports/stm/boards/espruino_pico/mpconfigboard.mk +++ b/ports/stm/boards/espruino_pico/mpconfigboard.mk @@ -22,6 +22,7 @@ CIRCUITPY_AUDIOPWMIO = 0 CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MIDI = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_ULAB = 0 diff --git a/ports/stm/boards/pyb_nano_v2/mpconfigboard.mk b/ports/stm/boards/pyb_nano_v2/mpconfigboard.mk index 99af948d7b..d1a627569c 100644 --- a/ports/stm/boards/pyb_nano_v2/mpconfigboard.mk +++ b/ports/stm/boards/pyb_nano_v2/mpconfigboard.mk @@ -16,5 +16,6 @@ LD_FILE = boards/STM32F411_fs.ld # Too big for the flash CIRCUITPY_AUDIOCORE = 0 CIRCUITPY_AUDIOPWMIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MIDI = 0 CIRCUITPY_MSGPACK = 0 diff --git a/ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk b/ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk index 04c8cc2d45..c8dc80a70c 100644 --- a/ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk +++ b/ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk @@ -15,5 +15,6 @@ LD_FILE = boards/STM32F411_fs.ld # Too big for the flash CIRCUITPY_AUDIOCORE = 0 CIRCUITPY_AUDIOPWMIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MIDI = 0 CIRCUITPY_MSGPACK = 0 From 3d18c5c3272e8d19d7ea80b5e017595b3b4a972f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 16 Jun 2021 13:29:38 -0400 Subject: [PATCH 21/38] Use a single list of keypad scanners --- py/circuitpy_mpconfig.h | 4 +- shared-module/keypad/KeyMatrix.c | 61 ++++------------------------- shared-module/keypad/KeyMatrix.h | 14 +++---- shared-module/keypad/Keys.c | 60 ++++------------------------ shared-module/keypad/Keys.h | 16 ++++---- shared-module/keypad/__init__.c | 67 +++++++++++++++++++++++++++++--- shared-module/keypad/__init__.h | 14 +++++++ 7 files changed, 105 insertions(+), 131 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 4b6585c2a4..fdb78d885c 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -533,9 +533,7 @@ extern const struct _mp_obj_module_t ipaddress_module; #if CIRCUITPY_KEYPAD extern const struct _mp_obj_module_t keypad_module; #define KEYPAD_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_keypad), (mp_obj_t)&keypad_module }, -#define KEYPAD_ROOT_POINTERS \ - mp_obj_t keypad_keys_linked_list; \ - mp_obj_t keypad_keymatrix_linked_list; +#define KEYPAD_ROOT_POINTERS mp_obj_t keypad_scanners_linked_list; #else #define KEYPAD_MODULE #define KEYPAD_ROOT_POINTERS diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 8ad08d0eb8..c7c7d60cc1 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -26,16 +26,14 @@ #include "py/gc.h" #include "py/runtime.h" +#include "shared-bindings/keypad/__init__.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/KeyMatrix.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/util.h" #include "supervisor/port.h" -#include "supervisor/shared/lock.h" #include "supervisor/shared/tick.h" -static supervisor_lock_t keypad_keymatrix_linked_list_lock; - #define DEBOUNCE_TICKS (20) // Top bit of 16-bit event indicates pressed or released. Rest is key_num. @@ -75,12 +73,8 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint // Event queue is 16-bit values. ringbuf_alloc(&self->encoded_events, max_events * 2, false); - // Add self to the list of active Keys objects. - - supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock); - self->next = MP_STATE_VM(keypad_keymatrix_linked_list); - MP_STATE_VM(keypad_keymatrix_linked_list) = self; - supervisor_release_lock(&keypad_keymatrix_linked_list_lock); + // Add self to the list of active keypad scanners. + keypad_register_scanner((keypad_scanner_obj_t *)self); supervisor_enable_tick(); } @@ -90,6 +84,9 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { return; } + // Remove self from the list of active keypad scanners first. + keypad_deregister_scanner((keypad_scanner_obj_t *)self); + for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) { common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]); } @@ -99,25 +96,6 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { common_hal_digitalio_digitalinout_deinit(self->col_digitalinouts->items[col]); } self->col_digitalinouts = MP_ROM_NONE; - - // Remove self from the list of active KeyMatrix objects. - - supervisor_acquire_lock(&keypad_keymatrix_linked_list_lock); - if (MP_STATE_VM(keypad_keymatrix_linked_list) == self) { - // I'm at the front; splice myself out. - MP_STATE_VM(keypad_keymatrix_linked_list) = self->next; - } else { - keypad_keymatrix_obj_t *current = MP_STATE_VM(keypad_keymatrix_linked_list); - while (current) { - if (current->next == self) { - // Splice myself out. - current->next = self->next; - break; - } - current = current->next; - } - } - supervisor_release_lock(&keypad_keymatrix_linked_list_lock); } bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) { @@ -160,7 +138,7 @@ mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_u return row_col_to_key_num(self, row, col); } -static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { +void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { // Too soon. Wait longer to debounce. @@ -201,28 +179,3 @@ static void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { common_hal_digitalio_digitalinout_switch_to_input(self->row_digitalinouts->items[row], PULL_UP); } } - -void keypad_keymatrix_tick(void) { - // Fast path. - if (!MP_STATE_VM(keypad_keymatrix_linked_list)) { - return; - } - - if (supervisor_try_lock(&keypad_keymatrix_linked_list_lock)) { - keypad_keymatrix_obj_t *keypad_keymatrix = MP_STATE_VM(keypad_keymatrix_linked_list); - while (keypad_keymatrix) { - keypad_keymatrix_scan(keypad_keymatrix); - keypad_keymatrix = keypad_keymatrix->next; - } - supervisor_release_lock(&keypad_keymatrix_linked_list_lock); - } -} - -void keypad_keymatrix_reset(void) { - if (MP_STATE_VM(keypad_keymatrix_linked_list)) { - supervisor_disable_tick(); - } - - MP_STATE_VM(keypad_keys_linked_list) = NULL; - keypad_keymatrix_linked_list_lock = false; -} diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index 2051536898..e25f23b0fc 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -27,25 +27,25 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H #define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H -#include "common-hal/digitalio/DigitalInOut.h" - #include "py/obj.h" #include "py/objtuple.h" #include "py/ringbuf.h" -typedef struct _keypad_keymatrix_obj_t { +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-module/keypad/__init__.h" + +typedef struct { mp_obj_base_t base; + // All scanners have a next field here, to keep a linked list of active scanners. + keypad_scanner_obj_t *next; mp_obj_tuple_t *row_digitalinouts; mp_obj_tuple_t *col_digitalinouts; uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; ringbuf_t encoded_events; - // Keep a linked list of active KeyMatrix objects. - struct _keypad_keymatrix_obj_t *next; } keypad_keymatrix_obj_t; -void keypad_keymatrix_tick(void); -void keypad_keymatrix_reset(void); +void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYMATRIX_H diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 84e77e91eb..bc8549b55b 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -26,15 +26,13 @@ #include "py/gc.h" #include "py/runtime.h" +#include "shared-bindings/keypad/__init__.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "supervisor/port.h" -#include "supervisor/shared/lock.h" #include "supervisor/shared/tick.h" -static supervisor_lock_t keypad_keys_linked_list_lock; - #define DEBOUNCE_TICKS (20) // Top bit of 16-bit event indicates pressed or released. Rest is key_num. @@ -64,12 +62,8 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin // Event queue is 16-bit values. ringbuf_alloc(&self->encoded_events, max_events * 2, false); - // Add self to the list of active Keys objects. - - supervisor_acquire_lock(&keypad_keys_linked_list_lock); - self->next = MP_STATE_VM(keypad_keys_linked_list); - MP_STATE_VM(keypad_keys_linked_list) = self; - supervisor_release_lock(&keypad_keys_linked_list_lock); + // Add self to the list of active keypad scanners. + keypad_register_scanner((keypad_scanner_obj_t *)self); supervisor_enable_tick(); } @@ -79,29 +73,14 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) { return; } + // Remove self from the list of active keypad scanners first. + keypad_deregister_scanner((keypad_scanner_obj_t *)self); + for (size_t key = 0; key < common_hal_keypad_keys_num_keys(self); key++) { common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]); } self->digitalinouts = MP_ROM_NONE; - // Remove self from the list of active Keys objects. - - supervisor_acquire_lock(&keypad_keys_linked_list_lock); - if (MP_STATE_VM(keypad_keys_linked_list) == self) { - // I'm at the front; splice myself out. - MP_STATE_VM(keypad_keys_linked_list) = self->next; - } else { - keypad_keys_obj_t *current = MP_STATE_VM(keypad_keys_linked_list); - while (current) { - if (current->next == self) { - // Splice myself out. - current->next = self->next; - break; - } - current = current->next; - } - } - supervisor_release_lock(&keypad_keys_linked_list_lock); } bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) { @@ -131,7 +110,7 @@ void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { ringbuf_clear(&self->encoded_events); } -static void keypad_keys_scan(keypad_keys_obj_t *self) { +void keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { // Too soon. Wait longer to debounce. @@ -160,28 +139,3 @@ static void keypad_keys_scan(keypad_keys_obj_t *self) { } } } - -void keypad_keys_tick(void) { - // Fast path. - if (!MP_STATE_VM(keypad_keys_linked_list)) { - return; - } - - if (supervisor_try_lock(&keypad_keys_linked_list_lock)) { - keypad_keys_obj_t *keypad_keys = MP_STATE_VM(keypad_keys_linked_list); - while (keypad_keys) { - keypad_keys_scan(keypad_keys); - keypad_keys = keypad_keys->next; - } - supervisor_release_lock(&keypad_keys_linked_list_lock); - } -} - -void keypad_keys_reset(void) { - if (MP_STATE_VM(keypad_keys_linked_list)) { - supervisor_disable_tick(); - } - - MP_STATE_VM(keypad_keys_linked_list) = NULL; - keypad_keys_linked_list_lock = false; -} diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index ecf8165b9e..03eb65d635 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -27,25 +27,25 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H #define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H -#include "common-hal/digitalio/DigitalInOut.h" - #include "py/obj.h" #include "py/objtuple.h" #include "py/ringbuf.h" -typedef struct _keypad_keys_obj_t { +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-module/keypad/__init__.h" + +typedef struct { mp_obj_base_t base; + // All scanners have a next field here, to keep a linked list of active scanners. + keypad_scanner_obj_t *next; mp_obj_tuple_t *digitalinouts; uint64_t last_scan_ticks; - bool value_when_pressed; bool *previously_pressed; bool *currently_pressed; ringbuf_t encoded_events; - // Keep a linked list of active Keys objects. - struct _keypad_keys_obj_t *next; + bool value_when_pressed; } keypad_keys_obj_t; -void keypad_keys_tick(void); -void keypad_keys_reset(void); +void keypad_keys_scan(keypad_keys_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_KEYS_H diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index 9b08dc9bb5..f29f126c3f 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -24,15 +24,70 @@ * THE SOFTWARE. */ -#include "shared-module/keypad/Keys.h" -#include "shared-module/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/KeyMatrix.h" +#include "supervisor/shared/lock.h" +#include "supervisor/shared/tick.h" + +static supervisor_lock_t keypad_scanners_linked_list_lock; void keypad_tick(void) { - keypad_keys_tick(); - keypad_keymatrix_tick(); + // Fast path. Return immediately if there are no scanners. + if (!MP_STATE_VM(keypad_scanners_linked_list)) { + return; + } + + // Skip scanning if someone else has the lock. Don't wait for the lock. + if (supervisor_try_lock(&keypad_scanners_linked_list_lock)) { + mp_obj_t scanner = MP_STATE_VM(keypad_scanners_linked_list); + while (scanner) { + if (mp_obj_is_type(scanner, &keypad_keys_type)) { + keypad_keys_scan((keypad_keys_obj_t *)scanner); + } else if (mp_obj_is_type(scanner, &keypad_keymatrix_type)) { + keypad_keymatrix_scan((keypad_keymatrix_obj_t *)scanner); + } + + scanner = ((keypad_scanner_obj_t *)scanner)->next; + } + supervisor_release_lock(&keypad_scanners_linked_list_lock); + } } void keypad_reset(void) { - keypad_keys_reset(); - keypad_keymatrix_reset(); + if (MP_STATE_VM(keypad_scanners_linked_list)) { + supervisor_disable_tick(); + } + + MP_STATE_VM(keypad_scanners_linked_list) = NULL; + keypad_scanners_linked_list_lock = false; +} + +// Register a Keys, KeyMatrix, etc. that will be scanned in the background +void keypad_register_scanner(keypad_scanner_obj_t *scanner) { + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + scanner->next = MP_STATE_VM(keypad_scanners_linked_list); + MP_STATE_VM(keypad_scanners_linked_list) = scanner; + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + +// Remove scanner from the list of active scanners. +void keypad_deregister_scanner(keypad_scanner_obj_t *scanner) { + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + if (MP_STATE_VM(keypad_scanners_linked_list) == scanner) { + // Scanner is at the front; splice it out. + MP_STATE_VM(keypad_scanners_linked_list) = scanner->next; + scanner->next = NULL; + } else { + keypad_scanner_obj_t *current = MP_STATE_VM(keypad_scanners_linked_list); + while (current) { + if (current->next == scanner) { + // Splice myself out. + current->next = scanner->next; + scanner->next = NULL; + break; + } + current = current->next; + } + } + supervisor_release_lock(&keypad_scanners_linked_list_lock); } diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h index 2dc3fdca8e..de89c310a5 100644 --- a/shared-module/keypad/__init__.h +++ b/shared-module/keypad/__init__.h @@ -27,7 +27,21 @@ #ifndef SHARED_MODULE_KEYPAD_H #define SHARED_MODULE_KEYPAD_H +#include "py/obj.h" + +// All scanners must have a next field immediately following base. +// This is an ad hoc "superclass" struct for scanners, though they do +// not actually have a superclass relationship. +typedef struct _keypad_scanner_obj_t { + mp_obj_base_t base; + struct _keypad_scanner_obj_t *next; +} keypad_scanner_obj_t; + void keypad_tick(void); void keypad_reset(void); +void keypad_register_scanner(keypad_scanner_obj_t *scanner); +void keypad_deregister_scanner(keypad_scanner_obj_t *scanner); + + #endif // SHARED_MODULE_KEYPAD_H From cd31136c30791ced328eb132676382c21c09b5e9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 16 Jun 2021 15:27:59 -0400 Subject: [PATCH 22/38] factor out keypad.EventQueue --- py/circuitpy_defns.mk | 1 + shared-bindings/keypad/Event.c | 20 +++--- shared-bindings/keypad/EventQueue.c | 105 ++++++++++++++++++++++++++++ shared-bindings/keypad/EventQueue.h | 41 +++++++++++ shared-bindings/keypad/KeyMatrix.c | 61 +++++++--------- shared-bindings/keypad/KeyMatrix.h | 4 +- shared-bindings/keypad/Keys.c | 70 ++++++++----------- shared-bindings/keypad/Keys.h | 5 +- shared-bindings/keypad/__init__.c | 10 +-- shared-module/keypad/EventQueue.c | 66 +++++++++++++++++ shared-module/keypad/EventQueue.h | 40 +++++++++++ shared-module/keypad/KeyMatrix.c | 45 ++++-------- shared-module/keypad/KeyMatrix.h | 4 +- shared-module/keypad/Keys.c | 40 +++-------- shared-module/keypad/Keys.h | 4 +- 15 files changed, 352 insertions(+), 164 deletions(-) create mode 100644 shared-bindings/keypad/EventQueue.c create mode 100644 shared-bindings/keypad/EventQueue.h create mode 100644 shared-module/keypad/EventQueue.c create mode 100644 shared-module/keypad/EventQueue.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 43ae46ac00..aa06434368 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -517,6 +517,7 @@ SRC_SHARED_MODULE_ALL = \ ipaddress/__init__.c \ keypad/__init__.c \ keypad/Event.c \ + keypad/EventQueue.c \ keypad/KeyMatrix.c \ keypad/Keys.c \ sdcardio/SDCard.c \ diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 807f0c6af5..7abd75e54d 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -64,11 +64,11 @@ STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, //| key_num: int //| """The key number.""" //| -STATIC mp_obj_t keypad_event_obj_get_key_num(mp_obj_t self_in) { +STATIC mp_obj_t keypad_event_get_key_num(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_num(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_num_obj, keypad_event_obj_get_key_num); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_num_obj, keypad_event_get_key_num); const mp_obj_property_t keypad_event_key_num_obj = { .base.type = &mp_type_property, @@ -78,15 +78,15 @@ const mp_obj_property_t keypad_event_key_num_obj = { }; //| pressed: bool -//| """True if event represents a key down (pressed) transition. +//| """``True`` if the event represents a key down (pressed) transition. //| The opposite of `released`. //| """ //| -STATIC mp_obj_t keypad_event_obj_get_pressed(mp_obj_t self_in) { +STATIC mp_obj_t keypad_event_get_pressed(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(common_hal_keypad_event_get_pressed(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_obj_get_pressed); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_get_pressed); const mp_obj_property_t keypad_event_pressed_obj = { .base.type = &mp_type_property, @@ -96,15 +96,15 @@ const mp_obj_property_t keypad_event_pressed_obj = { }; //| released: bool -//| """True if event represents a key up (released) transition. +//| """``True`` if the event represents a key up (released) transition. //| The opposite of `pressed`. //| """ //| -STATIC mp_obj_t keypad_event_obj_get_released(mp_obj_t self_in) { +STATIC mp_obj_t keypad_event_get_released(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_bool(common_hal_keypad_event_get_released(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_obj_get_released); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_get_released); const mp_obj_property_t keypad_event_released_obj = { .base.type = &mp_type_property, @@ -114,7 +114,7 @@ const mp_obj_property_t keypad_event_released_obj = { }; //| def __eq__(self, other: object) -> bool: -//| """Two Event objects are equal if their `key_num` +//| """Two `Event` objects are equal if their `key_num` //| and `pressed`/`released` values are equal. //| """ //| ... @@ -140,7 +140,7 @@ STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_ob } //| def __hash__(self) -> int: -//| """Returns a hash for the Event, so it can be used in dictionaries, etc..""" +//| """Returns a hash for the `Event`, so it can be used in dictionaries, etc..""" //| ... //| STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) { diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c new file mode 100644 index 0000000000..9ffebf3662 --- /dev/null +++ b/shared-bindings/keypad/EventQueue.c @@ -0,0 +1,105 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "shared-bindings/keypad/EventQueue.h" + +//| class EventQueue: +//| """A queue of `Event` objects, filled by a `keypad` scanner such as `Keys` or `KeyMatrix`. +//| +//| You cannot create an instance of `EventQueue` directly. Each scanner creates an +//| instance when it is created. +//| """ +//| ... + +//| def next(self) -> Optional[Event]: +//| """Return the next key transition event. Return ``None`` if no events are pending. +//| +//| Note that the queue size is limited; see ``max_events`` in the constructor of +//| a scanner such as `Keys` or `KeyMatrix`. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| +//| :return: the next queued key transition `Event` +//| :rtype: Optional[Event] +//| """ +//| ... +//| +STATIC mp_obj_t keypad_eventqueue_next(mp_obj_t self_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_keypad_eventqueue_next(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_next_obj, keypad_eventqueue_next); + +//| def clear(self) -> None: +//| """Clear any queued key transition events. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_eventqueue_clear(mp_obj_t self_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_eventqueue_clear(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_clear_obj, keypad_eventqueue_clear); + +//| def __bool__(self) -> bool: +//| """``True`` if `len()` is greater than zero. +//| This is an easy way to check if the queue is empty. +//| """ +//| ... +//| +//| def __len__(self) -> int: +//| """Return the number of events currently in the queue. Used to implement ``len()``.""" +//| ... +//| +STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint16_t len = common_hal_keypad_eventqueue_get_length(self); + switch (op) { + case MP_UNARY_OP_BOOL: + return mp_obj_new_bool(len != 0); + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(len); + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&keypad_eventqueue_next_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table); + +const mp_obj_type_t keypad_eventqueue_type = { + { &mp_type_type }, + .name = MP_QSTR_Keys, + .unary_op = keypad_eventqueue_unary_op, + .locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict, +}; diff --git a/shared-bindings/keypad/EventQueue.h b/shared-bindings/keypad/EventQueue.h new file mode 100644 index 0000000000..d6b2ac32c6 --- /dev/null +++ b/shared-bindings/keypad/EventQueue.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H + +#include "py/objlist.h" +#include "shared-module/keypad/Keys.h" + +extern const mp_obj_type_t keypad_eventqueue_type; + +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events); + +void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self); +size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self); +mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 5820c9ea39..75e434ac3e 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -25,6 +25,7 @@ */ #include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/KeyMatrix.h" @@ -44,11 +45,13 @@ //| The keys are numbered sequentially from zero. A key number can be computed //| by ``row * len(col_pins) + col``. //| +//| An `EventQueue` is created when this object is created and is available in the `events` attribute. +//| //| The keys are debounced by waiting about 20 msecs before reporting a transition. //| //| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows. //| :param Sequence[microcontroller.Pin] col_pins: The pins attached to the colums. -//| :param int max_events: Size of key event queue: +//| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. //| If a new event arrives when the queue is full, the oldest event is discarded. @@ -133,42 +136,10 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { } } -//| def next_event(self) -> Optional[Event]: -//| """Return the next key transition event. Return ``None`` if no events are pending. -//| -//| Note that the queue size is limited; see ``max_events`` in the constructor. -//| If a new event arrives when the queue is full, the oldest event is discarded. -//| -//| :return: the next queued key transition `Event` -//| :rtype: Optional[Event] -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keymatrix_next_event(mp_obj_t self_in) { - keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - return common_hal_keypad_keymatrix_next_event(self); -} -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_next_event_obj, keypad_keymatrix_next_event); - -//| def clear_events(self) -> None: -//| """Clear any queued key transition events. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keymatrix_clear_events(mp_obj_t self_in) { - keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - common_hal_keypad_keymatrix_clear_events(self); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_clear_events_obj, keypad_keymatrix_clear_events); //| def pressed(self, key_num: int) -> None: //| """Return ``True`` if the given key is pressed. This is a debounced read -//| of the key state which bypasses the event queue. +//| of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| @@ -210,14 +181,30 @@ STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_o } MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_key_num_obj, keypad_keymatrix_key_num); +//| events: EventQueue +//| """The `EventQueue` associated with this `Keys` object. (read-only) +//| """ +//| +STATIC mp_obj_t keypad_keymatrix_get_events(mp_obj_t self_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_keypad_keymatrix_get_events(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_events_obj, keypad_keymatrix_get_events); + +const mp_obj_property_t keypad_keymatrix_events_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_keymatrix_get_events_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_clear_events), MP_ROM_PTR(&keypad_keymatrix_clear_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) }, { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_keymatrix_key_num_obj) }, - { MP_ROM_QSTR(MP_QSTR_next_event), MP_ROM_PTR(&keypad_keymatrix_next_event_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, }; @@ -225,7 +212,7 @@ STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_local const mp_obj_type_t keypad_keymatrix_type = { { &mp_type_type }, - .name = MP_QSTR_Keys, + .name = MP_QSTR_KeyMatrix, .make_new = keypad_keymatrix_make_new, .locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict, }; diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index f0ce8761bc..d6a2cbb074 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -33,6 +33,7 @@ extern const mp_obj_type_t keypad_keymatrix_type; void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events); + void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); @@ -42,8 +43,7 @@ mp_uint_t common_hal_keypad_keymatrix_num_keys(keypad_keymatrix_obj_t *self); mp_uint_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self); mp_uint_t common_hal_keypad_keymatrix_num_rows(keypad_keymatrix_obj_t *self); +mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num); -mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self); -void common_hal_keypad_keymatrix_clear_events(keypad_keymatrix_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index ad8a1b9e03..35a9c0e09b 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -25,6 +25,7 @@ */ #include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/Keys.h" @@ -39,6 +40,8 @@ //| Create a `Keys` object that will scan keys attached to the given sequence of pins. //| Each key is independent and attached to its own pin. //| +//| An `EventQueue` is created when this object is created and is available in the `events` attribute. +//| //| The keys are debounced by waiting about 20 msecs before reporting a transition. //| //| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys. @@ -52,7 +55,7 @@ //| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. //| However, enabling an internal pull when an external one is already present is not a problem; //| it simply uses slightly more current. -//| :param int max_events: Size of key event queue: +//| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. //| If a new event arrives when the queue is full, the oldest event is discarded. @@ -132,42 +135,9 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { } } -//| def next_event(self) -> Optional[Event]: -//| """Return the next key transition event. Return ``None`` if no events are pending. -//| -//| Note that the queue size is limited; see ``max_events`` in the constructor. -//| If a new event arrives when the queue is full, the oldest event is discarded. -//| -//| :return: the next queued key transition `Event` -//| :rtype: Optional[Event] -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keys_next_event(mp_obj_t self_in) { - keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - return common_hal_keypad_keys_next_event(self); -} -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_next_event_obj, keypad_keys_next_event); - -//| def clear_events(self) -> None: -//| """Clear any queued key transition events. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keys_clear_events(mp_obj_t self_in) { - keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - common_hal_keypad_keys_clear_events(self); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_clear_events_obj, keypad_keys_clear_events); - //| def pressed(self, key_num: int) -> None: //| """Return ``True`` if the given key is pressed. This is a debounced read -//| of the key state which bypasses the event queue. +//| of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| @@ -184,14 +154,30 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { } MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); -STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, +//| events: EventQueue +//| """The `EventQueue` associated with this `Keys` object. (read-only) +//| """ +//| +STATIC mp_obj_t keypad_keys_get_events(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_keypad_keys_get_events(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_events_obj, keypad_keys_get_events); - { MP_ROM_QSTR(MP_QSTR_clear_events), MP_ROM_PTR(&keypad_keys_clear_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_next_event), MP_ROM_PTR(&keypad_keys_next_event_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, +const mp_obj_property_t keypad_keys_events_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_keys_get_events_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index f7ec2302d8..81fc36d3cb 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -33,13 +33,12 @@ extern const mp_obj_type_t keypad_keys_type; void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events); + void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); +mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self); mp_uint_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self); bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); -mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self); -void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self); - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c index 20f60a5137..5f6177576e 100644 --- a/shared-bindings/keypad/__init__.c +++ b/shared-bindings/keypad/__init__.c @@ -28,6 +28,7 @@ #include "shared-bindings/keypad/__init__.h" #include "shared-bindings/keypad/Event.h" +#include "shared-bindings/keypad/EventQueue.h" #include "shared-bindings/keypad/KeyMatrix.h" #include "shared-bindings/keypad/Keys.h" @@ -39,10 +40,11 @@ //| STATIC mp_map_elem_t keypad_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, - { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) }, - { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) }, - { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, + { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) }, + { MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) }, + { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, }; STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table); diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c new file mode 100644 index 0000000000..e75d93106a --- /dev/null +++ b/shared-module/keypad/EventQueue.c @@ -0,0 +1,66 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/keypad/Event.h" +#include "shared-module/keypad/EventQueue.h" + +// Top bit of 16-bit event indicates pressed or released. Rest is key_num. +#define EVENT_PRESSED (1 << 15) +#define EVENT_RELEASED (0) +#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) + +void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events) { + // Event queue is 16-bit values. + ringbuf_alloc(&self->encoded_events, max_events * 2, false); +} + +mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self) { + int encoded_event = ringbuf_get16(&self->encoded_events); + if (encoded_event == -1) { + return MP_ROM_NONE; + } + + keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); + event->base.type = &keypad_event_type; + common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); + return MP_OBJ_FROM_PTR(event); +} + +void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) { + ringbuf_clear(&self->encoded_events); +} + +size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self) { + return ringbuf_num_filled(&self->encoded_events); +} + +void keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_num, bool pressed) { + if (ringbuf_num_empty(&self->encoded_events) == 0) { + // Discard oldest if full. + ringbuf_get16(&self->encoded_events); + } + ringbuf_put16(&self->encoded_events, key_num | (pressed ? EVENT_PRESSED : EVENT_RELEASED)); +} diff --git a/shared-module/keypad/EventQueue.h b/shared-module/keypad/EventQueue.h new file mode 100644 index 0000000000..88e585b23b --- /dev/null +++ b/shared-module/keypad/EventQueue.h @@ -0,0 +1,40 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H + +#include "py/obj.h" +#include "py/ringbuf.h" + +typedef struct { + mp_obj_base_t base; + ringbuf_t encoded_events; +} keypad_eventqueue_obj_t; + +void keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_num, bool pressed); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index c7c7d60cc1..441f78a448 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -26,21 +26,16 @@ #include "py/gc.h" #include "py/runtime.h" -#include "shared-bindings/keypad/__init__.h" -#include "shared-bindings/keypad/Event.h" -#include "shared-bindings/keypad/KeyMatrix.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/keypad/EventQueue.h" +#include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/__init__.h" #include "shared-bindings/util.h" #include "supervisor/port.h" #include "supervisor/shared/tick.h" #define DEBOUNCE_TICKS (20) -// Top bit of 16-bit event indicates pressed or released. Rest is key_num. -#define EVENT_PRESSED (1 << 15) -#define EVENT_RELEASED (0) -#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) - static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { return row * self->col_digitalinouts->len + col; } @@ -70,8 +65,10 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); - // Event queue is 16-bit values. - ringbuf_alloc(&self->encoded_events, max_events * 2, false); + keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); + events->base.type = &keypad_eventqueue_type; + common_hal_keypad_eventqueue_construct(events, max_events); + self->events = events; // Add self to the list of active keypad scanners. keypad_register_scanner((keypad_scanner_obj_t *)self); @@ -117,27 +114,14 @@ size_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self) { bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num) { return self->currently_pressed[key_num]; } - -mp_obj_t common_hal_keypad_keymatrix_next_event(keypad_keymatrix_obj_t *self) { - int encoded_event = ringbuf_get16(&self->encoded_events); - if (encoded_event == -1) { - return MP_ROM_NONE; - } - - keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); - event->base.type = &keypad_event_type; - common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); - return MP_OBJ_FROM_PTR(event); -} - -void common_hal_keypad_keymatrix_clear_events(keypad_keymatrix_obj_t *self) { - ringbuf_clear(&self->encoded_events); -} - mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { return row_col_to_key_num(self, row, col); } +mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self) { + return MP_OBJ_FROM_PTR(self->events); +} + void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { @@ -166,13 +150,8 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { // Record any transitions. if (previous != current) { - if (ringbuf_num_empty(&self->encoded_events) == 0) { - // Discard oldest if full. - ringbuf_get16(&self->encoded_events); - } - ringbuf_put16(&self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + keypad_eventqueue_record(self->events, key_num, current); } - } // Switch the row back to an input, pulled up. diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index e25f23b0fc..253067890a 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -29,10 +29,10 @@ #include "py/obj.h" #include "py/objtuple.h" -#include "py/ringbuf.h" #include "common-hal/digitalio/DigitalInOut.h" #include "shared-module/keypad/__init__.h" +#include "shared-module/keypad/EventQueue.h" typedef struct { mp_obj_base_t base; @@ -43,7 +43,7 @@ typedef struct { uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; - ringbuf_t encoded_events; + keypad_eventqueue_obj_t *events; } keypad_keymatrix_obj_t; void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self); diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index bc8549b55b..19fd2acd5c 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -26,20 +26,15 @@ #include "py/gc.h" #include "py/runtime.h" -#include "shared-bindings/keypad/__init__.h" -#include "shared-bindings/keypad/Event.h" -#include "shared-bindings/keypad/Keys.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/keypad/EventQueue.h" +#include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/__init__.h" #include "supervisor/port.h" #include "supervisor/shared/tick.h" #define DEBOUNCE_TICKS (20) -// Top bit of 16-bit event indicates pressed or released. Rest is key_num. -#define EVENT_PRESSED (1 << 15) -#define EVENT_RELEASED (0) -#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) - void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events) { mp_obj_t dios[num_pins]; @@ -59,8 +54,10 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->value_when_pressed = value_when_pressed; self->last_scan_ticks = port_get_raw_ticks(NULL); - // Event queue is 16-bit values. - ringbuf_alloc(&self->encoded_events, max_events * 2, false); + keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); + events->base.type = &keypad_eventqueue_type; + common_hal_keypad_eventqueue_construct(events, max_events); + self->events = events; // Add self to the list of active keypad scanners. keypad_register_scanner((keypad_scanner_obj_t *)self); @@ -94,20 +91,8 @@ bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) return self->currently_pressed[key_num]; } -mp_obj_t common_hal_keypad_keys_next_event(keypad_keys_obj_t *self) { - int encoded_event = ringbuf_get16(&self->encoded_events); - if (encoded_event == -1) { - return MP_ROM_NONE; - } - - keypad_event_obj_t *event = m_new_obj(keypad_event_obj_t); - event->base.type = &keypad_event_type; - common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); - return MP_OBJ_FROM_PTR(event); -} - -void common_hal_keypad_keys_clear_events(keypad_keys_obj_t *self) { - ringbuf_clear(&self->encoded_events); +mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) { + return MP_OBJ_FROM_PTR(self->events); } void keypad_keys_scan(keypad_keys_obj_t *self) { @@ -129,13 +114,10 @@ void keypad_keys_scan(keypad_keys_obj_t *self) { common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == self->value_when_pressed; self->currently_pressed[key_num] = current; + // Record any transitions. if (previous != current) { - if (ringbuf_num_empty(&self->encoded_events) == 0) { - // Discard oldest if full. - ringbuf_get16(&self->encoded_events); - } - ringbuf_put16(&self->encoded_events, key_num | (current ? EVENT_PRESSED : EVENT_RELEASED)); + keypad_eventqueue_record(self->events, key_num, current); } } } diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 03eb65d635..7aea31bc50 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -29,10 +29,10 @@ #include "py/obj.h" #include "py/objtuple.h" -#include "py/ringbuf.h" #include "common-hal/digitalio/DigitalInOut.h" #include "shared-module/keypad/__init__.h" +#include "shared-module/keypad/EventQueue.h" typedef struct { mp_obj_base_t base; @@ -42,7 +42,7 @@ typedef struct { uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; - ringbuf_t encoded_events; + keypad_eventqueue_obj_t *events; bool value_when_pressed; } keypad_keys_obj_t; From a152bd3b72814497462949187a6dec7040699e09 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 17 Jun 2021 12:02:54 -0400 Subject: [PATCH 23/38] add .num_keys and .store_states() to Keys and KeyMatrix --- locale/circuitpython.pot | 8 +++ shared-bindings/keypad/KeyMatrix.c | 88 +++++++++++++++++++++++------- shared-bindings/keypad/KeyMatrix.h | 7 ++- shared-bindings/keypad/Keys.c | 63 ++++++++++++++++++--- shared-bindings/keypad/Keys.h | 3 +- shared-module/keypad/KeyMatrix.c | 27 ++++++--- shared-module/keypad/Keys.c | 16 +++++- shared-module/keypad/__init__.c | 2 +- shared-module/keypad/__init__.h | 3 + 9 files changed, 172 insertions(+), 45 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index d2c2dbe8b4..f9aa9aab52 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -83,6 +83,10 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" +#: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c +msgid "%q length must be %q" +msgstr "" + #: shared-bindings/vectorio/Polygon.c msgid "%q list must be a list" msgstr "" @@ -120,6 +124,10 @@ msgstr "" msgid "%q must be a tuple of length 2" msgstr "" +#: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c +msgid "%q must store bytes" +msgstr "" + #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: shared-bindings/canio/Match.c shared-bindings/keypad/KeyMatrix.c #: shared-bindings/keypad/Keys.c diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 75e434ac3e..d63bfdc0b3 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -25,6 +25,7 @@ */ #include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/keypad/Event.h" @@ -136,25 +137,22 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { } } - -//| def pressed(self, key_num: int) -> None: -//| """Return ``True`` if the given key is pressed. This is a debounced read -//| of the key state which bypasses the `events` `EventQueue`. -//| """ -//| ... +//| num_keys: int +//| """The number of keys that are being scanned. (read-only) +//| """ //| -STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { +STATIC mp_obj_t keypad_keymatrix_get_num_keys(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keymatrix_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); - } - - return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_num)); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keymatrix_get_num_keys(self)); } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_num_keys_obj, keypad_keymatrix_get_num_keys); + +const mp_obj_property_t keypad_keymatrix_num_keys_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_keymatrix_get_num_keys_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; //| def key_num(self, row: int, col: int) -> int: //| """Return the key number for a given row and column. @@ -167,12 +165,12 @@ STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_o check_for_deinit(self); const mp_int_t row = mp_obj_get_int(row_in); - if (row < 0 || (size_t)row >= common_hal_keypad_keymatrix_num_rows(self)) { + if (row < 0 || (size_t)row >= common_hal_keypad_keymatrix_get_num_rows(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_row_num); } const mp_int_t col = mp_obj_get_int(col_in); - if (col < 0 || (size_t)col >= common_hal_keypad_keymatrix_num_cols(self)) { + if (col < 0 || (size_t)col >= common_hal_keypad_keymatrix_get_num_cols(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_col_num); } @@ -181,6 +179,52 @@ STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_o } MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_key_num_obj, keypad_keymatrix_key_num); +//| def pressed(self, key_num: int) -> None: +//| """Return ``True`` if the given key is pressed. This is a debounced read +//| of the key state which bypasses the `events` `EventQueue`. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_int_t key_num = mp_obj_get_int(key_num_in); + if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keymatrix_get_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed); + +//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| """Write the state of all the keys into ``states``. +//| Write a ``1`` if pressed, and ``0`` if released. +//| The ``length`` of ``states`` must be `num_keys`. +//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. +//| The read is done atomically. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_store_states(mp_obj_t self_in, mp_obj_t pressed) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_states); + } + if (bufinfo.len != common_hal_keypad_keymatrix_get_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_states, MP_QSTR_num_keys); + } + + common_hal_keypad_keymatrix_store_states(self, (uint8_t *)bufinfo.buf); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_store_states_obj, keypad_keymatrix_store_states); + //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) //| """ @@ -199,13 +243,15 @@ const mp_obj_property_t keypad_keymatrix_events_obj = { }; STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) }, { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_keymatrix_key_num_obj) }, + { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_keymatrix_num_keys_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_keymatrix_store_states_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table); diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index d6a2cbb074..24ac405a82 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -39,11 +39,12 @@ bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col); -mp_uint_t common_hal_keypad_keymatrix_num_keys(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_num_rows(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_num_keys(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_num_cols(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_num_rows(keypad_keymatrix_obj_t *self); mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num); +void common_hal_keypad_keymatrix_store_states(keypad_keymatrix_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 35a9c0e09b..ccbe034f3c 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -25,6 +25,7 @@ */ #include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/keypad/Event.h" @@ -135,9 +136,26 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { } } +//| num_keys: int +//| """The number of keys that are being scanned. (read-only) +//| """ +//| +STATIC mp_obj_t keypad_keys_get_num_keys(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keys_get_num_keys(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_num_keys_obj, keypad_keys_get_num_keys); + +const mp_obj_property_t keypad_keys_num_keys_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_keys_get_num_keys_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + //| def pressed(self, key_num: int) -> None: -//| """Return ``True`` if the given key is pressed. This is a debounced read -//| of the key state which bypasses the `events` `EventQueue`. +//| """Return ``True`` if the given key is pressed. +// This is a debounced read of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| @@ -146,7 +164,7 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { check_for_deinit(self); mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keys_num_keys(self)) { + if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keys_get_num_keys(self)) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); } @@ -154,6 +172,33 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { } MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); +//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| """Write the states of all the keys into ``states``. +//| Write a ``1`` if pressed, and ``0`` if released. +//| The ``length`` of ``states`` must be `num_keys`. +//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. +//| The read is done atomically. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_store_states(mp_obj_t self_in, mp_obj_t pressed) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); + } + if (bufinfo.len != common_hal_keypad_keys_get_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); + } + + common_hal_keypad_keys_store_states(self, (uint8_t *)bufinfo.buf); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_store_states_obj, keypad_keys_store_states); + //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) //| """ @@ -172,12 +217,14 @@ const mp_obj_property_t keypad_keys_events_obj = { }; STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_keys_num_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_keys_store_states_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 81fc36d3cb..edcf0b2b03 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -38,7 +38,8 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self); -mp_uint_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self); +mp_uint_t common_hal_keypad_keys_get_num_keys(keypad_keys_obj_t *self); bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); +void common_hal_keypad_keys_store_states(keypad_keys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 441f78a448..bd72b4a940 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include + #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/digitalio/DigitalInOut.h" @@ -84,12 +86,12 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { // Remove self from the list of active keypad scanners first. keypad_deregister_scanner((keypad_scanner_obj_t *)self); - for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) { + for (size_t row = 0; row < common_hal_keypad_keymatrix_get_num_rows(self); row++) { common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]); } self->row_digitalinouts = MP_ROM_NONE; - for (size_t col = 0; col < common_hal_keypad_keymatrix_num_cols(self); col++) { + for (size_t col = 0; col < common_hal_keypad_keymatrix_get_num_cols(self); col++) { common_hal_digitalio_digitalinout_deinit(self->col_digitalinouts->items[col]); } self->col_digitalinouts = MP_ROM_NONE; @@ -99,21 +101,30 @@ bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) { return self->row_digitalinouts == MP_ROM_NONE; } -size_t common_hal_keypad_keymatrix_num_keys(keypad_keymatrix_obj_t *self) { - return common_hal_keypad_keymatrix_num_rows(self) * common_hal_keypad_keymatrix_num_cols(self); +size_t common_hal_keypad_keymatrix_get_num_keys(keypad_keymatrix_obj_t *self) { + return common_hal_keypad_keymatrix_get_num_rows(self) * common_hal_keypad_keymatrix_get_num_cols(self); } -size_t common_hal_keypad_keymatrix_num_rows(keypad_keymatrix_obj_t *self) { +size_t common_hal_keypad_keymatrix_get_num_rows(keypad_keymatrix_obj_t *self) { return self->row_digitalinouts->len; } -size_t common_hal_keypad_keymatrix_num_cols(keypad_keymatrix_obj_t *self) { +size_t common_hal_keypad_keymatrix_get_num_cols(keypad_keymatrix_obj_t *self) { return self->col_digitalinouts->len; } bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num) { return self->currently_pressed[key_num]; } + +// The length of states has already been validated. +void common_hal_keypad_keymatrix_store_states(keypad_keymatrix_obj_t *self, uint8_t *states) { + // Read the state atomically. + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memcpy(states, self->currently_pressed, common_hal_keypad_keymatrix_get_num_keys(self)); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { return row_col_to_key_num(self, row, col); } @@ -132,12 +143,12 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { self->last_scan_ticks = now; // On entry, all pins are set to inputs with a pull-up. - for (size_t row = 0; row < common_hal_keypad_keymatrix_num_rows(self); row++) { + for (size_t row = 0; row < common_hal_keypad_keymatrix_get_num_rows(self); row++) { // Switch this row to an output and set to low. common_hal_digitalio_digitalinout_switch_to_output( self->row_digitalinouts->items[row], false, DRIVE_MODE_PUSH_PULL); - for (size_t col = 0; col < common_hal_keypad_keymatrix_num_cols(self); col++) { + for (size_t col = 0; col < common_hal_keypad_keymatrix_get_num_cols(self); col++) { mp_uint_t key_num = row_col_to_key_num(self, row, col); const bool previous = self->currently_pressed[key_num]; self->previously_pressed[key_num] = previous; diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 19fd2acd5c..f8e897c719 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ +#include + #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/digitalio/DigitalInOut.h" @@ -73,7 +75,7 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) { // Remove self from the list of active keypad scanners first. keypad_deregister_scanner((keypad_scanner_obj_t *)self); - for (size_t key = 0; key < common_hal_keypad_keys_num_keys(self); key++) { + for (size_t key = 0; key < common_hal_keypad_keys_get_num_keys(self); key++) { common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]); } self->digitalinouts = MP_ROM_NONE; @@ -84,13 +86,21 @@ bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) { return self->digitalinouts == MP_ROM_NONE; } -size_t common_hal_keypad_keys_num_keys(keypad_keys_obj_t *self) { +size_t common_hal_keypad_keys_get_num_keys(keypad_keys_obj_t *self) { return self->digitalinouts->len; } bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) { return self->currently_pressed[key_num]; } +// The length of states has already been validated. +void common_hal_keypad_keys_store_states(keypad_keys_obj_t *self, uint8_t *states) { + // Read the state atomically. + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memcpy(states, self->currently_pressed, common_hal_keypad_keys_get_num_keys(self)); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) { return MP_OBJ_FROM_PTR(self->events); } @@ -104,7 +114,7 @@ void keypad_keys_scan(keypad_keys_obj_t *self) { self->last_scan_ticks = now; - for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_num_keys(self); key_num++) { + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_get_num_keys(self); key_num++) { // Remember the previous up/down state. const bool previous = self->currently_pressed[key_num]; self->previously_pressed[key_num] = previous; diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index f29f126c3f..4cfa011bad 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -29,7 +29,7 @@ #include "supervisor/shared/lock.h" #include "supervisor/shared/tick.h" -static supervisor_lock_t keypad_scanners_linked_list_lock; +supervisor_lock_t keypad_scanners_linked_list_lock; void keypad_tick(void) { // Fast path. Return immediately if there are no scanners. diff --git a/shared-module/keypad/__init__.h b/shared-module/keypad/__init__.h index de89c310a5..c5b8fe3a0a 100644 --- a/shared-module/keypad/__init__.h +++ b/shared-module/keypad/__init__.h @@ -28,6 +28,7 @@ #define SHARED_MODULE_KEYPAD_H #include "py/obj.h" +#include "supervisor/shared/lock.h" // All scanners must have a next field immediately following base. // This is an ad hoc "superclass" struct for scanners, though they do @@ -37,6 +38,8 @@ typedef struct _keypad_scanner_obj_t { struct _keypad_scanner_obj_t *next; } keypad_scanner_obj_t; +extern supervisor_lock_t keypad_scanners_linked_list_lock; + void keypad_tick(void); void keypad_reset(void); From 04b69cde9b7c7caec170a402b9131bde3812d562 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 17 Jun 2021 13:46:45 -0400 Subject: [PATCH 24/38] turn off gamepad on most builds;turn off keypad where appropriate --- ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk | 1 - ports/atmel-samd/boards/pycubed/mpconfigboard.mk | 2 +- ports/atmel-samd/boards/pycubed_mram/mpconfigboard.mk | 2 +- .../boards/winterbloom_big_honking_button/mpconfigboard.mk | 1 - ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk | 1 - ports/nrf/boards/simmel/mpconfigboard.mk | 2 +- py/circuitpy_mpconfig.mk | 2 +- 7 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk index 300419fa19..d7230df4bb 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.mk @@ -12,7 +12,6 @@ LONGINT_IMPL = NONE # To keep the build small CIRCUITPY_AUDIOBUSIO = 0 -CIRCUITPY_GAMEPAD = 0 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH diff --git a/ports/atmel-samd/boards/pycubed/mpconfigboard.mk b/ports/atmel-samd/boards/pycubed/mpconfigboard.mk index 1eb3cd5239..bbed46dbed 100644 --- a/ports/atmel-samd/boards/pycubed/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pycubed/mpconfigboard.mk @@ -16,8 +16,8 @@ CIRCUITPY_DRIVE_LABEL = "PYCUBED" CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_DISPLAYIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_FRAMEBUFFERIO = 0 -CIRCUITPY_GAMEPAD = 0 CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_PS2IO = 0 diff --git a/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.mk b/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.mk index 0c459c309c..ccf3050d11 100644 --- a/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pycubed_mram/mpconfigboard.mk @@ -17,7 +17,7 @@ CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 -CIRCUITPY_GAMEPAD = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_RGBMATRIX = 0 CIRCUITPY_PS2IO = 0 diff --git a/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk b/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk index 1c96e1d235..7364de0cfe 100644 --- a/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk +++ b/ports/atmel-samd/boards/winterbloom_big_honking_button/mpconfigboard.mk @@ -22,7 +22,6 @@ CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_BLEIO = 0 CIRCUITPY_DISPLAYIO = 0 -CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_TOUCHIO = 0 CIRCUITPY_RGBMATRIX = 0 diff --git a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk index 81956a0b80..bc4fff5018 100644 --- a/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk +++ b/ports/atmel-samd/boards/winterbloom_sol/mpconfigboard.mk @@ -21,7 +21,6 @@ CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 -CIRCUITPY_GAMEPAD = 0 CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_TOUCHIO = 0 CIRCUITPY_RGBMATRIX = 0 diff --git a/ports/nrf/boards/simmel/mpconfigboard.mk b/ports/nrf/boards/simmel/mpconfigboard.mk index e235fd1051..57f83fd3d2 100644 --- a/ports/nrf/boards/simmel/mpconfigboard.mk +++ b/ports/nrf/boards/simmel/mpconfigboard.mk @@ -20,7 +20,7 @@ CIRCUITPY_COUNTIO = 0 CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_ERRNO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 -CIRCUITPY_GAMEPAD = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_NEOPIXEL_WRITE = 0 CIRCUITPY_NVM = 0 diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 9c9e84321e..f4075f0d5a 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -184,7 +184,7 @@ CFLAGS += -DCIRCUITPY__EVE=$(CIRCUITPY__EVE) CIRCUITPY_FREQUENCYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_FREQUENCYIO=$(CIRCUITPY_FREQUENCYIO) -CIRCUITPY_GAMEPAD ?= $(CIRCUITPY_FULL_BUILD) +CIRCUITPY_GAMEPAD ?= 0 CFLAGS += -DCIRCUITPY_GAMEPAD=$(CIRCUITPY_GAMEPAD) CIRCUITPY_GAMEPADSHIFT ?= 0 From af66931f71355f04b3383d5715e15f580a038439 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 17 Jun 2021 20:51:30 -0400 Subject: [PATCH 25/38] Added keypad.ShiftRegisterKeys --- py/circuitpy_defns.mk | 1 + shared-bindings/keypad/ShiftRegisterKeys.c | 239 +++++++++++++++++++++ shared-bindings/keypad/ShiftRegisterKeys.h | 45 ++++ shared-bindings/keypad/__init__.c | 16 +- shared-module/keypad/ShiftRegisterKeys.c | 157 ++++++++++++++ shared-module/keypad/ShiftRegisterKeys.h | 54 +++++ shared-module/keypad/__init__.c | 5 +- 7 files changed, 510 insertions(+), 7 deletions(-) create mode 100644 shared-bindings/keypad/ShiftRegisterKeys.c create mode 100644 shared-bindings/keypad/ShiftRegisterKeys.h create mode 100644 shared-module/keypad/ShiftRegisterKeys.c create mode 100644 shared-module/keypad/ShiftRegisterKeys.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index aa06434368..9756329ac5 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -519,6 +519,7 @@ SRC_SHARED_MODULE_ALL = \ keypad/Event.c \ keypad/EventQueue.c \ keypad/KeyMatrix.c \ + keypad/ShiftRegisterKeys.c \ keypad/Keys.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c new file mode 100644 index 0000000000..31e0baf2f1 --- /dev/null +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -0,0 +1,239 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/keypad/Event.h" +#include "shared-bindings/keypad/ShiftRegisterKeys.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" + +//| class ShiftRegisterKeys: +//| """Manage a set of keys attached to an incoming shift register.""" +//| +//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, level_when_pressed: bool, max_events: int = 64) -> None: +//| """ +//| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register +//| like the 74HC165 or equivalent. +//| Note that you may chain shift registers to load in as many values as you need. +//| +//| Key number 0 is the first (or more properly, the zero-th) bit read. In the +//| 74HC165, this bit is labeled ``Q7``. Key number 1 will be the value of ``Q6``, etc. +//| +//| An `EventQueue` is created when this object is created and is available in the `events` attribute. +//| +//| The keys are debounced by waiting about 20 msecs before reporting a transition. +//| +//| :param microcontroller.Pin clock: The shift register clock pin. +//| The shift register should clock on a low-to-high transition. +//| :param microcontroller.Pin data: the incoming shift register data pin +//| :param microcontroller.Pin latch: +//| Pin used to trigger loading parallel data pins into the shift register. +//| Active low: pull low to load the data. +//| :param int num_keys: number of data lines to clock in +//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. +//| ``False`` if the pin reads low (is grounded) when the key is pressed. +//| :param int max_events: maximum size of `events` `EventQueue`: +//| maximum number of key transition events that are saved. +//| Must be >= 1. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| """ +//| ... + +STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t); + self->base.type = &keypad_shiftregisterkeys_type; + enum { ARG_clock, ARG_data, ARG_latch, ARG_num_keys, ARG_value_when_pressed, ARG_max_events }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_num_keys, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, + { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); + mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj); + mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); + + if (args[ARG_num_keys].u_int < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_num_keys); + } + const size_t num_keys = (size_t)args[ARG_num_keys].u_int; + + const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; + + if (args[ARG_max_events].u_int < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); + } + const size_t max_events = (size_t)args[ARG_max_events].u_int; + + common_hal_keypad_shiftregisterkeys_construct( + self, clock, data, latch, num_keys, value_when_pressed, max_events); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Stop scanning and release the pins.""" +//| ... +//| +STATIC mp_obj_t keypad_shiftregisterkeys_deinit(mp_obj_t self_in) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_shiftregisterkeys_deinit(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_deinit_obj, keypad_shiftregisterkeys_deinit); + +//| def __enter__(self) -> Keys: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t keypad_shiftregisterkeys___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_keypad_shiftregisterkeys_deinit(args[0]); + return MP_ROM_NONE; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_shiftregisterkeys___exit___obj, 4, 4, keypad_shiftregisterkeys___exit__); + +STATIC void check_for_deinit(keypad_shiftregisterkeys_obj_t *self) { + if (common_hal_keypad_shiftregisterkeys_deinited(self)) { + raise_deinited_error(); + } +} + +//| num_keys: int +//| """The number of keys that are being scanned. (read-only) +//| """ +//| +STATIC mp_obj_t keypad_shiftregisterkeys_get_num_keys(mp_obj_t self_in) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_shiftregisterkeys_get_num_keys(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_num_keys_obj, keypad_shiftregisterkeys_get_num_keys); + +const mp_obj_property_t keypad_shiftregisterkeys_num_keys_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_num_keys_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +//| def pressed(self, key_num: int) -> None: +//| """Return ``True`` if the given key is pressed. +// This is a debounced read of the key state which bypasses the `events` `EventQueue`. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_shiftregisterkeys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_int_t key_num = mp_obj_get_int(key_num_in); + if (key_num < 0 || (size_t)key_num >= common_hal_keypad_shiftregisterkeys_get_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); + } + + return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, (mp_uint_t)key_num)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_pressed_obj, keypad_shiftregisterkeys_pressed); + +//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| """Write the states of all the keys into ``states``. +//| Write a ``1`` if pressed, and ``0`` if released. +//| The ``length`` of ``states`` must be `num_keys`. +//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. +//| The read is done atomically. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_shiftregisterkeys_store_states(mp_obj_t self_in, mp_obj_t pressed) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); + } + if (bufinfo.len != common_hal_keypad_shiftregisterkeys_get_num_keys(self)) { + mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); + } + + common_hal_keypad_shiftregisterkeys_store_states(self, (uint8_t *)bufinfo.buf); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_store_states_obj, keypad_shiftregisterkeys_store_states); + +//| events: EventQueue +//| """The `EventQueue` associated with this `Keys` object. (read-only) +//| """ +//| +STATIC mp_obj_t keypad_shiftregisterkeys_get_events(mp_obj_t self_in) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_keypad_shiftregisterkeys_get_events(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_events_obj, keypad_shiftregisterkeys_get_events); + +const mp_obj_property_t keypad_shiftregisterkeys_events_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_events_obj, + MP_ROM_NONE, + MP_ROM_NONE}, +}; + +STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_shiftregisterkeys_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_shiftregisterkeys_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_shiftregisterkeys_num_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_shiftregisterkeys_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_shiftregisterkeys_store_states_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table); + +const mp_obj_type_t keypad_shiftregisterkeys_type = { + { &mp_type_type }, + .name = MP_QSTR_ShiftRegisterKeys, + .make_new = keypad_shiftregisterkeys_make_new, + .locals_dict = (mp_obj_t)&keypad_shiftregisterkeys_locals_dict, +}; diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h new file mode 100644 index 0000000000..6fb6dc94f4 --- /dev/null +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -0,0 +1,45 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H + +#include "py/objlist.h" +#include "shared-module/keypad/ShiftRegisterKeys.h" + +extern const mp_obj_type_t keypad_shiftregisterkeys_type; + +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, size_t max_events); + +void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self); +bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); + +mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self); +mp_uint_t common_hal_keypad_shiftregisterkeys_get_num_keys(keypad_shiftregisterkeys_obj_t *self); +bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_num); +void common_hal_keypad_shiftregisterkeys_store_states(keypad_shiftregisterkeys_obj_t *self, uint8_t *states); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c index 5f6177576e..30d3dd49f0 100644 --- a/shared-bindings/keypad/__init__.c +++ b/shared-bindings/keypad/__init__.c @@ -31,20 +31,24 @@ #include "shared-bindings/keypad/EventQueue.h" #include "shared-bindings/keypad/KeyMatrix.h" #include "shared-bindings/keypad/Keys.h" +#include "shared-bindings/keypad/ShiftRegisterKeys.h" //| """Support for scanning keys and key matrices //| //| The `keypad` module provides native support to scan sets of keys or buttons, -//| connected independently to individual pins, or connected in a row-and-column matrix. +//| connected independently to individual pins, +//| connected to a shift register, +//| or connected in a row-and-column matrix. //| """ //| STATIC mp_map_elem_t keypad_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, - { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) }, - { MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) }, - { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) }, - { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) }, + { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) }, + { MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) }, + { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) }, + { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) }, + { MP_ROM_QSTR(MP_QSTR_ShiftRegisterKeys), MP_OBJ_FROM_PTR(&keypad_shiftregisterkeys_type) }, }; STATIC MP_DEFINE_MUTABLE_DICT(keypad_module_globals, keypad_module_globals_table); diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c new file mode 100644 index 0000000000..0e9ce48555 --- /dev/null +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -0,0 +1,157 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/keypad/EventQueue.h" +#include "shared-bindings/keypad/ShiftRegisterKeys.h" +#include "shared-bindings/keypad/__init__.h" +#include "supervisor/port.h" +#include "supervisor/shared/tick.h" + +#define DEBOUNCE_TICKS (20) + +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, size_t max_events) { + + digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t); + clock->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(clock, clock_pin); + common_hal_digitalio_digitalinout_switch_to_output(clock, false, DRIVE_MODE_PUSH_PULL); + self->clock = clock; + + digitalio_digitalinout_obj_t *data = m_new_obj(digitalio_digitalinout_obj_t); + data->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(data, data_pin); + common_hal_digitalio_digitalinout_switch_to_input(data, PULL_NONE); + self->data = data; + + digitalio_digitalinout_obj_t *latch = m_new_obj(digitalio_digitalinout_obj_t); + latch->base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(latch, latch_pin); + common_hal_digitalio_digitalinout_switch_to_output(latch, true, DRIVE_MODE_PUSH_PULL); + self->latch = latch; + + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); + self->value_when_pressed = value_when_pressed; + self->num_keys = num_keys; + + self->last_scan_ticks = port_get_raw_ticks(NULL); + + keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); + events->base.type = &keypad_eventqueue_type; + common_hal_keypad_eventqueue_construct(events, max_events); + self->events = events; + + // Add self to the list of active keypad scanners. + keypad_register_scanner((keypad_scanner_obj_t *)self); + + supervisor_enable_tick(); +} + +void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self) { + if (common_hal_keypad_shiftregisterkeys_deinited(self)) { + return; + } + + // Remove self from the list of active keypad scanners first. + keypad_deregister_scanner((keypad_scanner_obj_t *)self); + + + common_hal_digitalio_digitalinout_deinit(self->clock); + self->clock = MP_ROM_NONE; + + common_hal_digitalio_digitalinout_deinit(self->data); + self->data = MP_ROM_NONE; + + common_hal_digitalio_digitalinout_deinit(self->latch); + self->latch = MP_ROM_NONE; +} + +bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self) { + return self->clock == MP_ROM_NONE; +} + +size_t common_hal_keypad_shiftregisterkeys_get_num_keys(keypad_shiftregisterkeys_obj_t *self) { + return self->num_keys; +} +bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_num) { + return self->currently_pressed[key_num]; +} + +// The length of states has already been validated. +void common_hal_keypad_shiftregisterkeys_store_states(keypad_shiftregisterkeys_obj_t *self, uint8_t *states) { + // Read the state atomically. + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memcpy(states, self->currently_pressed, common_hal_keypad_shiftregisterkeys_get_num_keys(self)); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + +mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self) { + return MP_OBJ_FROM_PTR(self->events); +} + +void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { + uint64_t now = port_get_raw_ticks(NULL); + if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { + // Too soon. Wait longer to debounce. + return; + } + + self->last_scan_ticks = now; + + // Latch (freeze) the current state of the input pins. + common_hal_digitalio_digitalinout_set_value(self->latch, true); + + for (mp_uint_t key_num = 0; key_num < common_hal_keypad_shiftregisterkeys_get_num_keys(self); key_num++) { + // Zero-th data appears on on the data pin immediately, without shifting. + common_hal_digitalio_digitalinout_set_value(self->clock, false); + + // Remember the previous up/down state. + const bool previous = self->currently_pressed[key_num]; + self->previously_pressed[key_num] = previous; + + // Get the current state. + const bool current = + common_hal_digitalio_digitalinout_get_value(self->data) == self->value_when_pressed; + self->currently_pressed[key_num] = current; + + // Trigger a shift to get the next bit. + common_hal_digitalio_digitalinout_set_value(self->clock, true); + + // Record any transitions. + if (previous != current) { + keypad_eventqueue_record(self->events, key_num, current); + } + } + + // Start reading the input pins again. + common_hal_digitalio_digitalinout_set_value(self->latch, false); + +} diff --git a/shared-module/keypad/ShiftRegisterKeys.h b/shared-module/keypad/ShiftRegisterKeys.h new file mode 100644 index 0000000000..7949ecbb67 --- /dev/null +++ b/shared-module/keypad/ShiftRegisterKeys.h @@ -0,0 +1,54 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H +#define MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H + +#include "py/obj.h" +#include "py/objtuple.h" + +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-module/keypad/__init__.h" +#include "shared-module/keypad/EventQueue.h" + +typedef struct { + mp_obj_base_t base; + // All scanners have a next field here, to keep a linked list of active scanners. + keypad_scanner_obj_t *next; + digitalio_digitalinout_obj_t *clock; + digitalio_digitalinout_obj_t *data; + digitalio_digitalinout_obj_t *latch; + size_t num_keys; + uint64_t last_scan_ticks; + bool *previously_pressed; + bool *currently_pressed; + keypad_eventqueue_obj_t *events; + bool value_when_pressed; +} keypad_shiftregisterkeys_obj_t; + +void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_SHIFTREGISTERKEYS_H diff --git a/shared-module/keypad/__init__.c b/shared-module/keypad/__init__.c index 4cfa011bad..fc41396617 100644 --- a/shared-module/keypad/__init__.c +++ b/shared-module/keypad/__init__.c @@ -26,13 +26,14 @@ #include "shared-bindings/keypad/Keys.h" #include "shared-bindings/keypad/KeyMatrix.h" +#include "shared-bindings/keypad/ShiftRegisterKeys.h" #include "supervisor/shared/lock.h" #include "supervisor/shared/tick.h" supervisor_lock_t keypad_scanners_linked_list_lock; void keypad_tick(void) { - // Fast path. Return immediately if there are no scanners. + // Fast path. Return immediately there are no scanners. if (!MP_STATE_VM(keypad_scanners_linked_list)) { return; } @@ -45,6 +46,8 @@ void keypad_tick(void) { keypad_keys_scan((keypad_keys_obj_t *)scanner); } else if (mp_obj_is_type(scanner, &keypad_keymatrix_type)) { keypad_keymatrix_scan((keypad_keymatrix_obj_t *)scanner); + } else if (mp_obj_is_type(scanner, &keypad_shiftregisterkeys_type)) { + keypad_shiftregisterkeys_scan((keypad_shiftregisterkeys_obj_t *)scanner); } scanner = ((keypad_scanner_obj_t *)scanner)->next; From 8cd7e774e75ede661460078af13db41715780172 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 18 Jun 2021 12:03:47 -0400 Subject: [PATCH 26/38] add KeyMatrix columns_to_anodes arg --- locale/circuitpython.pot | 6 ++++-- shared-bindings/keypad/KeyMatrix.c | 16 ++++++++++------ shared-bindings/keypad/KeyMatrix.h | 2 +- shared-module/keypad/KeyMatrix.c | 29 ++++++++++++++++++----------- shared-module/keypad/KeyMatrix.h | 1 + 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index f9aa9aab52..04c6ead9b7 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -84,6 +84,7 @@ msgid "%q indices must be integers, not %s" msgstr "" #: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c +#: shared-bindings/keypad/ShiftRegisterKeys.c msgid "%q length must be %q" msgstr "" @@ -110,7 +111,7 @@ msgstr "" #: shared-bindings/_bleio/CharacteristicBuffer.c #: shared-bindings/_bleio/PacketBuffer.c shared-bindings/displayio/Group.c #: shared-bindings/displayio/Shape.c shared-bindings/keypad/KeyMatrix.c -#: shared-bindings/keypad/Keys.c +#: shared-bindings/keypad/Keys.c shared-bindings/keypad/ShiftRegisterKeys.c #: shared-bindings/memorymonitor/AllocationAlarm.c #: shared-bindings/vectorio/Circle.c shared-bindings/vectorio/Rectangle.c msgid "%q must be >= 1" @@ -125,12 +126,13 @@ msgid "%q must be a tuple of length 2" msgstr "" #: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c +#: shared-bindings/keypad/ShiftRegisterKeys.c msgid "%q must store bytes" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: shared-bindings/canio/Match.c shared-bindings/keypad/KeyMatrix.c -#: shared-bindings/keypad/Keys.c +#: shared-bindings/keypad/Keys.c shared-bindings/keypad/ShiftRegisterKeys.c msgid "%q out of range" msgstr "" diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index d63bfdc0b3..98cefa0198 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -36,12 +36,10 @@ //| class KeyMatrix: //| """Manage a 2D matrix of keys with row and column pins.""" //| -//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], max_events: int = 64) -> None: +//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan the key matrix attached to the given row and column pins. -//| If the matrix uses diodes, the diode anodes should be connected to the column pins, -//| and the cathodes should be connected to the row pins. If your diodes are reversed, -//| simply exchange the row and column pin sequences. +//| There should not be any pull-ups or pull-downs on the matrix. //| //| The keys are numbered sequentially from zero. A key number can be computed //| by ``row * len(col_pins) + col``. @@ -52,6 +50,11 @@ //| //| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows. //| :param Sequence[microcontroller.Pin] col_pins: The pins attached to the colums. +//| :param bool columns_to_anodes: Default ``True``. +//| If the matrix uses diodes, the diode anodes are typically connected to the column pins, +//| and the cathodes should be connected to the row pins. If your diodes are reversed, +//| set ``columns_to_anodes`` to ``False``. +//| //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -62,10 +65,11 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t); self->base.type = &keypad_keymatrix_type; - enum { ARG_row_pins, ARG_col_pins, ARG_max_events }; + enum { ARG_row_pins, ARG_col_pins, ARG_columns_to_anodes, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -98,7 +102,7 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar col_pins_array[col] = pin; } - common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, max_events); + common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, args[ARG_columns_to_anodes].u_bool, max_events); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 24ac405a82..59df6830e9 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_keymatrix_type; -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events); +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, size_t max_events); void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index bd72b4a940..5aa7f95e5f 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -42,14 +42,14 @@ static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, return row * self->col_digitalinouts->len + col; } -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], size_t max_events) { +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, size_t max_events) { mp_obj_t row_dios[num_row_pins]; for (size_t row = 0; row < num_row_pins; row++) { digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); dio->base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(dio, row_pins[row]); - common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); + common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN); row_dios[row] = dio; } self->row_digitalinouts = mp_obj_new_tuple(num_row_pins, row_dios); @@ -59,7 +59,7 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); dio->base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(dio, col_pins[col]); - common_hal_digitalio_digitalinout_switch_to_input(dio, PULL_UP); + common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN); col_dios[col] = dio; } self->col_digitalinouts = mp_obj_new_tuple(num_col_pins, col_dios); @@ -67,6 +67,8 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); + self->columns_to_anodes = columns_to_anodes; + keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); events->base.type = &keypad_eventqueue_type; common_hal_keypad_eventqueue_construct(events, max_events); @@ -142,21 +144,25 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { self->last_scan_ticks = now; - // On entry, all pins are set to inputs with a pull-up. + // On entry, all pins are set to inputs with a pull-up or pull-down, + // depending on the diode orientation. for (size_t row = 0; row < common_hal_keypad_keymatrix_get_num_rows(self); row++) { - // Switch this row to an output and set to low. + // Switch this row to an output and set level appropriately + // Set low if columns_to_anodes is true, else set high. common_hal_digitalio_digitalinout_switch_to_output( - self->row_digitalinouts->items[row], false, DRIVE_MODE_PUSH_PULL); + self->row_digitalinouts->items[row], !self->columns_to_anodes, DRIVE_MODE_PUSH_PULL); for (size_t col = 0; col < common_hal_keypad_keymatrix_get_num_cols(self); col++) { mp_uint_t key_num = row_col_to_key_num(self, row, col); const bool previous = self->currently_pressed[key_num]; self->previously_pressed[key_num] = previous; - // Get the current state, by reading whether the col got pulled down or not. - // If low, the key is pressed. + // Get the current state, by reading whether the col got pulled to the row value or not. + // If low and columns_to_anodes is true, the key is pressed. + // If high and columns_to_anodes is false, the key is pressed. const bool current = - !common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[col]); + common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[col]) != + self->columns_to_anodes; self->currently_pressed[key_num] = current; // Record any transitions. @@ -165,7 +171,8 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { } } - // Switch the row back to an input, pulled up. - common_hal_digitalio_digitalinout_switch_to_input(self->row_digitalinouts->items[row], PULL_UP); + // Switch the row back to an input, pulled appropriately + common_hal_digitalio_digitalinout_switch_to_input( + self->row_digitalinouts->items[row], self->columns_to_anodes ? PULL_UP : PULL_DOWN); } } diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index 253067890a..14c6f8069c 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -44,6 +44,7 @@ typedef struct { bool *previously_pressed; bool *currently_pressed; keypad_eventqueue_obj_t *events; + bool columns_to_anodes; } keypad_keymatrix_obj_t; void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self); From 03adbbca7c9861584ac96b8e4652367b61b9f5f7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 18 Jun 2021 12:26:48 -0400 Subject: [PATCH 27/38] turn off keypad by default on all SAMD21, for now --- ports/atmel-samd/mpconfigport.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index d0ef189f41..cb8fae6f07 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -50,6 +50,7 @@ CIRCUITPY_FRAMEBUFFERIO ?= 0 CIRCUITPY_FREQUENCYIO ?= 0 CIRCUITPY_I2CPERIPHERAL ?= 0 CIRCUITPY_JSON ?= 0 +CIRCUITPY_KEYPAD ?= 0 CIRCUITPY_MSGPACK ?= 0 CIRCUITPY_RE ?= 0 CIRCUITPY_SDCARDIO ?= 0 From db297add6713ddf79e8dfc12dc38adfda46c1b5b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 18 Jun 2021 13:20:31 -0400 Subject: [PATCH 28/38] fix other too-big builds --- ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk | 1 + ports/stm/boards/meowbit_v121/mpconfigboard.mk | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk index d7b8a4bb1e..c2c583022c 100644 --- a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk @@ -15,6 +15,7 @@ CIRCUITPY_AUDIOMP3 = 0 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_KEYPAD = 0 CIRCUITPY_MSGPACK = 0 CIRCUITPY_PS2IO = 0 CIRCUITPY_RGBMATRIX = 0 diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index dc44095a31..d846755c28 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -20,4 +20,5 @@ LD_FILE = boards/STM32F401xe_boot.ld # For debugging - also comment BOOTLOADER_OFFSET and BOARD_VTOR_DEFER # LD_FILE = boards/STM32F401xe_fs.ld +CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_ULAB = 0 From 154e91ab855115979bd0a73766cf7392dccfc3b4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 21 Jun 2021 08:18:06 -0400 Subject: [PATCH 29/38] add EventQueue.store_next() to allow reusing event objects --- locale/circuitpython.pot | 4 ++++ shared-bindings/keypad/Event.c | 6 ++--- shared-bindings/keypad/EventQueue.c | 34 +++++++++++++++++++++++++++-- shared-bindings/keypad/EventQueue.h | 5 +++-- shared-module/keypad/EventQueue.c | 14 ++++++++++++ 5 files changed, 56 insertions(+), 7 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 04c6ead9b7..b399aba91f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -949,6 +949,10 @@ msgstr "" msgid "Expected a UUID" msgstr "" +#: shared-bindings/keypad/EventQueue.c +msgid "Expected an %q" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Expected an Address" msgstr "" diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 7abd75e54d..22f3b6b37d 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -32,7 +32,7 @@ //| class Event: //| """A key transition event.""" -//| def __init__(self, key_num: int, pressed: bool) -> None: +//| def __init__(self, key_num: int=0, pressed: bool=True) -> None: //| """Create a key transition event, which reports a key-pressed or key-released transition. //| //| :param int key_num: the key number @@ -46,8 +46,8 @@ STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, self->base.type = &keypad_event_type; enum { ARG_key_num, ARG_pressed }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_key_num, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_pressed, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_key_num, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_pressed, MP_ARG_BOOL, {.u_bool = true} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index 9ffebf3662..8cd3e74986 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -25,6 +25,7 @@ */ #include "py/runtime.h" +#include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/EventQueue.h" //| class EventQueue: @@ -54,6 +55,34 @@ STATIC mp_obj_t keypad_eventqueue_next(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_next_obj, keypad_eventqueue_next); +//| def store_next(self, Event: event) -> bool: +//| """Store the next key transition event in the supplied event, if available, +//| and return ``True``. +//| If there are no queued events, do not touch ``event`` and return ``False``. +//| +//| The advantage of this method over ``next()`` is that it does not allocate storage. +//| Instead you can reuse an existing ``Event`` object. +//| +//| Note that the queue size is limited; see ``max_events`` in the constructor of +//| a scanner such as `Keys` or `KeyMatrix`. +//| If a new event arrives when the queue is full, the oldest event is discarded. +//| +//| :return ``True`` if an event was available and stored, ``False`` if not. +//| :rtype: bool +//| """ +//| ... +//| +STATIC mp_obj_t keypad_eventqueue_store_next(mp_obj_t self_in, mp_obj_t event_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!mp_obj_is_type(event_in, &keypad_event_type)) { + mp_raise_ValueError_varg(translate("Expected an %q"), MP_QSTR_Event); + } + keypad_event_obj_t *event = MP_OBJ_TO_PTR(event_in); + return mp_obj_new_bool(common_hal_keypad_eventqueue_store_next(self, event)); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_store_next_obj, keypad_eventqueue_store_next); + //| def clear(self) -> None: //| """Clear any queued key transition events. //| """ @@ -91,8 +120,9 @@ STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&keypad_eventqueue_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&keypad_eventqueue_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_store_next), MP_ROM_PTR(&keypad_eventqueue_store_next_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table); diff --git a/shared-bindings/keypad/EventQueue.h b/shared-bindings/keypad/EventQueue.h index d6b2ac32c6..6faa2971fd 100644 --- a/shared-bindings/keypad/EventQueue.h +++ b/shared-bindings/keypad/EventQueue.h @@ -27,8 +27,8 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H -#include "py/objlist.h" -#include "shared-module/keypad/Keys.h" +#include "shared-module/keypad/Event.h" +#include "shared-module/keypad/EventQueue.h" extern const mp_obj_type_t keypad_eventqueue_type; @@ -37,5 +37,6 @@ void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_ void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self); size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self); mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self); +bool common_hal_keypad_eventqueue_store_next(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c index e75d93106a..556e425e4b 100644 --- a/shared-module/keypad/EventQueue.c +++ b/shared-module/keypad/EventQueue.c @@ -49,6 +49,20 @@ mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self) { return MP_OBJ_FROM_PTR(event); } +bool common_hal_keypad_eventqueue_store_next(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event) { + int encoded_event = ringbuf_get16(&self->encoded_events); + if (encoded_event == -1) { + return false; + } + + // "Construct" using the existing event. + common_hal_keypad_event_construct(event, encoded_event & EVENT_KEY_NUM_MASK, encoded_event & EVENT_PRESSED); + return true; +} + + + + void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) { ringbuf_clear(&self->encoded_events); } From a718d3315707887cebe3458e4cb3655e07c0f8b0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 21 Jun 2021 09:04:26 -0400 Subject: [PATCH 30/38] fix doc typos --- shared-bindings/imagecapture/ParallelImageCapture.c | 2 +- shared-bindings/keypad/EventQueue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/imagecapture/ParallelImageCapture.c b/shared-bindings/imagecapture/ParallelImageCapture.c index 8e8991339b..59a6f256e6 100644 --- a/shared-bindings/imagecapture/ParallelImageCapture.c +++ b/shared-bindings/imagecapture/ParallelImageCapture.c @@ -43,7 +43,7 @@ //| clock: microcontroller.Pin, //| vsync: Optional[microcontroller.Pin], //| href: Optional[microcontroller.Pin], -//| ): +//| ) -> None: //| """Create a parallel image capture object //| //| :param List[microcontroller.Pin] data_pins: The data pins. diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index 8cd3e74986..e9d1054c78 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -55,7 +55,7 @@ STATIC mp_obj_t keypad_eventqueue_next(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_next_obj, keypad_eventqueue_next); -//| def store_next(self, Event: event) -> bool: +//| def store_next(self, event: Event) -> bool: //| """Store the next key transition event in the supplied event, if available, //| and return ``True``. //| If there are no queued events, do not touch ``event`` and return ``False``. From 51c547a5b9e9b84af3e5d2490718853a88af9c61 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 21 Jun 2021 12:13:39 -0400 Subject: [PATCH 31/38] add generic arg validation routines; add interval args to keypad --- locale/circuitpython.pot | 35 +++++++++------ py/argcheck.c | 51 ++++++++++++++++++++++ py/runtime.h | 8 ++++ shared-bindings/keypad/Event.c | 7 +-- shared-bindings/keypad/EventQueue.c | 6 +-- shared-bindings/keypad/KeyMatrix.c | 43 ++++++++---------- shared-bindings/keypad/KeyMatrix.h | 2 +- shared-bindings/keypad/Keys.c | 28 ++++++------ shared-bindings/keypad/Keys.h | 2 +- shared-bindings/keypad/ShiftRegisterKeys.c | 37 +++++++--------- shared-bindings/keypad/ShiftRegisterKeys.h | 2 +- shared-module/keypad/KeyMatrix.c | 9 ++-- shared-module/keypad/KeyMatrix.h | 1 + shared-module/keypad/Keys.c | 8 ++-- shared-module/keypad/Keys.h | 1 + shared-module/keypad/ShiftRegisterKeys.c | 7 ++- shared-module/keypad/ShiftRegisterKeys.h | 1 + 17 files changed, 151 insertions(+), 97 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 23f4dd7baa..0c21d69438 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -83,8 +83,7 @@ msgstr "" msgid "%q indices must be integers, not %s" msgstr "" -#: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c -#: shared-bindings/keypad/ShiftRegisterKeys.c +#: py/argcheck.c msgid "%q length must be %q" msgstr "" @@ -92,6 +91,14 @@ msgstr "" msgid "%q list must be a list" msgstr "" +#: py/argcheck.c +msgid "%q must <= %d" +msgstr "" + +#: py/argcheck.c +msgid "%q must be %d-%d" +msgstr "" + #: shared-bindings/usb_hid/Device.c msgid "%q must be 0-255" msgstr "" @@ -100,18 +107,17 @@ msgstr "" msgid "%q must be 1-255" msgstr "" -#: shared-bindings/keypad/Event.c -msgid "%q must be > 0" +#: py/argcheck.c +msgid "%q must be >= %d" msgstr "" -#: shared-bindings/memorymonitor/AllocationAlarm.c +#: py/argcheck.c shared-bindings/memorymonitor/AllocationAlarm.c msgid "%q must be >= 0" msgstr "" #: shared-bindings/_bleio/CharacteristicBuffer.c #: shared-bindings/_bleio/PacketBuffer.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/Shape.c shared-bindings/keypad/KeyMatrix.c -#: shared-bindings/keypad/Keys.c shared-bindings/keypad/ShiftRegisterKeys.c +#: shared-bindings/displayio/Shape.c #: shared-bindings/memorymonitor/AllocationAlarm.c #: shared-bindings/vectorio/Circle.c shared-bindings/vectorio/Rectangle.c msgid "%q must be >= 1" @@ -121,6 +127,10 @@ msgstr "" msgid "%q must be None or between 1 and len(report_descriptor)-1" msgstr "" +#: py/argcheck.c +msgid "%q must be a string" +msgstr "" + #: shared-module/vectorio/Polygon.c msgid "%q must be a tuple of length 2" msgstr "" @@ -129,14 +139,17 @@ msgstr "" msgid "%q must be between %d and %d" msgstr "" +#: py/argcheck.c +msgid "%q must of type %q" +msgstr "" + #: shared-bindings/keypad/KeyMatrix.c shared-bindings/keypad/Keys.c #: shared-bindings/keypad/ShiftRegisterKeys.c msgid "%q must store bytes" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: shared-bindings/canio/Match.c shared-bindings/keypad/KeyMatrix.c -#: shared-bindings/keypad/Keys.c shared-bindings/keypad/ShiftRegisterKeys.c +#: shared-bindings/canio/Match.c msgid "%q out of range" msgstr "" @@ -953,10 +966,6 @@ msgstr "" msgid "Expected a UUID" msgstr "" -#: shared-bindings/keypad/EventQueue.c -msgid "Expected an %q" -msgstr "" - #: shared-bindings/_bleio/Adapter.c msgid "Expected an Address" msgstr "" diff --git a/py/argcheck.c b/py/argcheck.c index 8d26779b91..7710cf1592 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -162,3 +162,54 @@ NORETURN void mp_arg_error_unimpl_kw(void) { mp_raise_NotImplementedError(MP_ERROR_TEXT("keyword argument(s) not yet implemented - use normal args instead")); } #endif + + +mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name) { + if (i < min) { + mp_raise_ValueError_varg(translate("%q must be >= %d"), arg_name, min); + } + return i; +} + +mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t max, qstr arg_name) { + if (i > max) { + mp_raise_ValueError_varg(translate("%q must <= %d"), arg_name, max); + } + return i; +} + +mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name) { + if (i < min || i > max) { + mp_raise_ValueError_varg(translate("%q must be %d-%d"), arg_name, min, max); + } + return i; +} + +mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name) { + const mp_float_t f = (float_in == MP_OBJ_NULL) + ? default_for_null + : mp_obj_get_float(float_in); + if (f <= 0.0f) { + mp_raise_ValueError_varg(translate("%q must be >= 0"), arg_name); + } + return f; +} + +size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name) { + mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); + return (size_t)i; +} + +mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name) { + if (!mp_obj_is_type(obj, type)) { + mp_raise_TypeError_varg(translate("%q must of type %q"), arg_name, type->name); + } + return obj; +} + +mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name) { + if (!mp_obj_is_str(obj)) { + mp_raise_TypeError_varg(translate("%q must be a string"), arg_name); + } + return obj; +} diff --git a/py/runtime.h b/py/runtime.h index a8a3120eef..c16cbe80d7 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -90,6 +90,14 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, NORETURN void mp_arg_error_terse_mismatch(void); NORETURN void mp_arg_error_unimpl_kw(void); +mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name); +mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name); +mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name); +mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t default_for_null, qstr arg_name); +size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name); +mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name); +mp_obj_t mp_arg_validate_string(mp_obj_t obj, qstr arg_name); + static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_locals_get)(void) { return MP_STATE_THREAD(dict_locals); } diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 22f3b6b37d..ff1323eac0 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -52,12 +52,9 @@ STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mp_int_t key_num = args[ARG_key_num].u_int; - if (key_num < 0) { - mp_raise_ValueError_varg(translate("%q must be > 0"), MP_QSTR_key_num); - } + const mp_uint_t key_num = (mp_uint_t)mp_arg_validate_int_min(args[ARG_key_num].u_int, 0, MP_QSTR_key_num); - common_hal_keypad_event_construct(self, (mp_uint_t)key_num, args[ARG_pressed].u_bool); + common_hal_keypad_event_construct(self, key_num, args[ARG_pressed].u_bool); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index e9d1054c78..ae544a6665 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -75,10 +75,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_next_obj, keypad_eventqueue_next); STATIC mp_obj_t keypad_eventqueue_store_next(mp_obj_t self_in, mp_obj_t event_in) { keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (!mp_obj_is_type(event_in, &keypad_event_type)) { - mp_raise_ValueError_varg(translate("Expected an %q"), MP_QSTR_Event); - } - keypad_event_obj_t *event = MP_OBJ_TO_PTR(event_in); + keypad_event_obj_t *event = MP_OBJ_TO_PTR(mp_arg_validate_type(event_in, &keypad_event_type, MP_QSTR_event)); + return mp_obj_new_bool(common_hal_keypad_eventqueue_store_next(self, event)); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_store_next_obj, keypad_eventqueue_store_next); diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 98cefa0198..f2c80b42e5 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -36,7 +36,7 @@ //| class KeyMatrix: //| """Manage a 2D matrix of keys with row and column pins.""" //| -//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, max_events: int = 64) -> None: +//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan the key matrix attached to the given row and column pins. //| There should not be any pull-ups or pull-downs on the matrix. @@ -54,7 +54,8 @@ //| If the matrix uses diodes, the diode anodes are typically connected to the column pins, //| and the cathodes should be connected to the row pins. If your diodes are reversed, //| set ``columns_to_anodes`` to ``False``. -//| +//| :param float interval: Scan keys no more often +//| to allow for debouncing. Given in seconds. //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -65,11 +66,12 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t); self->base.type = &keypad_keymatrix_type; - enum { ARG_row_pins, ARG_col_pins, ARG_columns_to_anodes, ARG_max_events }; + enum { ARG_row_pins, ARG_col_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -82,10 +84,9 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar mp_obj_t col_pins = args[ARG_col_pins].u_obj; const size_t num_col_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(col_pins)); - if (args[ARG_max_events].u_int < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); - } - const size_t max_events = (size_t)args[ARG_max_events].u_int; + const mp_float_t interval = + mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); + const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); mcu_pin_obj_t *row_pins_array[num_row_pins]; mcu_pin_obj_t *col_pins_array[num_col_pins]; @@ -102,7 +103,7 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar col_pins_array[col] = pin; } - common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, args[ARG_columns_to_anodes].u_bool, max_events); + common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events); return MP_OBJ_FROM_PTR(self); } @@ -168,18 +169,14 @@ STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_o keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - const mp_int_t row = mp_obj_get_int(row_in); - if (row < 0 || (size_t)row >= common_hal_keypad_keymatrix_get_num_rows(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_row_num); - } + const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range( + mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_rows(self), MP_QSTR_row); - const mp_int_t col = mp_obj_get_int(col_in); - if (col < 0 || (size_t)col >= common_hal_keypad_keymatrix_get_num_cols(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_col_num); - } + const mp_int_t col = (mp_uint_t)mp_arg_validate_int_range( + mp_obj_get_int(col_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_cols(self), MP_QSTR_col); return MP_OBJ_NEW_SMALL_INT( - (mp_int_t)common_hal_keypad_keymatrix_key_num(self, (mp_uint_t)row, (mp_uint_t)col)); + (mp_int_t)common_hal_keypad_keymatrix_key_num(self, row, col)); } MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_key_num_obj, keypad_keymatrix_key_num); @@ -193,10 +190,8 @@ STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keymatrix_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); - } + mp_uint_t key_num = mp_arg_validate_int_range( + mp_obj_get_int(key_num_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_keys(self), MP_QSTR_key_num); return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_num)); } @@ -220,9 +215,9 @@ STATIC mp_obj_t keypad_keymatrix_store_states(mp_obj_t self_in, mp_obj_t pressed if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_states); } - if (bufinfo.len != common_hal_keypad_keymatrix_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_states, MP_QSTR_num_keys); - } + + (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_keymatrix_get_num_keys(self), + MP_QSTR_states, MP_QSTR_num_keys); common_hal_keypad_keymatrix_store_states(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 59df6830e9..72e1847c44 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_keymatrix_type; -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, size_t max_events); +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events); void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index ccbe034f3c..6286104be4 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -36,7 +36,7 @@ //| class Keys: //| """Manage a set of independent keys.""" //| -//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, max_events: int = 64) -> None: +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to the given sequence of pins. //| Each key is independent and attached to its own pin. @@ -56,6 +56,8 @@ //| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. //| However, enabling an internal pull when an external one is already present is not a problem; //| it simply uses slightly more current. +//| :param float interval: Scan keys no more often +//| to allow for debouncing. Given in seconds. //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -66,11 +68,12 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t); self->base.type = &keypad_keys_type; - enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_max_events }; + enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -81,11 +84,9 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins)); const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; - - if (args[ARG_max_events].u_int < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); - } - const size_t max_events = (size_t)args[ARG_max_events].u_int; + const mp_float_t interval = + mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); + const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); mcu_pin_obj_t *pins_array[num_pins]; @@ -95,7 +96,7 @@ STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, c pins_array[i] = pin; } - common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, max_events); + common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events); return MP_OBJ_FROM_PTR(self); } @@ -163,10 +164,8 @@ STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || (size_t)key_num >= common_hal_keypad_keys_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); - } + const mp_int_t key_num = mp_obj_get_int(key_num_in); + (void)mp_arg_validate_int_range(key_num, 0, common_hal_keypad_keys_get_num_keys(self), MP_QSTR_key_num); return mp_obj_new_bool(common_hal_keypad_keys_pressed(self, (mp_uint_t)key_num)); } @@ -190,9 +189,8 @@ STATIC mp_obj_t keypad_keys_store_states(mp_obj_t self_in, mp_obj_t pressed) { if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); } - if (bufinfo.len != common_hal_keypad_keys_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); - } + (void)mp_arg_validate_length_with_name(bufinfo.len,common_hal_keypad_keys_get_num_keys(self), + MP_QSTR_pressed, MP_QSTR_num_keys); common_hal_keypad_keys_store_states(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index edcf0b2b03..6160b8b959 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_keys_type; -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events); +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events); void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 31e0baf2f1..583e20e243 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -36,7 +36,7 @@ //| class ShiftRegisterKeys: //| """Manage a set of keys attached to an incoming shift register.""" //| -//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, level_when_pressed: bool, max_events: int = 64) -> None: +//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, level_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register //| like the 74HC165 or equivalent. @@ -58,6 +58,8 @@ //| :param int num_keys: number of data lines to clock in //| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. //| ``False`` if the pin reads low (is grounded) when the key is pressed. +//| :param float interval: Scan keys no more often +//| to allow for debouncing. Given in seconds. //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -68,13 +70,14 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t); self->base.type = &keypad_shiftregisterkeys_type; - enum { ARG_clock, ARG_data, ARG_latch, ARG_num_keys, ARG_value_when_pressed, ARG_max_events }; + enum { ARG_clock, ARG_data, ARG_latch, ARG_num_keys, ARG_value_when_pressed, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_num_keys, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -84,20 +87,14 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj); mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); - if (args[ARG_num_keys].u_int < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_num_keys); - } - const size_t num_keys = (size_t)args[ARG_num_keys].u_int; - + const size_t num_keys = (size_t)mp_arg_validate_int_min(args[ARG_num_keys].u_int, 1, MP_QSTR_num_keys); const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; - - if (args[ARG_max_events].u_int < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_max_events); - } - const size_t max_events = (size_t)args[ARG_max_events].u_int; + const mp_float_t interval = + mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); + const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); common_hal_keypad_shiftregisterkeys_construct( - self, clock, data, latch, num_keys, value_when_pressed, max_events); + self, clock, data, latch, num_keys, value_when_pressed, interval, max_events); return MP_OBJ_FROM_PTR(self); } @@ -165,12 +162,11 @@ STATIC mp_obj_t keypad_shiftregisterkeys_pressed(mp_obj_t self_in, mp_obj_t key_ keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_int_t key_num = mp_obj_get_int(key_num_in); - if (key_num < 0 || (size_t)key_num >= common_hal_keypad_shiftregisterkeys_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_key_num); - } + mp_uint_t key_num = mp_arg_validate_int_range( + mp_obj_get_int(key_num_in), 0, (mp_int_t)common_hal_keypad_shiftregisterkeys_get_num_keys(self), + MP_QSTR_key_num); - return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, (mp_uint_t)key_num)); + return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, key_num)); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_pressed_obj, keypad_shiftregisterkeys_pressed); @@ -192,9 +188,8 @@ STATIC mp_obj_t keypad_shiftregisterkeys_store_states(mp_obj_t self_in, mp_obj_t if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); } - if (bufinfo.len != common_hal_keypad_shiftregisterkeys_get_num_keys(self)) { - mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); - } + (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_shiftregisterkeys_get_num_keys(self), + MP_QSTR_states, MP_QSTR_num_keys); common_hal_keypad_shiftregisterkeys_store_states(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index 6fb6dc94f4..bf33f08e59 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_shiftregisterkeys_type; -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, size_t max_events); +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events); void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self); bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 5aa7f95e5f..8ac3abe837 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -36,13 +36,11 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -#define DEBOUNCE_TICKS (20) - static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { return row * self->col_digitalinouts->len + col; } -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, size_t max_events) { +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) { mp_obj_t row_dios[num_row_pins]; for (size_t row = 0; row < num_row_pins; row++) { @@ -74,6 +72,9 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint common_hal_keypad_eventqueue_construct(events, max_events); self->events = events; + self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) + self->last_scan_ticks = port_get_raw_ticks(NULL); + // Add self to the list of active keypad scanners. keypad_register_scanner((keypad_scanner_obj_t *)self); @@ -137,7 +138,7 @@ mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self) { void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); - if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { + if (now - self->last_scan_ticks < self->interval_ticks) { // Too soon. Wait longer to debounce. return; } diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index 14c6f8069c..4f789aa382 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -40,6 +40,7 @@ typedef struct { keypad_scanner_obj_t *next; mp_obj_tuple_t *row_digitalinouts; mp_obj_tuple_t *col_digitalinouts; + mp_uint_t interval_ticks; uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index f8e897c719..5f5d2f3880 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -35,9 +35,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -#define DEBOUNCE_TICKS (20) - -void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, size_t max_events) { +void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events) { mp_obj_t dios[num_pins]; for (size_t i = 0; i < num_pins; i++) { @@ -54,6 +52,8 @@ void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pin self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_pins, false, false); self->value_when_pressed = value_when_pressed; + + self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) self->last_scan_ticks = port_get_raw_ticks(NULL); keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); @@ -107,7 +107,7 @@ mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) { void keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); - if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { + if (now - self->last_scan_ticks < self->interval_ticks) { // Too soon. Wait longer to debounce. return; } diff --git a/shared-module/keypad/Keys.h b/shared-module/keypad/Keys.h index 7aea31bc50..3edae32439 100644 --- a/shared-module/keypad/Keys.h +++ b/shared-module/keypad/Keys.h @@ -39,6 +39,7 @@ typedef struct { // All scanners have a next field here, to keep a linked list of active scanners. keypad_scanner_obj_t *next; mp_obj_tuple_t *digitalinouts; + mp_uint_t interval_ticks; uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 0e9ce48555..80dd7b5bd4 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -35,9 +35,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -#define DEBOUNCE_TICKS (20) - -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, size_t max_events) { +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events) { digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t); clock->base.type = &digitalio_digitalinout_type; @@ -62,6 +60,7 @@ void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_ self->value_when_pressed = value_when_pressed; self->num_keys = num_keys; + self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) self->last_scan_ticks = port_get_raw_ticks(NULL); keypad_eventqueue_obj_t *events = m_new_obj(keypad_eventqueue_obj_t); @@ -119,7 +118,7 @@ mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); - if (now - self->last_scan_ticks < DEBOUNCE_TICKS) { + if (now - self->last_scan_ticks < self->interval_ticks) { // Too soon. Wait longer to debounce. return; } diff --git a/shared-module/keypad/ShiftRegisterKeys.h b/shared-module/keypad/ShiftRegisterKeys.h index 7949ecbb67..f0eb6abdf6 100644 --- a/shared-module/keypad/ShiftRegisterKeys.h +++ b/shared-module/keypad/ShiftRegisterKeys.h @@ -42,6 +42,7 @@ typedef struct { digitalio_digitalinout_obj_t *data; digitalio_digitalinout_obj_t *latch; size_t num_keys; + mp_uint_t interval_ticks; uint64_t last_scan_ticks; bool *previously_pressed; bool *currently_pressed; From 8c74b4a5f21513de9de7d7c387de104ac672bb0d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 21 Jun 2021 17:47:12 -0400 Subject: [PATCH 32/38] fix some typos --- py/argcheck.c | 6 ++++-- shared-bindings/keypad/Keys.c | 2 +- shared-bindings/keypad/ShiftRegisterKeys.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/py/argcheck.c b/py/argcheck.c index 7710cf1592..8b6588a556 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -189,14 +189,16 @@ mp_float_t mp_arg_validate_obj_float_non_negative(mp_obj_t float_in, mp_float_t const mp_float_t f = (float_in == MP_OBJ_NULL) ? default_for_null : mp_obj_get_float(float_in); - if (f <= 0.0f) { + if (f <= (mp_float_t)0.0) { mp_raise_ValueError_varg(translate("%q must be >= 0"), arg_name); } return f; } size_t mp_arg_validate_length_with_name(mp_int_t i, size_t length, qstr arg_name, qstr length_name) { - mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); + if (i != (mp_int_t)length) { + mp_raise_ValueError_varg(translate("%q length must be %q"), MP_QSTR_pressed, MP_QSTR_num_keys); + } return (size_t)i; } diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 6286104be4..5f1d0ecc7d 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -36,7 +36,7 @@ //| class Keys: //| """Manage a set of independent keys.""" //| -//| def __init__(self, pins: Sequence[microcontroller.Pin], *, level_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None: +//| def __init__(self, pins: Sequence[microcontroller.Pin], *, value_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to the given sequence of pins. //| Each key is independent and attached to its own pin. diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 583e20e243..7896ed7a38 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -36,7 +36,7 @@ //| class ShiftRegisterKeys: //| """Manage a set of keys attached to an incoming shift register.""" //| -//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, level_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: +//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register //| like the 74HC165 or equivalent. From f052dc4d8ba020858528228cd5c5ce2e2f20019f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 21 Jun 2021 19:03:48 -0400 Subject: [PATCH 33/38] ShiftRegisterKeys: allow specifying sense of latch --- shared-bindings/keypad/ShiftRegisterKeys.c | 18 ++++++++++++------ shared-bindings/keypad/ShiftRegisterKeys.h | 2 +- shared-module/keypad/ShiftRegisterKeys.c | 8 ++++---- shared-module/keypad/ShiftRegisterKeys.h | 1 + 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 7896ed7a38..2946ba3f98 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -36,10 +36,10 @@ //| class ShiftRegisterKeys: //| """Manage a set of keys attached to an incoming shift register.""" //| -//| def __init__(self, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: +//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, num_keys: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register -//| like the 74HC165 or equivalent. +//| like the 74HC165 or CD4021. //| Note that you may chain shift registers to load in as many values as you need. //| //| Key number 0 is the first (or more properly, the zero-th) bit read. In the @@ -53,8 +53,12 @@ //| The shift register should clock on a low-to-high transition. //| :param microcontroller.Pin data: the incoming shift register data pin //| :param microcontroller.Pin latch: -//| Pin used to trigger loading parallel data pins into the shift register. -//| Active low: pull low to load the data. +//| Pin used to latch parallel data going into the shift register. +//| :param bool value_to_latch: Pin state to latch data being read. +//| ``True`` if the data is latched when ``latch`` goes high +//| ``False`` if the data is latched when ``latch goes low. +//| The default is ``True``, which is how the 74HC165 operates. The CD4021 latch is the opposite. +//| Once the data is latched, it will be shifted out by toggling the clock pin. //| :param int num_keys: number of data lines to clock in //| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. //| ``False`` if the pin reads low (is grounded) when the key is pressed. @@ -70,11 +74,12 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t); self->base.type = &keypad_shiftregisterkeys_type; - enum { ARG_clock, ARG_data, ARG_latch, ARG_num_keys, ARG_value_when_pressed, ARG_interval, ARG_max_events }; + enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_num_keys, ARG_value_when_pressed, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_value_to_latch, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_num_keys, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, @@ -86,6 +91,7 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj); mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); + const bool value_to_latch = args[ARG_value_to_latch].u_bool; const size_t num_keys = (size_t)mp_arg_validate_int_min(args[ARG_num_keys].u_int, 1, MP_QSTR_num_keys); const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; @@ -94,7 +100,7 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); common_hal_keypad_shiftregisterkeys_construct( - self, clock, data, latch, num_keys, value_when_pressed, interval, max_events); + self, clock, data, latch, value_to_latch, num_keys, value_when_pressed, interval, max_events); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index bf33f08e59..6a27d3cc73 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -32,7 +32,7 @@ extern const mp_obj_type_t keypad_shiftregisterkeys_type; -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events); +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events); void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self); bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 80dd7b5bd4..5d7d956632 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -35,7 +35,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events) { +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events) { digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t); clock->base.type = &digitalio_digitalinout_type; @@ -54,6 +54,7 @@ void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_ common_hal_digitalio_digitalinout_construct(latch, latch_pin); common_hal_digitalio_digitalinout_switch_to_output(latch, true, DRIVE_MODE_PUSH_PULL); self->latch = latch; + self->value_to_latch = value_to_latch; self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); @@ -126,7 +127,7 @@ void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { self->last_scan_ticks = now; // Latch (freeze) the current state of the input pins. - common_hal_digitalio_digitalinout_set_value(self->latch, true); + common_hal_digitalio_digitalinout_set_value(self->latch, self->value_to_latch); for (mp_uint_t key_num = 0; key_num < common_hal_keypad_shiftregisterkeys_get_num_keys(self); key_num++) { // Zero-th data appears on on the data pin immediately, without shifting. @@ -151,6 +152,5 @@ void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { } // Start reading the input pins again. - common_hal_digitalio_digitalinout_set_value(self->latch, false); - + common_hal_digitalio_digitalinout_set_value(self->latch, !self->value_to_latch); } diff --git a/shared-module/keypad/ShiftRegisterKeys.h b/shared-module/keypad/ShiftRegisterKeys.h index f0eb6abdf6..c685a7141c 100644 --- a/shared-module/keypad/ShiftRegisterKeys.h +++ b/shared-module/keypad/ShiftRegisterKeys.h @@ -48,6 +48,7 @@ typedef struct { bool *currently_pressed; keypad_eventqueue_obj_t *events; bool value_when_pressed; + bool value_to_latch; } keypad_shiftregisterkeys_obj_t; void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self); From acf90fbb43f399970c66a34d2a0258b56bb306ef Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 23 Jun 2021 09:18:40 -0400 Subject: [PATCH 34/38] many renamings; add overflowed flag to EventQuque --- shared-bindings/keypad/Event.c | 49 ++++---- shared-bindings/keypad/Event.h | 5 +- shared-bindings/keypad/EventQueue.c | 53 ++++++-- shared-bindings/keypad/EventQueue.h | 7 +- shared-bindings/keypad/KeyMatrix.c | 135 +++++++++++++-------- shared-bindings/keypad/KeyMatrix.h | 15 +-- shared-bindings/keypad/Keys.c | 46 ++++--- shared-bindings/keypad/Keys.h | 6 +- shared-bindings/keypad/ShiftRegisterKeys.c | 60 +++++---- shared-bindings/keypad/ShiftRegisterKeys.h | 8 +- shared-module/keypad/Event.c | 8 +- shared-module/keypad/Event.h | 2 +- shared-module/keypad/EventQueue.c | 40 +++--- shared-module/keypad/EventQueue.h | 3 +- shared-module/keypad/KeyMatrix.c | 81 +++++++------ shared-module/keypad/KeyMatrix.h | 2 +- shared-module/keypad/Keys.c | 32 +++-- shared-module/keypad/ShiftRegisterKeys.c | 38 +++--- shared-module/keypad/ShiftRegisterKeys.h | 2 +- 19 files changed, 346 insertions(+), 246 deletions(-) diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index ff1323eac0..11cd0c120c 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -32,44 +32,44 @@ //| class Event: //| """A key transition event.""" -//| def __init__(self, key_num: int=0, pressed: bool=True) -> None: +//| def __init__(self, key_number: int=0, pressed: bool=True) -> None: //| """Create a key transition event, which reports a key-pressed or key-released transition. //| -//| :param int key_num: the key number +//| :param int key_number: the key number //| :param bool pressed: ``True`` if the key was pressed; ``False`` if it was released. //| """ //| ... //| - STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_event_obj_t *self = m_new_obj(keypad_event_obj_t); self->base.type = &keypad_event_type; - enum { ARG_key_num, ARG_pressed }; + enum { ARG_key_number, ARG_pressed }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_key_num, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_pressed, MP_ARG_BOOL, {.u_bool = true} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mp_uint_t key_num = (mp_uint_t)mp_arg_validate_int_min(args[ARG_key_num].u_int, 0, MP_QSTR_key_num); + const mp_uint_t key_number = + (mp_uint_t)mp_arg_validate_int_min(args[ARG_key_number].u_int, 0, MP_QSTR_key_number); - common_hal_keypad_event_construct(self, key_num, args[ARG_pressed].u_bool); + common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool); return MP_OBJ_FROM_PTR(self); } -//| key_num: int +//| key_number: int //| """The key number.""" //| -STATIC mp_obj_t keypad_event_get_key_num(mp_obj_t self_in) { +STATIC mp_obj_t keypad_event_get_key_number(mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_num(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_number(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_num_obj, keypad_event_get_key_num); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_number_obj, keypad_event_get_key_number); -const mp_obj_property_t keypad_event_key_num_obj = { +const mp_obj_property_t keypad_event_key_number_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&keypad_event_get_key_num_obj, + .proxy = {(mp_obj_t)&keypad_event_get_key_number_obj, MP_ROM_NONE, MP_ROM_NONE}, }; @@ -111,7 +111,7 @@ const mp_obj_property_t keypad_event_released_obj = { }; //| def __eq__(self, other: object) -> bool: -//| """Two `Event` objects are equal if their `key_num` +//| """Two `Event` objects are equal if their `key_number` //| and `pressed`/`released` values are equal. //| """ //| ... @@ -123,10 +123,11 @@ STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_ob keypad_event_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); keypad_event_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); return mp_obj_new_bool( - (common_hal_keypad_event_get_key_num(lhs) == - common_hal_keypad_event_get_key_num(rhs)) && + (common_hal_keypad_event_get_key_number(lhs) == + common_hal_keypad_event_get_key_number(rhs)) && (common_hal_keypad_event_get_pressed(lhs) == - common_hal_keypad_event_get_pressed(rhs))); + common_hal_keypad_event_get_pressed(rhs)) + ); } else { return mp_const_false; } @@ -144,9 +145,9 @@ STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self); switch (op) { case MP_UNARY_OP_HASH: { - const mp_int_t key_num = common_hal_keypad_event_get_key_num(self); + const mp_int_t key_number = common_hal_keypad_event_get_key_number(self); const bool pressed = common_hal_keypad_event_get_pressed(self); - return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_num); + return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_number); } default: return MP_OBJ_NULL; // op not supported @@ -155,16 +156,16 @@ STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) { STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "", - common_hal_keypad_event_get_key_num(self), + mp_printf(print, "", + common_hal_keypad_event_get_key_number(self), common_hal_keypad_event_get_pressed(self) ? "pressed" : "released"); } STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = { // Properties - { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_event_key_num_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_number), MP_ROM_PTR(&keypad_event_key_number_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table); diff --git a/shared-bindings/keypad/Event.h b/shared-bindings/keypad/Event.h index 23017f1dc5..35cfdcdc64 100644 --- a/shared-bindings/keypad/Event.h +++ b/shared-bindings/keypad/Event.h @@ -32,10 +32,9 @@ extern const mp_obj_type_t keypad_event_type; -void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_num, bool pressed); -mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self); +void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_number, bool pressed); +mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self); bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self); bool common_hal_keypad_event_get_released(keypad_event_obj_t *self); - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index ae544a6665..72bbd06452 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/keypad/Event.h" #include "shared-bindings/keypad/EventQueue.h" @@ -36,50 +37,50 @@ //| """ //| ... -//| def next(self) -> Optional[Event]: +//| def get(self) -> Optional[Event]: //| """Return the next key transition event. Return ``None`` if no events are pending. //| //| Note that the queue size is limited; see ``max_events`` in the constructor of //| a scanner such as `Keys` or `KeyMatrix`. -//| If a new event arrives when the queue is full, the oldest event is discarded. +//| If a new event arrives when the queue is full, the queue is cleared, and +//| `overflowed` is set to ``True``. //| //| :return: the next queued key transition `Event` //| :rtype: Optional[Event] //| """ //| ... //| -STATIC mp_obj_t keypad_eventqueue_next(mp_obj_t self_in) { +STATIC mp_obj_t keypad_eventqueue_get(mp_obj_t self_in) { keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_keypad_eventqueue_next(self); + return common_hal_keypad_eventqueue_get(self); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_next_obj, keypad_eventqueue_next); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_obj, keypad_eventqueue_get); -//| def store_next(self, event: Event) -> bool: +//| def get_into(self, event: Event) -> bool: //| """Store the next key transition event in the supplied event, if available, //| and return ``True``. //| If there are no queued events, do not touch ``event`` and return ``False``. //| -//| The advantage of this method over ``next()`` is that it does not allocate storage. +//| The advantage of this method over ``get()`` is that it does not allocate storage. //| Instead you can reuse an existing ``Event`` object. //| //| Note that the queue size is limited; see ``max_events`` in the constructor of //| a scanner such as `Keys` or `KeyMatrix`. -//| If a new event arrives when the queue is full, the oldest event is discarded. //| //| :return ``True`` if an event was available and stored, ``False`` if not. //| :rtype: bool //| """ //| ... //| -STATIC mp_obj_t keypad_eventqueue_store_next(mp_obj_t self_in, mp_obj_t event_in) { +STATIC mp_obj_t keypad_eventqueue_get_into(mp_obj_t self_in, mp_obj_t event_in) { keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); keypad_event_obj_t *event = MP_OBJ_TO_PTR(mp_arg_validate_type(event_in, &keypad_event_type, MP_QSTR_event)); - return mp_obj_new_bool(common_hal_keypad_eventqueue_store_next(self, event)); + return mp_obj_new_bool(common_hal_keypad_eventqueue_get_into(self, event)); } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_store_next_obj, keypad_eventqueue_store_next); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_get_into_obj, keypad_eventqueue_get_into); //| def clear(self) -> None: //| """Clear any queued key transition events. @@ -117,10 +118,36 @@ STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +//| overflowed: bool +//| """``True`` if an event could not be added to the event queue because it was full. +//| When this happens, the event queue is cleared. +//| The `overflowed` flag is persistent. Reset it by setting it to ``False``. +//| """ +//| +STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_keypad_eventqueue_get_overflowed(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_overflowed_obj, keypad_eventqueue_get_overflowed); + +STATIC mp_obj_t keypad_eventqueue_set_overflowed(mp_obj_t self_in, mp_obj_t overflowed_in) { + keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_keypad_eventqueue_set_overflowed(self, mp_obj_is_true(overflowed_in)); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_set_overflowed_obj, keypad_eventqueue_set_overflowed); + +const mp_obj_property_t keypad_eventqueue_overflowed_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&keypad_eventqueue_get_overflowed_obj, + (mp_obj_t)&keypad_eventqueue_set_overflowed_obj, + MP_ROM_NONE}, +}; + STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) }, - { MP_ROM_QSTR(MP_QSTR_next), MP_ROM_PTR(&keypad_eventqueue_next_obj) }, - { MP_ROM_QSTR(MP_QSTR_store_next), MP_ROM_PTR(&keypad_eventqueue_store_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&keypad_eventqueue_get_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_into), MP_ROM_PTR(&keypad_eventqueue_get_into_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table); diff --git a/shared-bindings/keypad/EventQueue.h b/shared-bindings/keypad/EventQueue.h index 6faa2971fd..fbbd9df0cb 100644 --- a/shared-bindings/keypad/EventQueue.h +++ b/shared-bindings/keypad/EventQueue.h @@ -36,7 +36,10 @@ void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_ void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self); size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self); -mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self); -bool common_hal_keypad_eventqueue_store_next(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event); +mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self); +bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event); + +bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self); +void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index f2c80b42e5..fc29f67e33 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -36,26 +36,25 @@ //| class KeyMatrix: //| """Manage a 2D matrix of keys with row and column pins.""" //| -//| def __init__(self, row_pins: Sequence[microcontroller.Pin], col_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None: +//| def __init__(self, row_pins: Sequence[microcontroller.Pin], column_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan the key matrix attached to the given row and column pins. -//| There should not be any pull-ups or pull-downs on the matrix. +//| There should not be any external pull-ups or pull-downs on the matrix: +//| ``KeyMatrix`` enables internal pull-ups or pull-downs on the pins as necessary. //| //| The keys are numbered sequentially from zero. A key number can be computed -//| by ``row * len(col_pins) + col``. +//| by ``row * len(column_pins) + column``. //| //| An `EventQueue` is created when this object is created and is available in the `events` attribute. //| -//| The keys are debounced by waiting about 20 msecs before reporting a transition. -//| //| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows. -//| :param Sequence[microcontroller.Pin] col_pins: The pins attached to the colums. +//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the colums. //| :param bool columns_to_anodes: Default ``True``. //| If the matrix uses diodes, the diode anodes are typically connected to the column pins, //| and the cathodes should be connected to the row pins. If your diodes are reversed, //| set ``columns_to_anodes`` to ``False``. -//| :param float interval: Scan keys no more often -//| to allow for debouncing. Given in seconds. +//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing. +//| ``interval`` is in float seconds. The default is 0.020 (20 msecs). //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -66,10 +65,10 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t); self->base.type = &keypad_keymatrix_type; - enum { ARG_row_pins, ARG_col_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events }; + enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_col_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, @@ -81,15 +80,15 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar // mp_obj_len() will be >= 0. const size_t num_row_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_pins)); - mp_obj_t col_pins = args[ARG_col_pins].u_obj; - const size_t num_col_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(col_pins)); + mp_obj_t column_pins = args[ARG_column_pins].u_obj; + const size_t num_column_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(column_pins)); const mp_float_t interval = mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); mcu_pin_obj_t *row_pins_array[num_row_pins]; - mcu_pin_obj_t *col_pins_array[num_col_pins]; + mcu_pin_obj_t *column_pins_array[num_column_pins]; for (size_t row = 0; row < num_row_pins; row++) { mcu_pin_obj_t *pin = @@ -97,13 +96,13 @@ STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar row_pins_array[row] = pin; } - for (size_t col = 0; col < num_col_pins; col++) { + for (size_t column = 0; column < num_column_pins; column++) { mcu_pin_obj_t *pin = - validate_obj_is_free_pin(mp_obj_subscr(col_pins, MP_OBJ_NEW_SMALL_INT(col), MP_OBJ_SENTINEL)); - col_pins_array[col] = pin; + validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL)); + column_pins_array[column] = pin; } - common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_col_pins, col_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events); + common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events); return MP_OBJ_FROM_PTR(self); } @@ -142,71 +141,102 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { } } -//| num_keys: int +//| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ //| -STATIC mp_obj_t keypad_keymatrix_get_num_keys(mp_obj_t self_in) { +STATIC mp_obj_t keypad_keymatrix_get_key_count(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keymatrix_get_num_keys(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keymatrix_get_key_count(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_num_keys_obj, keypad_keymatrix_get_num_keys); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_key_count_obj, keypad_keymatrix_get_key_count); -const mp_obj_property_t keypad_keymatrix_num_keys_obj = { +const mp_obj_property_t keypad_keymatrix_key_count_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&keypad_keymatrix_get_num_keys_obj, + .proxy = {(mp_obj_t)&keypad_keymatrix_get_key_count_obj, MP_ROM_NONE, MP_ROM_NONE}, }; -//| def key_num(self, row: int, col: int) -> int: -//| """Return the key number for a given row and column. -//| The key number is calculated by ``row * len(col_pins) + col``. +//| def key_number_to_row_column(self, row: int, column: int) -> Tuple[int]: +//| """Return the row and column for the given key number. +//| The row is ``key_number // len(column_pins)``. +//| The column is ``key_number % len(column_pins)``. +//| +//| :return: ``(row, column)`` +//| :rtype: Tuple[int] //| """ //| ... //| -STATIC mp_obj_t keypad_keymatrix_key_num(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t col_in) { +STATIC mp_obj_t keypad_keymatrix_key_number_to_row_column(mp_obj_t self_in, mp_obj_t key_number_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range( + mp_obj_get_int(key_number_in), + 0, (mp_int_t)common_hal_keypad_keymatrix_get_key_count(self), + MP_QSTR_key_number); + + mp_uint_t row; + mp_uint_t column; + common_hal_keypad_keymatrix_key_number_to_row_column(self, key_number, &row, &column); + + mp_obj_t row_column[2]; + row_column[0] = MP_OBJ_NEW_SMALL_INT(row); + row_column[1] = MP_OBJ_NEW_SMALL_INT(column); + + return mp_obj_new_tuple(2, row_column); +} +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_key_number_to_row_column_obj, keypad_keymatrix_key_number_to_row_column); + +//| def row_column_to_key_number(self, row: int, column: int) -> int: +//| """Return the key number for a given row and column. +//| The key number is ``row * len(column_pins) + column``. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t column_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_rows(self), MP_QSTR_row); + mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self), MP_QSTR_row); - const mp_int_t col = (mp_uint_t)mp_arg_validate_int_range( - mp_obj_get_int(col_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_cols(self), MP_QSTR_col); + const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range( + mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self), MP_QSTR_column); return MP_OBJ_NEW_SMALL_INT( - (mp_int_t)common_hal_keypad_keymatrix_key_num(self, row, col)); + (mp_int_t)common_hal_keypad_keymatrix_row_column_to_key_number(self, row, column)); } -MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_key_num_obj, keypad_keymatrix_key_num); +MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_keymatrix_row_column_to_key_number); -//| def pressed(self, key_num: int) -> None: +//| def pressed(self, key_number: int) -> None: //| """Return ``True`` if the given key is pressed. This is a debounced read //| of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| -STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { +STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_uint_t key_num = mp_arg_validate_int_range( - mp_obj_get_int(key_num_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_num_keys(self), MP_QSTR_key_num); + mp_uint_t key_number = mp_arg_validate_int_range( + mp_obj_get_int(key_number_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_key_count(self), MP_QSTR_key_number); - return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_num)); + return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_number)); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed); -//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: //| """Write the state of all the keys into ``states``. //| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `num_keys`. +//| The ``length`` of ``states`` must be `key_count`. //| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. //| The read is done atomically. //| """ //| ... //| -STATIC mp_obj_t keypad_keymatrix_store_states(mp_obj_t self_in, mp_obj_t pressed) { +STATIC mp_obj_t keypad_keymatrix_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); @@ -216,13 +246,13 @@ STATIC mp_obj_t keypad_keymatrix_store_states(mp_obj_t self_in, mp_obj_t pressed mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_states); } - (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_keymatrix_get_num_keys(self), - MP_QSTR_states, MP_QSTR_num_keys); + (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_keymatrix_get_key_count(self), + MP_QSTR_states, MP_QSTR_key_count); - common_hal_keypad_keymatrix_store_states(self, (uint8_t *)bufinfo.buf); + common_hal_keypad_keymatrix_get_states_into(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_store_states_obj, keypad_keymatrix_store_states); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_get_states_into_obj, keypad_keymatrix_get_states_into); //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) @@ -242,15 +272,16 @@ const mp_obj_property_t keypad_keymatrix_events_obj = { }; STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_key_num), MP_ROM_PTR(&keypad_keymatrix_key_num_obj) }, - { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_keymatrix_num_keys_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_keymatrix_store_states_obj) }, + { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keymatrix_get_states_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_keymatrix_key_number_to_row_column_obj) }, + { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keymatrix_key_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table); diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 72e1847c44..98152f759a 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -32,19 +32,20 @@ extern const mp_obj_type_t keypad_keymatrix_type; -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events); +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events); void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col); +void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column); +mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column); -mp_uint_t common_hal_keypad_keymatrix_get_num_keys(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_get_num_cols(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_get_num_rows(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self); +mp_uint_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self); mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self); -bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num); -void common_hal_keypad_keymatrix_store_states(keypad_keymatrix_obj_t *self, uint8_t *states); +bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_keymatrix_get_states_into(keypad_keymatrix_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 5f1d0ecc7d..95e68e9bd1 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -43,8 +43,6 @@ //| //| An `EventQueue` is created when this object is created and is available in the `events` attribute. //| -//| The keys are debounced by waiting about 20 msecs before reporting a transition. -//| //| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys. //| The key numbers correspond to indices into this sequence. //| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. @@ -56,8 +54,8 @@ //| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``. //| However, enabling an internal pull when an external one is already present is not a problem; //| it simply uses slightly more current. -//| :param float interval: Scan keys no more often -//| to allow for debouncing. Given in seconds. +//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing. +//| ``interval`` is in float seconds. The default is 0.020 (20 msecs). //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -137,50 +135,50 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { } } -//| num_keys: int +//| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ //| -STATIC mp_obj_t keypad_keys_get_num_keys(mp_obj_t self_in) { +STATIC mp_obj_t keypad_keys_get_key_count(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keys_get_num_keys(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keys_get_key_count(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_num_keys_obj, keypad_keys_get_num_keys); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_key_count_obj, keypad_keys_get_key_count); -const mp_obj_property_t keypad_keys_num_keys_obj = { +const mp_obj_property_t keypad_keys_key_count_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&keypad_keys_get_num_keys_obj, + .proxy = {(mp_obj_t)&keypad_keys_get_key_count_obj, MP_ROM_NONE, MP_ROM_NONE}, }; -//| def pressed(self, key_num: int) -> None: +//| def pressed(self, key_number: int) -> None: //| """Return ``True`` if the given key is pressed. // This is a debounced read of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| -STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { +STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - const mp_int_t key_num = mp_obj_get_int(key_num_in); - (void)mp_arg_validate_int_range(key_num, 0, common_hal_keypad_keys_get_num_keys(self), MP_QSTR_key_num); + const mp_int_t key_number = mp_obj_get_int(key_number_in); + (void)mp_arg_validate_int_range(key_number, 0, common_hal_keypad_keys_get_key_count(self), MP_QSTR_key_number); - return mp_obj_new_bool(common_hal_keypad_keys_pressed(self, (mp_uint_t)key_num)); + return mp_obj_new_bool(common_hal_keypad_keys_pressed(self, (mp_uint_t)key_number)); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); -//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: //| """Write the states of all the keys into ``states``. //| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `num_keys`. +//| The ``length`` of ``states`` must be `key_count`. //| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. //| The read is done atomically. //| """ //| ... //| -STATIC mp_obj_t keypad_keys_store_states(mp_obj_t self_in, mp_obj_t pressed) { +STATIC mp_obj_t keypad_keys_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); @@ -189,13 +187,13 @@ STATIC mp_obj_t keypad_keys_store_states(mp_obj_t self_in, mp_obj_t pressed) { if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); } - (void)mp_arg_validate_length_with_name(bufinfo.len,common_hal_keypad_keys_get_num_keys(self), - MP_QSTR_pressed, MP_QSTR_num_keys); + (void)mp_arg_validate_length_with_name(bufinfo.len,common_hal_keypad_keys_get_key_count(self), + MP_QSTR_pressed, MP_QSTR_key_count); - common_hal_keypad_keys_store_states(self, (uint8_t *)bufinfo.buf); + common_hal_keypad_keys_get_states_into(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_store_states_obj, keypad_keys_store_states); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_get_states_into_obj, keypad_keys_get_states_into); //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) @@ -220,9 +218,9 @@ STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_keys_num_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keys_key_count_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_keys_store_states_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keys_get_states_into_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 6160b8b959..3ac3dd43b2 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -38,8 +38,8 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self); -mp_uint_t common_hal_keypad_keys_get_num_keys(keypad_keys_obj_t *self); -bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num); -void common_hal_keypad_keys_store_states(keypad_keys_obj_t *self, uint8_t *states); +mp_uint_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self); +bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_keys_get_states_into(keypad_keys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 2946ba3f98..e5d959348c 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -36,7 +36,7 @@ //| class ShiftRegisterKeys: //| """Manage a set of keys attached to an incoming shift register.""" //| -//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, num_keys: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: +//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, key_count: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None: //| """ //| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register //| like the 74HC165 or CD4021. @@ -47,8 +47,6 @@ //| //| An `EventQueue` is created when this object is created and is available in the `events` attribute. //| -//| The keys are debounced by waiting about 20 msecs before reporting a transition. -//| //| :param microcontroller.Pin clock: The shift register clock pin. //| The shift register should clock on a low-to-high transition. //| :param microcontroller.Pin data: the incoming shift register data pin @@ -59,11 +57,11 @@ //| ``False`` if the data is latched when ``latch goes low. //| The default is ``True``, which is how the 74HC165 operates. The CD4021 latch is the opposite. //| Once the data is latched, it will be shifted out by toggling the clock pin. -//| :param int num_keys: number of data lines to clock in +//| :param int key_count: number of data lines to clock in //| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed. //| ``False`` if the pin reads low (is grounded) when the key is pressed. -//| :param float interval: Scan keys no more often -//| to allow for debouncing. Given in seconds. +//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing. +//| ``interval`` is in float seconds. The default is 0.020 (20 msecs). //| :param int max_events: maximum size of `events` `EventQueue`: //| maximum number of key transition events that are saved. //| Must be >= 1. @@ -74,13 +72,13 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t); self->base.type = &keypad_shiftregisterkeys_type; - enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_num_keys, ARG_value_when_pressed, ARG_interval, ARG_max_events }; + enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_value_to_latch, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_num_keys, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_key_count, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL }, { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, @@ -93,14 +91,14 @@ STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj); const bool value_to_latch = args[ARG_value_to_latch].u_bool; - const size_t num_keys = (size_t)mp_arg_validate_int_min(args[ARG_num_keys].u_int, 1, MP_QSTR_num_keys); + const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count); const bool value_when_pressed = args[ARG_value_when_pressed].u_bool; const mp_float_t interval = mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval); const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); common_hal_keypad_shiftregisterkeys_construct( - self, clock, data, latch, value_to_latch, num_keys, value_when_pressed, interval, max_events); + self, clock, data, latch, value_to_latch, key_count, value_when_pressed, interval, max_events); return MP_OBJ_FROM_PTR(self); } @@ -141,51 +139,51 @@ STATIC void check_for_deinit(keypad_shiftregisterkeys_obj_t *self) { } } -//| num_keys: int +//| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ //| -STATIC mp_obj_t keypad_shiftregisterkeys_get_num_keys(mp_obj_t self_in) { +STATIC mp_obj_t keypad_shiftregisterkeys_get_key_count(mp_obj_t self_in) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_shiftregisterkeys_get_num_keys(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_shiftregisterkeys_get_key_count(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_num_keys_obj, keypad_shiftregisterkeys_get_num_keys); +MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_key_count_obj, keypad_shiftregisterkeys_get_key_count); -const mp_obj_property_t keypad_shiftregisterkeys_num_keys_obj = { +const mp_obj_property_t keypad_shiftregisterkeys_key_count_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_num_keys_obj, + .proxy = {(mp_obj_t)&keypad_shiftregisterkeys_get_key_count_obj, MP_ROM_NONE, MP_ROM_NONE}, }; -//| def pressed(self, key_num: int) -> None: +//| def pressed(self, key_number: int) -> None: //| """Return ``True`` if the given key is pressed. // This is a debounced read of the key state which bypasses the `events` `EventQueue`. //| """ //| ... //| -STATIC mp_obj_t keypad_shiftregisterkeys_pressed(mp_obj_t self_in, mp_obj_t key_num_in) { +STATIC mp_obj_t keypad_shiftregisterkeys_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - mp_uint_t key_num = mp_arg_validate_int_range( - mp_obj_get_int(key_num_in), 0, (mp_int_t)common_hal_keypad_shiftregisterkeys_get_num_keys(self), - MP_QSTR_key_num); + mp_uint_t key_number = mp_arg_validate_int_range( + mp_obj_get_int(key_number_in), 0, (mp_int_t)common_hal_keypad_shiftregisterkeys_get_key_count(self), + MP_QSTR_key_number); - return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, key_num)); + return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, key_number)); } MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_pressed_obj, keypad_shiftregisterkeys_pressed); -//| def store_states(self, states: _typing.WriteableBuffer) -> None: +//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: //| """Write the states of all the keys into ``states``. //| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `num_keys`. +//| The ``length`` of ``states`` must be `key_count`. //| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. //| The read is done atomically. //| """ //| ... //| -STATIC mp_obj_t keypad_shiftregisterkeys_store_states(mp_obj_t self_in, mp_obj_t pressed) { +STATIC mp_obj_t keypad_shiftregisterkeys_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); @@ -194,13 +192,13 @@ STATIC mp_obj_t keypad_shiftregisterkeys_store_states(mp_obj_t self_in, mp_obj_t if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); } - (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_shiftregisterkeys_get_num_keys(self), - MP_QSTR_states, MP_QSTR_num_keys); + (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_shiftregisterkeys_get_key_count(self), + MP_QSTR_states, MP_QSTR_key_count); - common_hal_keypad_shiftregisterkeys_store_states(self, (uint8_t *)bufinfo.buf); + common_hal_keypad_shiftregisterkeys_get_states_into(self, (uint8_t *)bufinfo.buf); return MP_ROM_NONE; } -MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_store_states_obj, keypad_shiftregisterkeys_store_states); +MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_get_states_into_obj, keypad_shiftregisterkeys_get_states_into); //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) @@ -225,9 +223,9 @@ STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_shiftregisterkeys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_num_keys), MP_ROM_PTR(&keypad_shiftregisterkeys_num_keys_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_shiftregisterkeys_key_count_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_shiftregisterkeys_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_store_states), MP_ROM_PTR(&keypad_shiftregisterkeys_store_states_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_shiftregisterkeys_get_states_into_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index 6a27d3cc73..9aced14466 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -32,14 +32,14 @@ extern const mp_obj_type_t keypad_shiftregisterkeys_type; -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events); +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events); void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self); bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self); -mp_uint_t common_hal_keypad_shiftregisterkeys_get_num_keys(keypad_shiftregisterkeys_obj_t *self); -bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_num); -void common_hal_keypad_shiftregisterkeys_store_states(keypad_shiftregisterkeys_obj_t *self, uint8_t *states); +mp_uint_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self); +bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_shiftregisterkeys_get_states_into(keypad_shiftregisterkeys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H diff --git a/shared-module/keypad/Event.c b/shared-module/keypad/Event.c index 21b4ad18d3..d938002cc5 100644 --- a/shared-module/keypad/Event.c +++ b/shared-module/keypad/Event.c @@ -26,13 +26,13 @@ #include "shared-module/keypad/Event.h" -void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_num, bool pressed) { - self->key_num = key_num; +void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_int_t key_number, bool pressed) { + self->key_number = key_number; self->pressed = pressed; } -mp_int_t common_hal_keypad_event_get_key_num(keypad_event_obj_t *self) { - return self->key_num; +mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self) { + return self->key_number; } bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self) { diff --git a/shared-module/keypad/Event.h b/shared-module/keypad/Event.h index 4780df0aa2..3c47b0e636 100644 --- a/shared-module/keypad/Event.h +++ b/shared-module/keypad/Event.h @@ -31,7 +31,7 @@ typedef struct { mp_obj_base_t base; - uint16_t key_num; + uint16_t key_number; bool pressed; } keypad_event_obj_t; diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c index 556e425e4b..204c5d21dc 100644 --- a/shared-module/keypad/EventQueue.c +++ b/shared-module/keypad/EventQueue.c @@ -27,17 +27,17 @@ #include "shared-bindings/keypad/Event.h" #include "shared-module/keypad/EventQueue.h" -// Top bit of 16-bit event indicates pressed or released. Rest is key_num. +// Key number is lower 15 bits of a 16-bit value. #define EVENT_PRESSED (1 << 15) -#define EVENT_RELEASED (0) -#define EVENT_KEY_NUM_MASK (~EVENT_PRESSED) +#define EVENT_KEY_NUM_MASK ((1 << 15) - 1) void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events) { // Event queue is 16-bit values. ringbuf_alloc(&self->encoded_events, max_events * 2, false); + self->overflowed = false; } -mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self) { +mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self) { int encoded_event = ringbuf_get16(&self->encoded_events); if (encoded_event == -1) { return MP_ROM_NONE; @@ -49,7 +49,7 @@ mp_obj_t common_hal_keypad_eventqueue_next(keypad_eventqueue_obj_t *self) { return MP_OBJ_FROM_PTR(event); } -bool common_hal_keypad_eventqueue_store_next(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event) { +bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event) { int encoded_event = ringbuf_get16(&self->encoded_events); if (encoded_event == -1) { return false; @@ -60,9 +60,6 @@ bool common_hal_keypad_eventqueue_store_next(keypad_eventqueue_obj_t *self, keyp return true; } - - - void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) { ringbuf_clear(&self->encoded_events); } @@ -71,10 +68,25 @@ size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self) { return ringbuf_num_filled(&self->encoded_events); } -void keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_num, bool pressed) { - if (ringbuf_num_empty(&self->encoded_events) == 0) { - // Discard oldest if full. - ringbuf_get16(&self->encoded_events); - } - ringbuf_put16(&self->encoded_events, key_num | (pressed ? EVENT_PRESSED : EVENT_RELEASED)); +bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self) { + return self->overflowed; +} + +void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed) { + self->overflowed = overflowed; +} + +bool keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_number, bool pressed) { + if (ringbuf_num_empty(&self->encoded_events) == 0) { + // Queue is full. The caller will decide what to do, including whether to set the overflowed flag. + return false; + } + + uint16_t encoded_event = key_number & EVENT_KEY_NUM_MASK; + if (pressed) { + encoded_event |= EVENT_PRESSED; + } + ringbuf_put16(&self->encoded_events, encoded_event); + + return true; } diff --git a/shared-module/keypad/EventQueue.h b/shared-module/keypad/EventQueue.h index 88e585b23b..ce5e55ef3b 100644 --- a/shared-module/keypad/EventQueue.h +++ b/shared-module/keypad/EventQueue.h @@ -33,8 +33,9 @@ typedef struct { mp_obj_base_t base; ringbuf_t encoded_events; + bool overflowed; } keypad_eventqueue_obj_t; -void keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_num, bool pressed); +bool keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_number, bool pressed); #endif // MICROPY_INCLUDED_SHARED_MODULE_KEYPAD_EVENTQUEUE_H diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 8ac3abe837..3cf7c89a91 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -36,11 +36,11 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -static mp_uint_t row_col_to_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { - return row * self->col_digitalinouts->len + col; +static mp_uint_t row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) { + return row * self->column_digitalinouts->len + column; } -void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_col_pins, mcu_pin_obj_t *col_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) { +void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events) { mp_obj_t row_dios[num_row_pins]; for (size_t row = 0; row < num_row_pins; row++) { @@ -52,18 +52,18 @@ void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint } self->row_digitalinouts = mp_obj_new_tuple(num_row_pins, row_dios); - mp_obj_t col_dios[num_col_pins]; - for (size_t col = 0; col < num_col_pins; col++) { + mp_obj_t column_dios[num_column_pins]; + for (size_t column = 0; column < num_column_pins; column++) { digitalio_digitalinout_obj_t *dio = m_new_obj(digitalio_digitalinout_obj_t); dio->base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(dio, col_pins[col]); + common_hal_digitalio_digitalinout_construct(dio, column_pins[column]); common_hal_digitalio_digitalinout_switch_to_input(dio, columns_to_anodes ? PULL_UP : PULL_DOWN); - col_dios[col] = dio; + column_dios[column] = dio; } - self->col_digitalinouts = mp_obj_new_tuple(num_col_pins, col_dios); + self->column_digitalinouts = mp_obj_new_tuple(num_column_pins, column_dios); - self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); - self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_col_pins, false, false); + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_column_pins, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_row_pins * num_column_pins, false, false); self->columns_to_anodes = columns_to_anodes; @@ -89,47 +89,53 @@ void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self) { // Remove self from the list of active keypad scanners first. keypad_deregister_scanner((keypad_scanner_obj_t *)self); - for (size_t row = 0; row < common_hal_keypad_keymatrix_get_num_rows(self); row++) { + for (size_t row = 0; row < common_hal_keypad_keymatrix_get_row_count(self); row++) { common_hal_digitalio_digitalinout_deinit(self->row_digitalinouts->items[row]); } self->row_digitalinouts = MP_ROM_NONE; - for (size_t col = 0; col < common_hal_keypad_keymatrix_get_num_cols(self); col++) { - common_hal_digitalio_digitalinout_deinit(self->col_digitalinouts->items[col]); + for (size_t column = 0; column < common_hal_keypad_keymatrix_get_column_count(self); column++) { + common_hal_digitalio_digitalinout_deinit(self->column_digitalinouts->items[column]); } - self->col_digitalinouts = MP_ROM_NONE; + self->column_digitalinouts = MP_ROM_NONE; } bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self) { return self->row_digitalinouts == MP_ROM_NONE; } -size_t common_hal_keypad_keymatrix_get_num_keys(keypad_keymatrix_obj_t *self) { - return common_hal_keypad_keymatrix_get_num_rows(self) * common_hal_keypad_keymatrix_get_num_cols(self); +size_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self) { + return common_hal_keypad_keymatrix_get_row_count(self) * common_hal_keypad_keymatrix_get_column_count(self); } -size_t common_hal_keypad_keymatrix_get_num_rows(keypad_keymatrix_obj_t *self) { +size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self) { return self->row_digitalinouts->len; } -size_t common_hal_keypad_keymatrix_get_num_cols(keypad_keymatrix_obj_t *self) { - return self->col_digitalinouts->len; +size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self) { + return self->column_digitalinouts->len; } -bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_num) { - return self->currently_pressed[key_num]; +bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_number) { + return self->currently_pressed[key_number]; } // The length of states has already been validated. -void common_hal_keypad_keymatrix_store_states(keypad_keymatrix_obj_t *self, uint8_t *states) { +void common_hal_keypad_keymatrix_get_states_into(keypad_keymatrix_obj_t *self, uint8_t *states) { // Read the state atomically. supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_keymatrix_get_num_keys(self)); + memcpy(states, self->currently_pressed, common_hal_keypad_keymatrix_get_key_count(self)); supervisor_release_lock(&keypad_scanners_linked_list_lock); } -mp_uint_t common_hal_keypad_keymatrix_key_num(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t col) { - return row_col_to_key_num(self, row, col); +mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) { + return row_column_to_key_number(self, row, column); +} + +void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column) { + const size_t num_columns = common_hal_keypad_keymatrix_get_column_count(self); + *row = key_number / num_columns; + *column = key_number % num_columns; } mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self) { @@ -147,28 +153,35 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { // On entry, all pins are set to inputs with a pull-up or pull-down, // depending on the diode orientation. - for (size_t row = 0; row < common_hal_keypad_keymatrix_get_num_rows(self); row++) { + for (size_t row = 0; row < common_hal_keypad_keymatrix_get_row_count(self); row++) { // Switch this row to an output and set level appropriately // Set low if columns_to_anodes is true, else set high. common_hal_digitalio_digitalinout_switch_to_output( self->row_digitalinouts->items[row], !self->columns_to_anodes, DRIVE_MODE_PUSH_PULL); - for (size_t col = 0; col < common_hal_keypad_keymatrix_get_num_cols(self); col++) { - mp_uint_t key_num = row_col_to_key_num(self, row, col); - const bool previous = self->currently_pressed[key_num]; - self->previously_pressed[key_num] = previous; + for (size_t column = 0; column < common_hal_keypad_keymatrix_get_column_count(self); column++) { + mp_uint_t key_number = row_column_to_key_number(self, row, column); + const bool previous = self->currently_pressed[key_number]; + self->previously_pressed[key_number] = previous; - // Get the current state, by reading whether the col got pulled to the row value or not. + // Get the current state, by reading whether the column got pulled to the row value or not. // If low and columns_to_anodes is true, the key is pressed. // If high and columns_to_anodes is false, the key is pressed. const bool current = - common_hal_digitalio_digitalinout_get_value(self->col_digitalinouts->items[col]) != + common_hal_digitalio_digitalinout_get_value(self->column_digitalinouts->items[column]) != self->columns_to_anodes; - self->currently_pressed[key_num] = current; + self->currently_pressed[key_number] = current; // Record any transitions. if (previous != current) { - keypad_eventqueue_record(self->events, key_num, current); + if (!keypad_eventqueue_record(self->events, key_number, current)) { + // The event queue is full. Reset all states to initial values and set the overflowed flag. + const size_t key_count = common_hal_keypad_keymatrix_get_key_count(self); + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + + common_hal_keypad_eventqueue_set_overflowed(self->events, true); + } } } diff --git a/shared-module/keypad/KeyMatrix.h b/shared-module/keypad/KeyMatrix.h index 4f789aa382..bd7e2d23e2 100644 --- a/shared-module/keypad/KeyMatrix.h +++ b/shared-module/keypad/KeyMatrix.h @@ -39,7 +39,7 @@ typedef struct { // All scanners have a next field here, to keep a linked list of active scanners. keypad_scanner_obj_t *next; mp_obj_tuple_t *row_digitalinouts; - mp_obj_tuple_t *col_digitalinouts; + mp_obj_tuple_t *column_digitalinouts; mp_uint_t interval_ticks; uint64_t last_scan_ticks; bool *previously_pressed; diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 5f5d2f3880..9443da85b6 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -75,7 +75,7 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self) { // Remove self from the list of active keypad scanners first. keypad_deregister_scanner((keypad_scanner_obj_t *)self); - for (size_t key = 0; key < common_hal_keypad_keys_get_num_keys(self); key++) { + for (size_t key = 0; key < common_hal_keypad_keys_get_key_count(self); key++) { common_hal_digitalio_digitalinout_deinit(self->digitalinouts->items[key]); } self->digitalinouts = MP_ROM_NONE; @@ -86,18 +86,18 @@ bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) { return self->digitalinouts == MP_ROM_NONE; } -size_t common_hal_keypad_keys_get_num_keys(keypad_keys_obj_t *self) { +size_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self) { return self->digitalinouts->len; } -bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_num) { - return self->currently_pressed[key_num]; +bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_number) { + return self->currently_pressed[key_number]; } // The length of states has already been validated. -void common_hal_keypad_keys_store_states(keypad_keys_obj_t *self, uint8_t *states) { +void common_hal_keypad_keys_get_states_into(keypad_keys_obj_t *self, uint8_t *states) { // Read the state atomically. supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_keys_get_num_keys(self)); + memcpy(states, self->currently_pressed, common_hal_keypad_keys_get_key_count(self)); supervisor_release_lock(&keypad_scanners_linked_list_lock); } @@ -114,20 +114,28 @@ void keypad_keys_scan(keypad_keys_obj_t *self) { self->last_scan_ticks = now; - for (mp_uint_t key_num = 0; key_num < common_hal_keypad_keys_get_num_keys(self); key_num++) { + const size_t key_count = common_hal_keypad_keys_get_key_count(self); + + for (mp_uint_t key_number = 0; key_number < key_count; key_number++) { // Remember the previous up/down state. - const bool previous = self->currently_pressed[key_num]; - self->previously_pressed[key_num] = previous; + const bool previous = self->currently_pressed[key_number]; + self->previously_pressed[key_number] = previous; // Get the current state. const bool current = - common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_num]) == + common_hal_digitalio_digitalinout_get_value(self->digitalinouts->items[key_number]) == self->value_when_pressed; - self->currently_pressed[key_num] = current; + self->currently_pressed[key_number] = current; // Record any transitions. if (previous != current) { - keypad_eventqueue_record(self->events, key_num, current); + if (!keypad_eventqueue_record(self->events, key_number, current)) { + // The event queue is full. Reset all states to initial values and set the overflowed flag. + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + + common_hal_keypad_eventqueue_set_overflowed(self->events, true); + } } } } diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 5d7d956632..21bf103642 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -35,7 +35,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" -void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t num_keys, bool value_when_pressed, mp_float_t interval, size_t max_events) { +void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, mcu_pin_obj_t *clock_pin, mcu_pin_obj_t *data_pin, mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events) { digitalio_digitalinout_obj_t *clock = m_new_obj(digitalio_digitalinout_obj_t); clock->base.type = &digitalio_digitalinout_type; @@ -56,10 +56,10 @@ void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_ self->latch = latch; self->value_to_latch = value_to_latch; - self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); - self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * num_keys, false, false); + self->currently_pressed = (bool *)gc_alloc(sizeof(bool) * key_count, false, false); + self->previously_pressed = (bool *)gc_alloc(sizeof(bool) * key_count, false, false); self->value_when_pressed = value_when_pressed; - self->num_keys = num_keys; + self->key_count = key_count; self->interval_ticks = (mp_uint_t)(interval * 1024); // interval * 1000 * (1024/1000) self->last_scan_ticks = port_get_raw_ticks(NULL); @@ -98,18 +98,18 @@ bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t return self->clock == MP_ROM_NONE; } -size_t common_hal_keypad_shiftregisterkeys_get_num_keys(keypad_shiftregisterkeys_obj_t *self) { - return self->num_keys; +size_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self) { + return self->key_count; } -bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_num) { - return self->currently_pressed[key_num]; +bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_number) { + return self->currently_pressed[key_number]; } // The length of states has already been validated. -void common_hal_keypad_shiftregisterkeys_store_states(keypad_shiftregisterkeys_obj_t *self, uint8_t *states) { +void common_hal_keypad_shiftregisterkeys_get_states_into(keypad_shiftregisterkeys_obj_t *self, uint8_t *states) { // Read the state atomically. supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_shiftregisterkeys_get_num_keys(self)); + memcpy(states, self->currently_pressed, common_hal_keypad_shiftregisterkeys_get_key_count(self)); supervisor_release_lock(&keypad_scanners_linked_list_lock); } @@ -129,25 +129,33 @@ void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { // Latch (freeze) the current state of the input pins. common_hal_digitalio_digitalinout_set_value(self->latch, self->value_to_latch); - for (mp_uint_t key_num = 0; key_num < common_hal_keypad_shiftregisterkeys_get_num_keys(self); key_num++) { + const size_t key_count = common_hal_keypad_shiftregisterkeys_get_key_count(self); + + for (mp_uint_t key_number = 0; key_number < key_count; key_number++) { // Zero-th data appears on on the data pin immediately, without shifting. common_hal_digitalio_digitalinout_set_value(self->clock, false); // Remember the previous up/down state. - const bool previous = self->currently_pressed[key_num]; - self->previously_pressed[key_num] = previous; + const bool previous = self->currently_pressed[key_number]; + self->previously_pressed[key_number] = previous; // Get the current state. const bool current = common_hal_digitalio_digitalinout_get_value(self->data) == self->value_when_pressed; - self->currently_pressed[key_num] = current; + self->currently_pressed[key_number] = current; // Trigger a shift to get the next bit. common_hal_digitalio_digitalinout_set_value(self->clock, true); // Record any transitions. if (previous != current) { - keypad_eventqueue_record(self->events, key_num, current); + if (!keypad_eventqueue_record(self->events, key_number, current)) { + // The event queue is full. Reset all states to initial values and set the overflowed flag. + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + + common_hal_keypad_eventqueue_set_overflowed(self->events, true); + } } } diff --git a/shared-module/keypad/ShiftRegisterKeys.h b/shared-module/keypad/ShiftRegisterKeys.h index c685a7141c..b04c622679 100644 --- a/shared-module/keypad/ShiftRegisterKeys.h +++ b/shared-module/keypad/ShiftRegisterKeys.h @@ -41,7 +41,7 @@ typedef struct { digitalio_digitalinout_obj_t *clock; digitalio_digitalinout_obj_t *data; digitalio_digitalinout_obj_t *latch; - size_t num_keys; + size_t key_count; mp_uint_t interval_ticks; uint64_t last_scan_ticks; bool *previously_pressed; From 7774b18895d4f2bad8d4d4a72acbb33619490daa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 23 Jun 2021 14:54:52 -0400 Subject: [PATCH 35/38] Add reset() to scanners. Clear .overflow on EventQueue.clear(). --- shared-bindings/keypad/EventQueue.c | 16 ++++------------ shared-bindings/keypad/KeyMatrix.c | 16 ++++++++++++++++ shared-bindings/keypad/KeyMatrix.h | 1 + shared-bindings/keypad/Keys.c | 18 +++++++++++++++++- shared-bindings/keypad/Keys.h | 1 + shared-bindings/keypad/ShiftRegisterKeys.c | 20 ++++++++++++++++++-- shared-bindings/keypad/ShiftRegisterKeys.h | 1 + shared-module/keypad/EventQueue.c | 20 +++++++++++--------- shared-module/keypad/KeyMatrix.c | 18 ++++++++++-------- shared-module/keypad/Keys.c | 17 ++++++++++------- shared-module/keypad/ShiftRegisterKeys.c | 17 ++++++++++------- 11 files changed, 99 insertions(+), 46 deletions(-) diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index 72bbd06452..6a0e904ed1 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -83,7 +83,7 @@ STATIC mp_obj_t keypad_eventqueue_get_into(mp_obj_t self_in, mp_obj_t event_in) MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_get_into_obj, keypad_eventqueue_get_into); //| def clear(self) -> None: -//| """Clear any queued key transition events. +//| """Clear any queued key transition events. Also sets `overflowed` to ``False``. //| """ //| ... //| @@ -119,9 +119,8 @@ STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } //| overflowed: bool -//| """``True`` if an event could not be added to the event queue because it was full. -//| When this happens, the event queue is cleared. -//| The `overflowed` flag is persistent. Reset it by setting it to ``False``. +//| """``True`` if an event could not be added to the event queue because it was full. (read-only) +//| Set to ``False`` by `clear()`. //| """ //| STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) { @@ -130,17 +129,10 @@ STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_overflowed_obj, keypad_eventqueue_get_overflowed); -STATIC mp_obj_t keypad_eventqueue_set_overflowed(mp_obj_t self_in, mp_obj_t overflowed_in) { - keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_keypad_eventqueue_set_overflowed(self, mp_obj_is_true(overflowed_in)); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_set_overflowed_obj, keypad_eventqueue_set_overflowed); - const mp_obj_property_t keypad_eventqueue_overflowed_obj = { .base.type = &mp_type_property, .proxy = {(mp_obj_t)&keypad_eventqueue_get_overflowed_obj, - (mp_obj_t)&keypad_eventqueue_set_overflowed_obj, + MP_ROM_NONE, MP_ROM_NONE}, }; diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index fc29f67e33..506add0713 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -141,6 +141,21 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { } } +//| def reset(self) -> None: +//| """Reset the internal state of the scanner to assume that all keys are now released. +//| Any key that is already pressed at the time of this call will therefore immediately cause +//| a new key-pressed event to occur. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keymatrix_reset(mp_obj_t self_in) { + keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keymatrix_reset(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_reset_obj, keypad_keymatrix_reset); + //| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ @@ -282,6 +297,7 @@ STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) }, { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keymatrix_key_count_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keymatrix_reset_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table); diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 98152f759a..6643d2f9fd 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -46,6 +46,7 @@ mp_uint_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self); bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_keymatrix_reset(keypad_keymatrix_obj_t *self); void common_hal_keypad_keymatrix_get_states_into(keypad_keymatrix_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 95e68e9bd1..9c5ca08bf3 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -135,6 +135,21 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { } } +//| def reset(self) -> None: +//| """Reset the internal state of the scanner to assume that all keys are now released. +//| Any key that is already pressed at the time of this call will therefore immediately cause +//| a new key-pressed event to occur. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_keys_reset(mp_obj_t self_in) { + keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_keys_reset(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_reset_obj, keypad_keys_reset); + //| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ @@ -218,9 +233,10 @@ STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keys_get_states_into_obj) }, { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keys_key_count_obj) }, { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keys_get_states_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keys_reset_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table); diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 3ac3dd43b2..4d45d9e06a 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -40,6 +40,7 @@ bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self); mp_uint_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self); bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_keys_reset(keypad_keys_obj_t *self); void common_hal_keypad_keys_get_states_into(keypad_keys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index e5d959348c..c76910726f 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -139,6 +139,21 @@ STATIC void check_for_deinit(keypad_shiftregisterkeys_obj_t *self) { } } +//| def reset(self) -> None: +//| """Reset the internal state of the scanner to assume that all keys are now released. +//| Any key that is already pressed at the time of this call will therefore immediately cause +//| a new key-pressed event to occur. +//| """ +//| ... +//| +STATIC mp_obj_t keypad_shiftregisterkeys_reset(mp_obj_t self_in) { + keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_keypad_shiftregisterkeys_reset(self); + return MP_ROM_NONE; +} +MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_reset_obj, keypad_shiftregisterkeys_reset); + //| key_count: int //| """The number of keys that are being scanned. (read-only) //| """ @@ -223,9 +238,10 @@ STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_shiftregisterkeys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_shiftregisterkeys_key_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_shiftregisterkeys_pressed_obj) }, { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_shiftregisterkeys_get_states_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_shiftregisterkeys_key_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_shiftregisterkeys_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_shiftregisterkeys_reset_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index 9aced14466..b81b3b45e6 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -40,6 +40,7 @@ bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self); mp_uint_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self); bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_number); +void common_hal_keypad_shiftregisterkeys_reset(keypad_shiftregisterkeys_obj_t *self); void common_hal_keypad_shiftregisterkeys_get_states_into(keypad_shiftregisterkeys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H diff --git a/shared-module/keypad/EventQueue.c b/shared-module/keypad/EventQueue.c index 204c5d21dc..5986a29ce8 100644 --- a/shared-module/keypad/EventQueue.c +++ b/shared-module/keypad/EventQueue.c @@ -60,14 +60,6 @@ bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad return true; } -void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) { - ringbuf_clear(&self->encoded_events); -} - -size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self) { - return ringbuf_num_filled(&self->encoded_events); -} - bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self) { return self->overflowed; } @@ -76,9 +68,19 @@ void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, self->overflowed = overflowed; } +void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self) { + ringbuf_clear(&self->encoded_events); + common_hal_keypad_eventqueue_set_overflowed(self, false); +} + +size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self) { + return ringbuf_num_filled(&self->encoded_events); +} + bool keypad_eventqueue_record(keypad_eventqueue_obj_t *self, mp_uint_t key_number, bool pressed) { if (ringbuf_num_empty(&self->encoded_events) == 0) { - // Queue is full. The caller will decide what to do, including whether to set the overflowed flag. + // Queue is full. Set the overflow flag. The caller will decide what else to do. + common_hal_keypad_eventqueue_set_overflowed(self, true); return false; } diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index 3cf7c89a91..ac2e715dbd 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -142,6 +142,15 @@ mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self) { return MP_OBJ_FROM_PTR(self->events); } +void common_hal_keypad_keymatrix_reset(keypad_keymatrix_obj_t *self) { + const size_t key_count = common_hal_keypad_keymatrix_get_key_count(self); + + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < self->interval_ticks) { @@ -174,14 +183,7 @@ void keypad_keymatrix_scan(keypad_keymatrix_obj_t *self) { // Record any transitions. if (previous != current) { - if (!keypad_eventqueue_record(self->events, key_number, current)) { - // The event queue is full. Reset all states to initial values and set the overflowed flag. - const size_t key_count = common_hal_keypad_keymatrix_get_key_count(self); - memset(self->previously_pressed, false, key_count); - memset(self->currently_pressed, false, key_count); - - common_hal_keypad_eventqueue_set_overflowed(self->events, true); - } + keypad_eventqueue_record(self->events, key_number, current); } } diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index 9443da85b6..c621a757d2 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -105,6 +105,15 @@ mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) { return MP_OBJ_FROM_PTR(self->events); } +void common_hal_keypad_keys_reset(keypad_keys_obj_t *self) { + const size_t key_count = common_hal_keypad_keys_get_key_count(self); + + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + void keypad_keys_scan(keypad_keys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < self->interval_ticks) { @@ -129,13 +138,7 @@ void keypad_keys_scan(keypad_keys_obj_t *self) { // Record any transitions. if (previous != current) { - if (!keypad_eventqueue_record(self->events, key_number, current)) { - // The event queue is full. Reset all states to initial values and set the overflowed flag. - memset(self->previously_pressed, false, key_count); - memset(self->currently_pressed, false, key_count); - - common_hal_keypad_eventqueue_set_overflowed(self->events, true); - } + keypad_eventqueue_record(self->events, key_number, current); } } } diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index 21bf103642..fd5d8bbdb1 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -117,6 +117,15 @@ mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys return MP_OBJ_FROM_PTR(self->events); } +void common_hal_keypad_shiftregisterkeys_reset(keypad_shiftregisterkeys_obj_t *self) { + const size_t key_count = common_hal_keypad_shiftregisterkeys_get_key_count(self); + + supervisor_acquire_lock(&keypad_scanners_linked_list_lock); + memset(self->previously_pressed, false, key_count); + memset(self->currently_pressed, false, key_count); + supervisor_release_lock(&keypad_scanners_linked_list_lock); +} + void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { uint64_t now = port_get_raw_ticks(NULL); if (now - self->last_scan_ticks < self->interval_ticks) { @@ -149,13 +158,7 @@ void keypad_shiftregisterkeys_scan(keypad_shiftregisterkeys_obj_t *self) { // Record any transitions. if (previous != current) { - if (!keypad_eventqueue_record(self->events, key_number, current)) { - // The event queue is full. Reset all states to initial values and set the overflowed flag. - memset(self->previously_pressed, false, key_count); - memset(self->currently_pressed, false, key_count); - - common_hal_keypad_eventqueue_set_overflowed(self->events, true); - } + keypad_eventqueue_record(self->events, key_number, current); } } From 4f538b6c09b4956f2ff18dfb757773dddd61e806 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 23 Jun 2021 15:10:38 -0400 Subject: [PATCH 36/38] remove pressed() and get_states_into() --- shared-bindings/keypad/KeyMatrix.c | 50 +--------------------- shared-bindings/keypad/KeyMatrix.h | 8 ++-- shared-bindings/keypad/Keys.c | 47 +------------------- shared-bindings/keypad/Keys.h | 4 +- shared-bindings/keypad/ShiftRegisterKeys.c | 46 -------------------- shared-bindings/keypad/ShiftRegisterKeys.h | 4 +- shared-module/keypad/KeyMatrix.c | 12 ------ shared-module/keypad/Keys.c | 11 ----- shared-module/keypad/ShiftRegisterKeys.c | 11 ----- 9 files changed, 8 insertions(+), 185 deletions(-) diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 506add0713..83efdd5f16 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -225,50 +225,6 @@ STATIC mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_o } MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_keymatrix_row_column_to_key_number); -//| def pressed(self, key_number: int) -> None: -//| """Return ``True`` if the given key is pressed. This is a debounced read -//| of the key state which bypasses the `events` `EventQueue`. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keymatrix_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { - keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_uint_t key_number = mp_arg_validate_int_range( - mp_obj_get_int(key_number_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_key_count(self), MP_QSTR_key_number); - - return mp_obj_new_bool(common_hal_keypad_keymatrix_pressed(self, (mp_uint_t)key_number)); -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_pressed_obj, keypad_keymatrix_pressed); - -//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: -//| """Write the state of all the keys into ``states``. -//| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `key_count`. -//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. -//| The read is done atomically. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keymatrix_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { - keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); - if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { - mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_states); - } - - (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_keymatrix_get_key_count(self), - MP_QSTR_states, MP_QSTR_key_count); - - common_hal_keypad_keymatrix_get_states_into(self, (uint8_t *)bufinfo.buf); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_get_states_into_obj, keypad_keymatrix_get_states_into); - //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) //| """ @@ -292,12 +248,10 @@ STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keymatrix_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keymatrix_get_states_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keymatrix_key_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keymatrix_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_keymatrix_key_number_to_row_column_obj) }, { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) }, - { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keymatrix_key_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keymatrix_pressed_obj) }, - { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keymatrix_reset_obj) }, }; STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table); diff --git a/shared-bindings/keypad/KeyMatrix.h b/shared-bindings/keypad/KeyMatrix.h index 6643d2f9fd..7ebe1af5b7 100644 --- a/shared-bindings/keypad/KeyMatrix.h +++ b/shared-bindings/keypad/KeyMatrix.h @@ -40,13 +40,11 @@ bool common_hal_keypad_keymatrix_deinited(keypad_keymatrix_obj_t *self); void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column); mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column); -mp_uint_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self); -mp_uint_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self); +size_t common_hal_keypad_keymatrix_get_key_count(keypad_keymatrix_obj_t *self); +size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self); +size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self); mp_obj_t common_hal_keypad_keymatrix_get_events(keypad_keymatrix_obj_t *self); -bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_number); void common_hal_keypad_keymatrix_reset(keypad_keymatrix_obj_t *self); -void common_hal_keypad_keymatrix_get_states_into(keypad_keymatrix_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 9c5ca08bf3..e9ed1346e8 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -167,49 +167,6 @@ const mp_obj_property_t keypad_keys_key_count_obj = { MP_ROM_NONE}, }; -//| def pressed(self, key_number: int) -> None: -//| """Return ``True`` if the given key is pressed. -// This is a debounced read of the key state which bypasses the `events` `EventQueue`. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keys_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { - keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - const mp_int_t key_number = mp_obj_get_int(key_number_in); - (void)mp_arg_validate_int_range(key_number, 0, common_hal_keypad_keys_get_key_count(self), MP_QSTR_key_number); - - return mp_obj_new_bool(common_hal_keypad_keys_pressed(self, (mp_uint_t)key_number)); -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_pressed_obj, keypad_keys_pressed); - -//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: -//| """Write the states of all the keys into ``states``. -//| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `key_count`. -//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. -//| The read is done atomically. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_keys_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { - keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); - if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { - mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); - } - (void)mp_arg_validate_length_with_name(bufinfo.len,common_hal_keypad_keys_get_key_count(self), - MP_QSTR_pressed, MP_QSTR_key_count); - - common_hal_keypad_keys_get_states_into(self, (uint8_t *)bufinfo.buf); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_keys_get_states_into_obj, keypad_keys_get_states_into); - //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) //| """ @@ -233,9 +190,7 @@ STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_keys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_keys_get_states_into_obj) }, - { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keys_key_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_keys_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_keys_key_count_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_keys_reset_obj) }, }; diff --git a/shared-bindings/keypad/Keys.h b/shared-bindings/keypad/Keys.h index 4d45d9e06a..094220e588 100644 --- a/shared-bindings/keypad/Keys.h +++ b/shared-bindings/keypad/Keys.h @@ -38,9 +38,7 @@ void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self); bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self); mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self); -mp_uint_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self); -bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_number); +size_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self); void common_hal_keypad_keys_reset(keypad_keys_obj_t *self); -void common_hal_keypad_keys_get_states_into(keypad_keys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index c76910726f..340960c718 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -171,50 +171,6 @@ const mp_obj_property_t keypad_shiftregisterkeys_key_count_obj = { MP_ROM_NONE}, }; -//| def pressed(self, key_number: int) -> None: -//| """Return ``True`` if the given key is pressed. -// This is a debounced read of the key state which bypasses the `events` `EventQueue`. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_shiftregisterkeys_pressed(mp_obj_t self_in, mp_obj_t key_number_in) { - keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_uint_t key_number = mp_arg_validate_int_range( - mp_obj_get_int(key_number_in), 0, (mp_int_t)common_hal_keypad_shiftregisterkeys_get_key_count(self), - MP_QSTR_key_number); - - return mp_obj_new_bool(common_hal_keypad_shiftregisterkeys_pressed(self, key_number)); -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_pressed_obj, keypad_shiftregisterkeys_pressed); - -//| def get_states_into(self, states: _typing.WriteableBuffer) -> None: -//| """Write the states of all the keys into ``states``. -//| Write a ``1`` if pressed, and ``0`` if released. -//| The ``length`` of ``states`` must be `key_count`. -//| This is a debounced read of the state of all the keys, and bypasses the `events` `EventQueue`. -//| The read is done atomically. -//| """ -//| ... -//| -STATIC mp_obj_t keypad_shiftregisterkeys_get_states_into(mp_obj_t self_in, mp_obj_t pressed) { - keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(pressed, &bufinfo, MP_BUFFER_WRITE); - if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { - mp_raise_ValueError_varg(translate("%q must store bytes"), MP_QSTR_pressed); - } - (void)mp_arg_validate_length_with_name(bufinfo.len, common_hal_keypad_shiftregisterkeys_get_key_count(self), - MP_QSTR_states, MP_QSTR_key_count); - - common_hal_keypad_shiftregisterkeys_get_states_into(self, (uint8_t *)bufinfo.buf); - return MP_ROM_NONE; -} -MP_DEFINE_CONST_FUN_OBJ_2(keypad_shiftregisterkeys_get_states_into_obj, keypad_shiftregisterkeys_get_states_into); - //| events: EventQueue //| """The `EventQueue` associated with this `Keys` object. (read-only) //| """ @@ -238,9 +194,7 @@ STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_shiftregisterkeys_events_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_states_into), MP_ROM_PTR(&keypad_shiftregisterkeys_get_states_into_obj) }, { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_shiftregisterkeys_key_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_shiftregisterkeys_pressed_obj) }, { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_shiftregisterkeys_reset_obj) }, }; diff --git a/shared-bindings/keypad/ShiftRegisterKeys.h b/shared-bindings/keypad/ShiftRegisterKeys.h index b81b3b45e6..f1432f1069 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.h +++ b/shared-bindings/keypad/ShiftRegisterKeys.h @@ -38,9 +38,7 @@ void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t * bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t *self); mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self); -mp_uint_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self); -bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_number); +size_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self); void common_hal_keypad_shiftregisterkeys_reset(keypad_shiftregisterkeys_obj_t *self); -void common_hal_keypad_shiftregisterkeys_get_states_into(keypad_shiftregisterkeys_obj_t *self, uint8_t *states); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H diff --git a/shared-module/keypad/KeyMatrix.c b/shared-module/keypad/KeyMatrix.c index ac2e715dbd..677a0b7142 100644 --- a/shared-module/keypad/KeyMatrix.c +++ b/shared-module/keypad/KeyMatrix.c @@ -116,18 +116,6 @@ size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self return self->column_digitalinouts->len; } -bool common_hal_keypad_keymatrix_pressed(keypad_keymatrix_obj_t *self, mp_uint_t key_number) { - return self->currently_pressed[key_number]; -} - -// The length of states has already been validated. -void common_hal_keypad_keymatrix_get_states_into(keypad_keymatrix_obj_t *self, uint8_t *states) { - // Read the state atomically. - supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_keymatrix_get_key_count(self)); - supervisor_release_lock(&keypad_scanners_linked_list_lock); -} - mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column) { return row_column_to_key_number(self, row, column); } diff --git a/shared-module/keypad/Keys.c b/shared-module/keypad/Keys.c index c621a757d2..1f232a03ed 100644 --- a/shared-module/keypad/Keys.c +++ b/shared-module/keypad/Keys.c @@ -89,17 +89,6 @@ bool common_hal_keypad_keys_deinited(keypad_keys_obj_t *self) { size_t common_hal_keypad_keys_get_key_count(keypad_keys_obj_t *self) { return self->digitalinouts->len; } -bool common_hal_keypad_keys_pressed(keypad_keys_obj_t *self, mp_uint_t key_number) { - return self->currently_pressed[key_number]; -} - -// The length of states has already been validated. -void common_hal_keypad_keys_get_states_into(keypad_keys_obj_t *self, uint8_t *states) { - // Read the state atomically. - supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_keys_get_key_count(self)); - supervisor_release_lock(&keypad_scanners_linked_list_lock); -} mp_obj_t common_hal_keypad_keys_get_events(keypad_keys_obj_t *self) { return MP_OBJ_FROM_PTR(self->events); diff --git a/shared-module/keypad/ShiftRegisterKeys.c b/shared-module/keypad/ShiftRegisterKeys.c index fd5d8bbdb1..074f226998 100644 --- a/shared-module/keypad/ShiftRegisterKeys.c +++ b/shared-module/keypad/ShiftRegisterKeys.c @@ -101,17 +101,6 @@ bool common_hal_keypad_shiftregisterkeys_deinited(keypad_shiftregisterkeys_obj_t size_t common_hal_keypad_shiftregisterkeys_get_key_count(keypad_shiftregisterkeys_obj_t *self) { return self->key_count; } -bool common_hal_keypad_shiftregisterkeys_pressed(keypad_shiftregisterkeys_obj_t *self, mp_uint_t key_number) { - return self->currently_pressed[key_number]; -} - -// The length of states has already been validated. -void common_hal_keypad_shiftregisterkeys_get_states_into(keypad_shiftregisterkeys_obj_t *self, uint8_t *states) { - // Read the state atomically. - supervisor_acquire_lock(&keypad_scanners_linked_list_lock); - memcpy(states, self->currently_pressed, common_hal_keypad_shiftregisterkeys_get_key_count(self)); - supervisor_release_lock(&keypad_scanners_linked_list_lock); -} mp_obj_t common_hal_keypad_shiftregisterkeys_get_events(keypad_shiftregisterkeys_obj_t *self) { return MP_OBJ_FROM_PTR(self->events); From 2e67d6708dcd50d54bb0757b8745fb61262e1a9c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 23 Jun 2021 15:42:31 -0400 Subject: [PATCH 37/38] check_for_deinit() more places in scanners --- shared-bindings/keypad/KeyMatrix.c | 5 +++++ shared-bindings/keypad/Keys.c | 5 +++++ shared-bindings/keypad/ShiftRegisterKeys.c | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 83efdd5f16..0b854ef475 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -150,6 +150,7 @@ STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) { //| STATIC mp_obj_t keypad_keymatrix_reset(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); common_hal_keypad_keymatrix_reset(self); return MP_ROM_NONE; @@ -162,6 +163,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_reset_obj, keypad_keymatrix_reset); //| STATIC mp_obj_t keypad_keymatrix_get_key_count(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keymatrix_get_key_count(self)); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_key_count_obj, keypad_keymatrix_get_key_count); @@ -231,6 +234,8 @@ MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_ //| STATIC mp_obj_t keypad_keymatrix_get_events(mp_obj_t self_in) { keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_keypad_keymatrix_get_events(self); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_get_events_obj, keypad_keymatrix_get_events); diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index e9ed1346e8..d616bcff84 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -144,6 +144,7 @@ STATIC void check_for_deinit(keypad_keys_obj_t *self) { //| STATIC mp_obj_t keypad_keys_reset(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); common_hal_keypad_keys_reset(self); return MP_ROM_NONE; @@ -156,6 +157,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_reset_obj, keypad_keys_reset); //| STATIC mp_obj_t keypad_keys_get_key_count(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_keys_get_key_count(self)); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_key_count_obj, keypad_keys_get_key_count); @@ -173,6 +176,8 @@ const mp_obj_property_t keypad_keys_key_count_obj = { //| STATIC mp_obj_t keypad_keys_get_events(mp_obj_t self_in) { keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_keypad_keys_get_events(self); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_get_events_obj, keypad_keys_get_events); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 340960c718..c81e127601 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -148,6 +148,7 @@ STATIC void check_for_deinit(keypad_shiftregisterkeys_obj_t *self) { //| STATIC mp_obj_t keypad_shiftregisterkeys_reset(mp_obj_t self_in) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); common_hal_keypad_shiftregisterkeys_reset(self); return MP_ROM_NONE; @@ -160,6 +161,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_reset_obj, keypad_shiftregist //| STATIC mp_obj_t keypad_shiftregisterkeys_get_key_count(mp_obj_t self_in) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_shiftregisterkeys_get_key_count(self)); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_key_count_obj, keypad_shiftregisterkeys_get_key_count); @@ -177,6 +180,8 @@ const mp_obj_property_t keypad_shiftregisterkeys_key_count_obj = { //| STATIC mp_obj_t keypad_shiftregisterkeys_get_events(mp_obj_t self_in) { keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_keypad_shiftregisterkeys_get_events(self); } MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_get_events_obj, keypad_shiftregisterkeys_get_events); From 36472a0a8b66b328b98f53fcbbe566fcb9518166 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 23 Jun 2021 19:23:56 -0400 Subject: [PATCH 38/38] Correct doc in EventQueue.c Co-authored-by: Scott Shawcroft --- shared-bindings/keypad/EventQueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/keypad/EventQueue.c b/shared-bindings/keypad/EventQueue.c index 6a0e904ed1..e47ee0772c 100644 --- a/shared-bindings/keypad/EventQueue.c +++ b/shared-bindings/keypad/EventQueue.c @@ -42,7 +42,7 @@ //| //| Note that the queue size is limited; see ``max_events`` in the constructor of //| a scanner such as `Keys` or `KeyMatrix`. -//| If a new event arrives when the queue is full, the queue is cleared, and +//| If a new event arrives when the queue is full, the event is discarded, and //| `overflowed` is set to ``True``. //| //| :return: the next queued key transition `Event`