Compare commits
460 Commits
v1.22.0-pr
...
main
Author | SHA1 | Date |
---|---|---|
Lephenixnoir | 8c5f68f16e | |
Lephenixnoir | fc9026798d | |
Lephenixnoir | 3775f28536 | |
Lephenixnoir | 5d51f205b9 | |
Lephenixnoir | 3e2f7f0aa0 | |
Lephenixnoir | 71ddfff567 | |
Lephenixnoir | 4bec7be97f | |
Lephenixnoir | fff06099a1 | |
Lephenixnoir | e7349aa227 | |
Lephenixnoir | dfb73611f9 | |
Lephenixnoir | b804cb7583 | |
Lephenixnoir | 38c0ec1d15 | |
Lephenixnoir | eaf5f43da4 | |
Lephenixnoir | c14f770483 | |
Lephenixnoir | 430fe06adc | |
Sylvain PILLOT | d298d0538d | |
Lephenixnoir | 3523a83bda | |
Lephenixnoir | ae3a135a81 | |
Lephenixnoir | 30fcf592d1 | |
Lephenixnoir | f9f94c999a | |
Lephenixnoir | 7abbcc1dfc | |
Lephenixnoir | a1848c0920 | |
Lephenixnoir | 3f02fd86ea | |
Lephenixnoir | 95eb40e25d | |
Lephenixnoir | 93e021f144 | |
Lephenixnoir | c84caa533d | |
Lephenixnoir | bcdb3b74ca | |
Sylvain PILLOT | 35b73ba954 | |
Sylvain PILLOT | 5f385d8bcc | |
Sylvain PILLOT | 05bfce99d6 | |
Sylvain PILLOT | 3e302b1b34 | |
Sylvain PILLOT | 26afb31ff2 | |
Lephenixnoir | a2b9c32cea | |
Sylvain PILLOT | 6225b1d667 | |
Sylvain PILLOT | 0f386bd779 | |
Sylvain PILLOT | 7fdf3aeb2e | |
Sylvain PILLOT | 263b9e83c8 | |
Sylvain PILLOT | 2cb2bc6e67 | |
Lephenixnoir | 0f867e9f72 | |
Sylvain PILLOT | d4dcc59d71 | |
Sylvain PILLOT | 9bc05bbf03 | |
Lephenixnoir | b1e39d3ab6 | |
Lephenixnoir | af8bacd271 | |
Lephenixnoir | d4501baadb | |
Lephenixnoir | 627c81c1b6 | |
Lephenixnoir | 262a90f15c | |
Sylvain PILLOT | 9156a21afa | |
Sylvain PILLOT | 226f82ec8c | |
Sylvain PILLOT | ba515dc168 | |
Lephenixnoir | 6ab101e1bd | |
Sylvain PILLOT | 6ae6d06387 | |
Sylvain PILLOT | e7ad1e267d | |
Lephenixnoir | 6969309cd7 | |
Lephenixnoir | eeb392a833 | |
Lephenixnoir | 00f009e0c2 | |
Sylvain PILLOT | 0fb961768a | |
Sylvain PILLOT | 8072e5b1a9 | |
Lephenixnoir | 7f647b57d7 | |
Lephenixnoir | b1ec8bcde4 | |
Sylvain PILLOT | e3fd785200 | |
Sylvain PILLOT | 12565ba8d2 | |
Sylvain PILLOT | 96077c1653 | |
Lephenixnoir | b9a457680b | |
Sylvain PILLOT | 226d94494f | |
Sylvain PILLOT | bca7048525 | |
Sylvain PILLOT | 0868d96d2b | |
Sylvain PILLOT | 2ac213cae0 | |
Sylvain PILLOT | c207c7b6f7 | |
Sylvain PILLOT | 774c8d0f44 | |
Lephenixnoir | 3a3ad0e155 | |
Lephenixnoir | 6af6f97df4 | |
Lephenixnoir | f3424c60a5 | |
Lephenixnoir | 9f860bd58a | |
Lephenixnoir | b6efd9ed31 | |
Lephenixnoir | e1bda048d0 | |
Lephenixnoir | 727b7fb032 | |
Lephenixnoir | 6547cf5fbc | |
Lephenixnoir | 2dddd209a0 | |
Lephenixnoir | f71cad03cf | |
Lephenixnoir | 5e2b33b148 | |
Lephenixnoir | c3dc438b82 | |
Damien George | dc2a4e3cbd | |
Damien George | 8438c8790c | |
Damien George | c3989e398f | |
robert-hh | 3d0b6276f3 | |
robert-hh | aea93a88f8 | |
robert-hh | 36d9e98fc6 | |
robert-hh | 8498b0b13e | |
iabdalkader | f34e27f178 | |
iabdalkader | 87d3f8b367 | |
Damien George | 2037edb5a2 | |
Lephenixnoir | 8823d1f473 | |
Lephenixnoir | cccc2787b5 | |
Damien George | 9feb0689ee | |
Lephenixnoir | 347e463e17 | |
Lephenixnoir | 61b2360b16 | |
Daniël van de Giessen | d014c82826 | |
Damien George | 0b2676db5c | |
Nicko van Someren | cfc212b108 | |
Sebastian Romero | e4d3ab3304 | |
Peter Züger | d69e69adb6 | |
Peter Züger | ce42c9ee16 | |
Maarten van der Schrieck | 3bca93b2d0 | |
Maarten van der Schrieck | 91ee8ac894 | |
Jim Mussared | 5d28bb4adb | |
IhorNehrutsa | 5552896ca8 | |
IhorNehrutsa | b31eef6094 | |
Jim Mussared | 74fd7b3d32 | |
Jim Mussared | 8b24aa36ba | |
Damien George | e9bcd49b3e | |
Damien George | 49d0c22b11 | |
Damien George | 859f219690 | |
Damien George | 7cf1118831 | |
Damien George | f46269a1d1 | |
Lephenixnoir | 5b52671c50 | |
Damien George | f6d630877c | |
Damien George | 97b13132b1 | |
Patrick Van Oosterwijck | 3270d856fd | |
Paul Grayson | c51081c604 | |
Paul Grayson | fbf079d773 | |
Damien George | a78ec4ef7b | |
Damien George | 1f2ec4583d | |
Damien George | 395886caa3 | |
Trent Piepho | 0e706a62b1 | |
Elias Wimmer | 2e101a8e44 | |
Patrick Van Oosterwijck | 06df3b2925 | |
dependabot[bot] | de3e83aa4d | |
dependabot[bot] | be64641210 | |
dependabot[bot] | d506b53377 | |
Trent Piepho | f22e88611d | |
Trent Piepho | 0d93392f10 | |
stijn | 85c02166ca | |
Carlosgg | 05d3b22301 | |
Carlosgg | bfd6ad94ff | |
Damien George | f33dfb966a | |
Damien George | bba8a673d5 | |
Damien George | ef996d15b9 | |
Damien George | c9eb6bc601 | |
Damien George | 58e75264c1 | |
Carlosgg | f3f215e9bd | |
IhorNehrutsa | 4365edb810 | |
Damien George | d0758d8a33 | |
Damien George | b4b77c17b5 | |
Ihor Nehrutsa | 3069fee386 | |
Ihor Nehrutsa | a427117d03 | |
Ihor Nehrutsa | e423b3c0ba | |
IhorNehrutsa | 495be71d56 | |
IhorNehrutsa | 3106ee4885 | |
IhorNehrutsa | 88778be73a | |
Carlosgg | c393cd7e48 | |
Damien George | e1a7aa23fd | |
Damien George | 241dbac928 | |
Angus Gratton | 2c828a8815 | |
Angus Gratton | 73879734d9 | |
Angus Gratton | c393f5c123 | |
Angus Gratton | 393938b3e6 | |
Angus Gratton | 28529351ae | |
Angus Gratton | df3948d3c2 | |
Angus Gratton | f5be0128e4 | |
Angus Gratton | 66be82da7c | |
iabdalkader | 0960d64d3b | |
iabdalkader | 50f31cc902 | |
Damien George | d30d5c99af | |
Damien George | b796f1e3f1 | |
Damien George | 3f2c423686 | |
Scott Zhao | 1323a71823 | |
Thomas Wenrich | 78b3fe5689 | |
Damien George | d3595fed2b | |
Damien George | 69089a532e | |
Angus Gratton | 527c4b0497 | |
Angus Gratton | 731a1f5233 | |
Angus Gratton | b6df8f8452 | |
Angus Gratton | 9f620d2819 | |
MikeTeachman | 58112fc49a | |
Damien George | f3889db265 | |
Damien George | 20af857f52 | |
Damien George | d422b68d10 | |
Carlosgg | 30b0ee34d3 | |
Damien George | b5449b0f09 | |
Carlosgg | 20ffbe1a41 | |
Damien George | ad806df857 | |
Damien George | bfdf500ea5 | |
Damien George | 7d784e5385 | |
Damien George | 7a6489aaa5 | |
Damien George | 49fa3ce65d | |
Damien George | 1c0e4644c7 | |
Damien George | 22d9116c8c | |
Damien George | e3c4c32c64 | |
Damien George | cc8fc450a6 | |
Damien George | 39d4153a8d | |
Damien George | 4bf7987f0a | |
Damien George | f523b86541 | |
Damien George | e1ec6af654 | |
Damien George | 48b5a7b060 | |
Damien George | e68aa40d2a | |
Damien George | 30a63a204d | |
Damien George | 7d39db2503 | |
Damien George | 14432b5da0 | |
Damien George | 7b2f13fb69 | |
Damien George | e120c00c95 | |
Damien George | b4d288ae44 | |
Damien George | 911662cc10 | |
Damien George | c554df57f6 | |
Damien George | 6ba57f760c | |
Damien George | e182f3862e | |
Damien George | 12ef8a5ba2 | |
Damien George | fc94399ffe | |
Damien George | 633c604722 | |
Damien George | c9a9b2e682 | |
Damien George | 516cc280e0 | |
Jeff Epler | 9c7067d9ad | |
iabdalkader | cfcd0c4022 | |
Jim Mussared | 992cd64555 | |
Mark Blakeney | 094b52b8ad | |
Ihor Nehrutsa | d6154925d5 | |
Angus Gratton | 960eef70e8 | |
Trent Piepho | 92f0469711 | |
Trent Piepho | f72a7dde18 | |
Damien George | a85c3c45a6 | |
Angus Gratton | a800ed5ae3 | |
Angus Gratton | 917b56137f | |
Damien George | f397a3ec31 | |
Angus Gratton | fce8d9fd55 | |
Angus Gratton | 57cce79a46 | |
Sebastian Romero | 6117aa686f | |
Sebastian Romero | 6f0193335a | |
stijn | a968888f69 | |
Damien George | 92741a3438 | |
Damien George | c34941109f | |
Rene Straub | 0cc100be2c | |
ThomHPL | 70feb123bf | |
Peter Züger | 36e162f116 | |
Peter Züger | a23dbdca79 | |
Peter Züger | 1879db7105 | |
Andrew Leech | 37c1c5fa49 | |
Angus Gratton | 8b1980ad45 | |
Angus Gratton | f567a9255a | |
Angus Gratton | 5e3f0e7f85 | |
Angus Gratton | 033361da4a | |
Damien George | a00c9d56db | |
Damien George | d46dc5e173 | |
stijn | 365913953a | |
Daniël van de Giessen | 3b954698fa | |
Jim Mussared | af52e1ff24 | |
Mark Blakeney | 2888c5b230 | |
Mark Blakeney | fbb7c32040 | |
robert-hh | f07f90f1ab | |
Andrew Leech | 4679a90097 | |
Angus Gratton | 26d5032980 | |
Angus Gratton | bcbdee2357 | |
Angus Gratton | 2d363a23cb | |
Andrew Leech | bbc5a18d09 | |
Andrew Leech | 4cf741062b | |
Damien George | dff293840e | |
stijn | 958c6d917d | |
Damien George | 03eae48847 | |
Jim Mussared | 4212799fd8 | |
Jim Mussared | 9be0623d4c | |
Alessandro Gatti | bea6ff82fa | |
robert-hh | c35cc63366 | |
robert-hh | 59afeb056a | |
robert-hh | 2c1f238205 | |
robert-hh | 6866d17d8f | |
Jim Mussared | 47ed06bda2 | |
robert-hh | e63d7189bc | |
robert-hh | ae3b1cfab1 | |
Jim Mussared | 09c9c8ac30 | |
Jim Mussared | c028f956fc | |
Jim Mussared | 841422817e | |
Angus Gratton | 8c432ea2d4 | |
iabdalkader | b41055a5a3 | |
Maarten van der Schrieck | d95f5aa011 | |
Rene Straub | 47ea831c0e | |
iabdalkader | e5014a4d79 | |
Jim Mussared | b6a9778484 | |
Mathieu Serandour | c85db05244 | |
Damien George | 9a4d4db3a1 | |
Jim Mussared | 6ef9b29f88 | |
Jim Mussared | 1f804e03f6 | |
Jim Mussared | c0b64a3f23 | |
Jim Mussared | 4d568a5bd7 | |
Jim Mussared | ff6c2adfd7 | |
Jim Mussared | 724ebb9916 | |
Jim Mussared | b4236c7368 | |
Jim Mussared | 286b1b3ed9 | |
Jim Mussared | 98dff07bb4 | |
Jim Mussared | 4bd6ec9ae4 | |
Jim Mussared | b0aec6a0ff | |
Jim Mussared | 9cabee8252 | |
Jim Mussared | 1ee5731122 | |
Jim Mussared | 59f3c7facb | |
Jim Mussared | cb37b7bba7 | |
Jim Mussared | df28aa1a59 | |
Jim Mussared | 3f99dbd634 | |
Jim Mussared | fc54d25a45 | |
Jim Mussared | c3c7c602da | |
Jim Mussared | 2eda513870 | |
Damien George | aa329d11ea | |
Jim Mussared | bbd8760bd9 | |
Jim Mussared | 303ccca7c6 | |
Daniël van de Giessen | 7ad84e0422 | |
Andrew Leech | 06a7bf967c | |
Andrew Leech | d8a263435f | |
Alessandro Gatti | 95ce61d0ad | |
Damien George | 4cffa848f6 | |
Damien George | a614c1d501 | |
Jim Mussared | e579ebb11b | |
Pascal Brunot | a8dd69f206 | |
robert-hh | bbbd484f5b | |
robert-hh | 9c244134fb | |
robert-hh | c4e63ace66 | |
Daniël van de Giessen | b2f220dff8 | |
Daniël van de Giessen | a1d20e0747 | |
Daniël van de Giessen | f1d6af9819 | |
Daniël van de Giessen | e676edac79 | |
Daniël van de Giessen | f74131134c | |
Alessandro Gatti | 1cf3085c57 | |
Seon Rozenblum | c146017f8a | |
Seon Rozenblum | bdae847082 | |
Jim Mussared | 64c79a5423 | |
Jim Mussared | e910533012 | |
Jim Mussared | 78f4f30cb1 | |
Jim Mussared | 1a017511d0 | |
iabdalkader | 2fda94c286 | |
Alessandro Gatti | b6c369a396 | |
Jim Mussared | 6cd99910cd | |
Jim Mussared | 3bf70f16e9 | |
Damien George | 3e2706a18d | |
Damien George | 6989aba93b | |
Damien George | d336c1b79b | |
Damien George | 90023b4dcf | |
Damien George | 5b4a2baff6 | |
Damien George | 95d8b5fd55 | |
Damien George | 48e0986666 | |
Damien George | bb4be837c3 | |
Damien George | 91a3f18391 | |
Damien George | 46ae3b5a34 | |
Damien George | 676f9bb78c | |
Damien George | 1477986815 | |
Damien George | cdd9ad8d62 | |
Damien George | a2d7e0da0b | |
Damien George | f2f3ef162d | |
Damien George | 7e7af71527 | |
Damien George | 60929ec7e2 | |
iabdalkader | 2590a34ed7 | |
iabdalkader | 5e52389f99 | |
iabdalkader | 4358faab0c | |
iabdalkader | 7bbf7910fe | |
iabdalkader | 9ed39553f2 | |
Christian Walther | 7be16e0540 | |
Christian Walther | be28829ae8 | |
Christian Walther | 0c4fb16871 | |
Christian Walther | 5f7065f57a | |
Christian Walther | e3ba6f952b | |
Seon Rozenblum | 86c7b957a8 | |
Jim Mussared | 3883f29485 | |
Kwabena W. Agyeman | e78471416b | |
Kwabena W. Agyeman | 433158076f | |
Kwabena W. Agyeman | 64ad676424 | |
Jim Mussared | c2361328e1 | |
Damien George | 971f1cf987 | |
Damien George | e15882ad2b | |
Rene Straub | 51da8cc28b | |
iabdalkader | 8b12923da2 | |
robert-hh | f84b4617cb | |
iabdalkader | 4074f828dd | |
Thomas Ackermann | ac4f79592b | |
Jim Mussared | 8eb7721b4a | |
Jim Mussared | 03a9fa227d | |
Jim Mussared | d040478d8a | |
Damien George | a1be5e1439 | |
Damien George | 6967ff3c58 | |
Damien George | 9b63421fb3 | |
Damien George | 9c7ea9b14a | |
Damien George | 516385c4cc | |
Ned Konz | 66c62353ce | |
Daniël van de Giessen | 4f5e165d0b | |
Matthias Urlichs | 5f0bd33b73 | |
Damien George | 05cb1406ad | |
Jim Mussared | 5015779a6f | |
robert-hh | 480659b1ac | |
Andrew Leech | d2a9d70c09 | |
Glenn Moloney | 9f835df35e | |
robert-hh | a06f4c8df4 | |
Matthias Urlichs | 3fb1bb131f | |
Jim Mussared | 5232847771 | |
Lephenixnoir | 70e15e9ed1 | |
Lephenixnoir | 01036c9611 | |
Lephenixnoir | e35ed0c2fb | |
mibi88 | 814b226158 | |
mibi88 | 7b7c00842f | |
mibi88 | 0b74e8cfb1 | |
mibi88 | 553af9b9c9 | |
mibi88 | 38f340cecd | |
Lephenixnoir | 3df7eae26c | |
Lephenixnoir | 7ecc558700 | |
Lephenixnoir | 8a498563b8 | |
Lephenixnoir | 4f63ac05d3 | |
Lephenixnoir | 63c4c8f609 | |
Lephenixnoir | e001880d5b | |
Lephenixnoir | da416f067f | |
mibi88 | 81d4bbdb1a | |
mibi88 | 16bd85a754 | |
Lephenixnoir | 53b2e6bfed | |
Lephenixnoir | b5d7c61c91 | |
Lephenixnoir | 0d20ae7929 | |
Lephenixnoir | ddab477c3e | |
Lephenixnoir | 189aadff1c | |
Lephenixnoir | 0da3395e89 | |
Lephenixnoir | dc062623da | |
Lephenixnoir | a4d5bc0752 | |
Lephenixnoir | dff23463b0 | |
Lephenixnoir | e85d84e802 | |
Lephenixnoir | 49e3f6a6af | |
Lephenixnoir | 9bdb18f49f | |
Lephenixnoir | 9684b6893f | |
Lephenixnoir | 46ca19aece | |
mibi88 | cb887885b9 | |
Lephenixnoir | d7d1df46bb | |
Lephenixnoir | 40a2de1a5f | |
Lephenixnoir | 8f5af62f9f | |
Lephenixnoir | edf57c6f07 | |
Lephenixnoir | e40f8cba15 | |
Lephenixnoir | 5051323860 | |
Lephenixnoir | 2cc8fe63e5 | |
Lephenixnoir | ed66b0d6a7 | |
mibi88 | b664e0ab9c | |
mibi88 | e3bda720ff | |
mibi88 | b39dc00203 | |
mibi88 | f9d6f55625 | |
mibi88 | c6e1666918 | |
mibi88 | 2ace52aff9 | |
mibi88 | a6fb6122db | |
mibi88 | 6fcce03e5c | |
Lephenixnoir | eeae10abc5 | |
Lephenixnoir | c1d2ca5048 | |
Lephenixnoir | 524562e8bc | |
Lephenixnoir | ab0f70effc | |
Lephenixnoir | 99f2156e5e | |
Lephenixnoir | bfa5de2cf9 | |
Lephenixnoir | 9ea4c17112 | |
Lephenixnoir | 5f1a066c94 | |
Lephenixnoir | 6c2aa39e56 | |
Lephenixnoir | 404d69aea4 | |
Lephenixnoir | 27822c2461 | |
Lephenixnoir | fa6aa00dae | |
Lephenixnoir | 4e529b5788 | |
Lephenixnoir | 2c238906e7 | |
Lephenixnoir | 8809f3eee4 | |
Lephenixnoir | d0654fc5e7 | |
Lephenixnoir | d6334be488 | |
Lephenixnoir | 3431000d2f | |
Lephenixnoir | ce4fefebbe | |
Lephenixnoir | e1df7e5f0b | |
Lephenixnoir | f930ff95db | |
Lephenixnoir | 1992ec0a49 | |
Lephenixnoir | c237e9874f | |
Lephenixnoir | a0d6c33275 | |
Lephenixnoir | f9b4c1f844 | |
Lephenixnoir | e33d85b1de |
|
@ -1,3 +1,6 @@
|
|||
# all: Update Python formatting to ruff-format.
|
||||
bbd8760bd9a2302e5abee29db279102bb11d7732
|
||||
|
||||
# all: Fix various spelling mistakes found by codespell 2.2.6.
|
||||
cf490a70917a1b2d38ba9b58e763e0837d0f7ca7
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
|
||||
# These are binary so should never be modified by git.
|
||||
*.a binary
|
||||
*.ico binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.dxf binary
|
||||
*.mpy binary
|
||||
*.der binary
|
||||
|
||||
# These should also not be modified by git.
|
||||
tests/basics/string_cr_conversion.py -text
|
||||
|
|
|
@ -11,11 +11,11 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_code_formatting_setup
|
||||
run: source tools/ci.sh && ci_c_code_formatting_setup
|
||||
- name: Run code formatting
|
||||
run: source tools/ci.sh && ci_code_formatting_run
|
||||
run: source tools/ci.sh && ci_c_code_formatting_run
|
||||
- name: Check code formatting
|
||||
run: git diff --exit-code
|
||||
|
||||
|
@ -23,7 +23,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_code_spell_setup
|
||||
- name: Run spell checker
|
||||
|
|
|
@ -36,7 +36,7 @@ jobs:
|
|||
run: echo $PR_NUMBER > pr_number
|
||||
- name: Upload diff
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: code-size-report
|
||||
path: |
|
||||
|
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
steps:
|
||||
- name: 'Download artifact'
|
||||
id: download-artifact
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
|
@ -56,7 +56,7 @@ jobs:
|
|||
run: unzip code-size-report.zip
|
||||
- name: Post comment to pull request
|
||||
if: steps.download-artifact.outputs.result == 'ok'
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
script: |
|
||||
|
|
|
@ -13,6 +13,6 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: '100'
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Check commit message formatting
|
||||
run: source tools/ci.sh && ci_commit_formatting_run
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
name: Build docs
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- docs/**
|
||||
|
@ -15,7 +16,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Install Python packages
|
||||
run: pip install -r docs/requirements.txt
|
||||
- name: Build docs
|
||||
|
|
|
@ -16,13 +16,13 @@ jobs:
|
|||
# Setting this to zero means fetch all history and tags,
|
||||
# which hatch-vcs can use to discover the version tag.
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Install build tools
|
||||
run: pip install build
|
||||
- name: Build mpremote wheel
|
||||
run: cd tools/mpremote && python -m build --wheel
|
||||
- name: Archive mpremote wheel
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mpremote
|
||||
path: |
|
||||
|
|
|
@ -18,11 +18,40 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_idf50:
|
||||
build_idf:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ci_func: # names are functions in ci.sh
|
||||
- esp32_build_cmod_spiram_s2
|
||||
- esp32_build_s3_c3
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_esp32_idf50_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_esp32_build
|
||||
|
||||
- id: idf_ver
|
||||
name: Read the ESP-IDF version
|
||||
run: source tools/ci.sh && echo "IDF_VER=$IDF_VER" | tee "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cached ESP-IDF install
|
||||
id: cache_esp_idf
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./esp-idf/
|
||||
~/.espressif/
|
||||
!~/.espressif/dist/
|
||||
~/.cache/pip/
|
||||
key: esp-idf-${{ steps.idf_ver.outputs.IDF_VER }}
|
||||
|
||||
- name: Install ESP-IDF packages
|
||||
if: steps.cache_esp_idf.outputs.cache-hit != 'true'
|
||||
run: source tools/ci.sh && ci_esp32_idf_setup
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: esp32-${{ matrix.ci_func }}
|
||||
|
||||
- name: Build ci_${{matrix.ci_func }}
|
||||
run: source tools/ci.sh && ci_${{ matrix.ci_func }}
|
||||
|
|
|
@ -18,20 +18,18 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build_pyb:
|
||||
build_stm32:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ci_func: # names are functions in ci.sh
|
||||
- stm32_pyb_build
|
||||
- stm32_nucleo_build
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_stm32_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_stm32_pyb_build
|
||||
- name: Build ci_${{matrix.ci_func }}
|
||||
run: source tools/ci.sh && ci_${{ matrix.ci_func }}
|
||||
|
||||
build_nucleo:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_stm32_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_stm32_nucleo_build
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
name: teensy port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'shared/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/teensy/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_teensy_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_teensy_build
|
|
@ -55,6 +55,18 @@ jobs:
|
|||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
standard_v2:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_standard_v2_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_standard_v2_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
@ -184,7 +196,7 @@ jobs:
|
|||
runs-on: macos-11.0
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.8'
|
||||
- name: Build
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
||||
name: Python code lint with ruff
|
||||
name: Python code lint and formatting with ruff
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
ruff:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: pip install --user ruff
|
||||
- run: ruff --format=github .
|
||||
- run: pip install --user ruff==0.1.3
|
||||
- run: ruff check --output-format=github .
|
||||
- run: ruff format --diff .
|
||||
|
|
|
@ -23,3 +23,6 @@ user.props
|
|||
|
||||
# MacOS desktop metadata files
|
||||
.DS_Store
|
||||
|
||||
# vscode
|
||||
.vscode/
|
|
@ -2,8 +2,8 @@ repos:
|
|||
- repo: local
|
||||
hooks:
|
||||
- id: codeformat
|
||||
name: MicroPython codeformat.py for changed files
|
||||
entry: tools/codeformat.py -v -f
|
||||
name: MicroPython codeformat.py for changed C files
|
||||
entry: tools/codeformat.py -v -c -f
|
||||
language: python
|
||||
- id: verifygitlog
|
||||
name: MicroPython git commit message format checker
|
||||
|
@ -12,6 +12,7 @@ repos:
|
|||
verbose: true
|
||||
stages: [commit-msg]
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.265
|
||||
rev: v0.1.3
|
||||
hooks:
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
|
|
|
@ -53,13 +53,16 @@ are then certifying and signing off against the following:
|
|||
Code auto-formatting
|
||||
====================
|
||||
|
||||
Both C and Python code are auto-formatted using the `tools/codeformat.py`
|
||||
script. This uses [uncrustify](https://github.com/uncrustify/uncrustify) to
|
||||
format C code and [black](https://github.com/psf/black) to format Python code.
|
||||
After making changes, and before committing, run this tool to reformat your
|
||||
changes to the correct style. Without arguments this tool will reformat all
|
||||
source code (and may take some time to run). Otherwise pass as arguments to
|
||||
the tool the files that changed and it will only reformat those.
|
||||
Both C and Python code formatting are controlled for consistency across the
|
||||
MicroPython codebase. C code is formatted using the `tools/codeformat.py`
|
||||
script which uses [uncrustify](https://github.com/uncrustify/uncrustify).
|
||||
Python code is linted and formatted using
|
||||
[ruff & ruff format](https://github.com/astral-sh/ruff).
|
||||
After making changes, and before committing, run `tools/codeformat.py` to
|
||||
reformat your C code and `ruff format` for any Python code. Without
|
||||
arguments this tool will reformat all source code (and may take some time
|
||||
to run). Otherwise pass as arguments to the tool the files that changed,
|
||||
and it will only reformat those.
|
||||
|
||||
uncrustify
|
||||
==========
|
||||
|
@ -151,12 +154,22 @@ Tips:
|
|||
* To ignore the pre-commit message format check temporarily, start the commit
|
||||
message subject line with "WIP" (for "Work In Progress").
|
||||
|
||||
Running pre-commit manually
|
||||
===========================
|
||||
|
||||
Once pre-commit is installed as per the previous section it can be manually
|
||||
run against the MicroPython python codebase to update file formatting on
|
||||
demand, with either:
|
||||
* `pre-commit run --all-files` to fix all files in the MicroPython codebase
|
||||
* `pre-commit run --file ./path/to/my/file` to fix just one file
|
||||
* `pre-commit run --file ./path/to/my/folder/*` to fix just one folder
|
||||
|
||||
Python code conventions
|
||||
=======================
|
||||
|
||||
Python code follows [PEP 8](https://legacy.python.org/dev/peps/pep-0008/) and
|
||||
is auto-formatted using [black](https://github.com/psf/black) with a line-length
|
||||
of 99 characters.
|
||||
is auto-formatted using [ruff format](https://docs.astral.sh/ruff/formatter)
|
||||
with a line-length of 99 characters.
|
||||
|
||||
Naming conventions:
|
||||
- Module names are short and all lowercase; eg pyb, stm.
|
||||
|
|
4
LICENSE
|
@ -69,6 +69,8 @@ used during the build process and is not part of the compiled source code.
|
|||
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
|
||||
/esp32
|
||||
/ppp_set_auth.* (Apache-2.0)
|
||||
/rp2
|
||||
/mutex_extra.c (BSD-3-clause)
|
||||
/stm32
|
||||
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
|
||||
/stm32_it.* (MIT + BSD-3-clause)
|
||||
|
@ -78,8 +80,6 @@ used during the build process and is not part of the compiled source code.
|
|||
/*/stm32*.h (BSD-3-clause)
|
||||
/usbdev (MCD-ST Liberty SW License Agreement V2)
|
||||
/usbhost (MCD-ST Liberty SW License Agreement V2)
|
||||
/teensy
|
||||
/core (PJRC.COM)
|
||||
/zephyr
|
||||
/src (Apache-2.0)
|
||||
/tools
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
[![Unix CI badge](https://github.com/micropython/micropython/actions/workflows/ports_unix.yml/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![STM32 CI badge](https://github.com/micropython/micropython/actions/workflows/ports_stm32.yml/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![Docs CI badge](https://github.com/micropython/micropython/actions/workflows/docs.yml/badge.svg)](https://docs.micropython.org/) [![codecov](https://codecov.io/gh/micropython/micropython/branch/master/graph/badge.svg?token=I92PfD05sD)](https://codecov.io/gh/micropython/micropython)
|
||||
|
||||
The MicroPython project
|
||||
=======================
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/micropython/micropython/master/logo/upython-with-micro.jpg" alt="MicroPython Logo"/>
|
||||
</p>
|
||||
|
||||
This is the MicroPython project, which aims to put an implementation
|
||||
of Python 3.x on microcontrollers and small embedded systems.
|
||||
You can find the official website at [micropython.org](http://www.micropython.org).
|
||||
|
||||
WARNING: this project is in beta stage and is subject to changes of the
|
||||
code-base, including project-wide name changes and API changes.
|
||||
|
||||
MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
`with`, `yield from`, etc., and additionally `async`/`await` keywords from
|
||||
Python 3.5 and some select features from later versions). The following core
|
||||
datatypes are provided: `str`(including basic Unicode support), `bytes`,
|
||||
`bytearray`, `tuple`, `list`, `dict`, `set`, `frozenset`, `array.array`,
|
||||
`collections.namedtuple`, classes and instances. Builtin modules include
|
||||
`os`, `sys`, `time`, `re`, and `struct`, etc. Select ports have support for
|
||||
`_thread` module (multithreading), `socket` and `ssl` for networking, and
|
||||
`asyncio`. Note that only a subset of Python 3 functionality is implemented
|
||||
for the data types and modules.
|
||||
|
||||
MicroPython can execute scripts in textual source form (.py files) or from
|
||||
precompiled bytecode (.mpy files), in both cases either from an on-device
|
||||
filesystem or "frozen" into the MicroPython executable.
|
||||
|
||||
MicroPython also provides a set of MicroPython-specific modules to access
|
||||
hardware-specific functionality and peripherals such as GPIO, Timers, ADC,
|
||||
DAC, PWM, SPI, I2C, CAN, Bluetooth, and USB.
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
See the [online documentation](https://docs.micropython.org/) for API
|
||||
references and information about using MicroPython and information about how
|
||||
it is implemented.
|
||||
|
||||
We use [GitHub Discussions](https://github.com/micropython/micropython/discussions)
|
||||
as our forum, and [Discord](https://discord.gg/RB8HZSAExQ) for chat. These
|
||||
are great places to ask questions and advice from the community or to discuss your
|
||||
MicroPython-based projects.
|
||||
|
||||
For bugs and feature requests, please [raise an issue](https://github.com/micropython/micropython/issues/new/choose)
|
||||
and follow the templates there.
|
||||
|
||||
For information about the [MicroPython pyboard](https://store.micropython.org/pyb-features),
|
||||
the officially supported board from the
|
||||
[original Kickstarter campaign](https://www.kickstarter.com/projects/214379695/micro-python-python-for-microcontrollers),
|
||||
see the [schematics and pinouts](http://github.com/micropython/pyboard) and
|
||||
[documentation](https://docs.micropython.org/en/latest/pyboard/quickref.html).
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
MicroPython is an open-source project and welcomes contributions. To be
|
||||
productive, please be sure to follow the
|
||||
[Contributors' Guidelines](https://github.com/micropython/micropython/wiki/ContributorGuidelines)
|
||||
and the [Code Conventions](https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md).
|
||||
Note that MicroPython is licenced under the MIT license, and all contributions
|
||||
should follow this license.
|
||||
|
||||
About this repository
|
||||
---------------------
|
||||
|
||||
This repository contains the following components:
|
||||
- [py/](py/) -- the core Python implementation, including compiler, runtime, and
|
||||
core library.
|
||||
- [mpy-cross/](mpy-cross/) -- the MicroPython cross-compiler which is used to turn scripts
|
||||
into precompiled bytecode.
|
||||
- [ports/](ports/) -- platform-specific code for the various ports and architectures that MicroPython runs on.
|
||||
- [lib/](lib/) -- submodules for external dependencies.
|
||||
- [tests/](tests/) -- test framework and test scripts.
|
||||
- [docs/](docs/) -- user documentation in Sphinx reStructuredText format. This is used to generate the [online documentation](http://docs.micropython.org).
|
||||
- [extmod/](extmod/) -- additional (non-core) modules implemented in C.
|
||||
- [tools/](tools/) -- various tools, including the pyboard.py module.
|
||||
- [examples/](examples/) -- a few example Python scripts.
|
||||
|
||||
"make" is used to build the components, or "gmake" on BSD-based systems.
|
||||
You will also need bash, gcc, and Python 3.3+ available as the command `python3`
|
||||
(if your system only has Python 2.7 then invoke make with the additional option
|
||||
`PYTHON=python2`). Some ports (rp2 and esp32) additionally use CMake.
|
||||
|
||||
Supported platforms & architectures
|
||||
-----------------------------------
|
||||
|
||||
MicroPython runs on a wide range of microcontrollers, as well as on Unix-like
|
||||
(including Linux, BSD, macOS, WSL) and Windows systems.
|
||||
|
||||
Microcontroller targets can be as small as 256kiB flash + 16kiB RAM, although
|
||||
devices with at least 512kiB flash + 128kiB RAM allow a much more
|
||||
full-featured experience.
|
||||
|
||||
The [Unix](ports/unix) and [Windows](ports/windows) ports allow both
|
||||
development and testing of MicroPython itself, as well as providing
|
||||
lightweight alternative to CPython on these platforms (in particular on
|
||||
embedded Linux systems).
|
||||
|
||||
The ["minimal"](ports/minimal) port provides an example of a very basic
|
||||
MicroPython port and can be compiled as both a standalone Linux binary as
|
||||
well as for ARM Cortex M4. Start with this if you want to port MicroPython to
|
||||
another microcontroller. Additionally the ["bare-arm"](ports/bare-arm) port
|
||||
is an example of the absolute minimum configuration, and is used to keep
|
||||
track of the code size of the core runtime and VM.
|
||||
|
||||
In addition, the following ports are provided in this repository:
|
||||
- [cc3200](ports/cc3200) -- Texas Instruments CC3200 (including PyCom WiPy).
|
||||
- [esp32](ports/esp32) -- Espressif ESP32 SoC (including ESP32S2, ESP32S3, ESP32C3).
|
||||
- [esp8266](ports/esp8266) -- Espressif ESP8266 SoC.
|
||||
- [mimxrt](ports/mimxrt) -- NXP m.iMX RT (including Teensy 4.x).
|
||||
- [nrf](ports/nrf) -- Nordic Semiconductor nRF51 and nRF52.
|
||||
- [pic16bit](ports/pic16bit) -- Microchip PIC 16-bit.
|
||||
- [powerpc](ports/powerpc) -- IBM PowerPC (including Microwatt)
|
||||
- [qemu-arm](ports/qemu-arm) -- QEMU-based emulated target, for testing)
|
||||
- [renesas-ra](ports/renesas-ra) -- Renesas RA family.
|
||||
- [rp2](ports/rp2) -- Raspberry Pi RP2040 (including Pico and Pico W).
|
||||
- [samd](ports/samd) -- Microchip (formerly Atmel) SAMD21 and SAMD51.
|
||||
- [stm32](ports/stm32) -- STMicroelectronics STM32 family (including F0, F4, F7, G0, G4, H7, L0, L4, WB)
|
||||
- [webassembly](ports/webassembly) -- Emscripten port targeting browsers and NodeJS.
|
||||
- [zephyr](ports/zephyr) -- Zephyr RTOS.
|
||||
|
||||
The MicroPython cross-compiler, mpy-cross
|
||||
-----------------------------------------
|
||||
|
||||
Most ports require the [MicroPython cross-compiler](mpy-cross) to be built
|
||||
first. This program, called mpy-cross, is used to pre-compile Python scripts
|
||||
to .mpy files which can then be included (frozen) into the
|
||||
firmware/executable for a port. To build mpy-cross use:
|
||||
|
||||
$ cd mpy-cross
|
||||
$ make
|
||||
|
||||
External dependencies
|
||||
---------------------
|
||||
|
||||
The core MicroPython VM and runtime has no external dependencies, but a given
|
||||
port might depend on third-party drivers or vendor HALs. This repository
|
||||
includes [several submodules](lib/) linking to these external dependencies.
|
||||
Before compiling a given port, use
|
||||
|
||||
$ cd ports/name
|
||||
$ make submodules
|
||||
|
||||
to ensure that all required submodules are initialised.
|
191
README.md
|
@ -1,148 +1,87 @@
|
|||
[![CI badge](https://github.com/micropython/micropython/workflows/unix%20port/badge.svg)](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [![codecov](https://codecov.io/gh/micropython/micropython/branch/master/graph/badge.svg?token=I92PfD05sD)](https://codecov.io/gh/micropython/micropython)
|
||||
# PythonExtra - A community MicroPython for CASIO calculators
|
||||
|
||||
The MicroPython project
|
||||
=======================
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/micropython/micropython/master/logo/upython-with-micro.jpg" alt="MicroPython Logo"/>
|
||||
</p>
|
||||
*Original MicroPython README: [`README-MicroPython.md`](README-MicroPython.md).*
|
||||
|
||||
This is the MicroPython project, which aims to put an implementation
|
||||
of Python 3.x on microcontrollers and small embedded systems.
|
||||
You can find the official website at [micropython.org](http://www.micropython.org).
|
||||
This is a MicroPython port for fx-CG 50, fx-9860G III and related CASIO calculators.
|
||||
|
||||
WARNING: this project is in beta stage and is subject to changes of the
|
||||
code-base, including project-wide name changes and API changes.
|
||||
**Build instructions**
|
||||
|
||||
MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
`with`, `yield from`, etc., and additionally `async`/`await` keywords from
|
||||
Python 3.5 and some select features from later versions). The following core
|
||||
datatypes are provided: `str`(including basic Unicode support), `bytes`,
|
||||
`bytearray`, `tuple`, `list`, `dict`, `set`, `frozenset`, `array.array`,
|
||||
`collections.namedtuple`, classes and instances. Builtin modules include
|
||||
`os`, `sys`, `time`, `re`, and `struct`, etc. Select ports have support for
|
||||
`_thread` module (multithreading), `socket` and `ssl` for networking, and
|
||||
`asyncio`. Note that only a subset of Python 3 functionality is implemented
|
||||
for the data types and modules.
|
||||
Requires the [fxSDK](/Lephenixnoir/fxsdk). Go to `ports/fxcg50` or `ports/fx9860g3` and run `make`. If it doesn't build, first try to use the `dev` branches for [fxSDK](/Lephenixnoir/fxSDK), [gint](/Lephenixnoir/gint), [fxlibc](/Lephenixnoir/fxlib) and [JustUI](/Lephenixnoir/JustUI). Rebuilds don't always work especially when checking out other commits (maybe my fault), so try to delete `build` if you think that's related.
|
||||
|
||||
MicroPython can execute scripts in textual source form (.py files) or from
|
||||
precompiled bytecode (.mpy files), in both cases either from an on-device
|
||||
filesystem or "frozen" into the MicroPython executable.
|
||||
Most of the code is in `ports/sh` and is shared between the platforms.
|
||||
|
||||
MicroPython also provides a set of MicroPython-specific modules to access
|
||||
hardware-specific functionality and peripherals such as GPIO, Timers, ADC,
|
||||
DAC, PWM, SPI, I2C, CAN, Bluetooth, and USB.
|
||||
---
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
**Test suite**
|
||||
|
||||
See the [online documentation](https://docs.micropython.org/) for API
|
||||
references and information about using MicroPython and information about how
|
||||
it is implemented.
|
||||
Located in [`ports/sh/examples`](ports/sh/examples).
|
||||
|
||||
We use [GitHub Discussions](https://github.com/micropython/micropython/discussions)
|
||||
as our forum, and [Discord](https://discord.gg/RB8HZSAExQ) for chat. These
|
||||
are great places to ask questions and advice from the community or to discuss your
|
||||
MicroPython-based projects.
|
||||
* **fx-CG**: Whether the program successfully runs on PythonExtra on
|
||||
models of the fx-CG family. This is typically tested on a Graph 90+E but
|
||||
should include the fx-CG 10/20/50.
|
||||
* **G-III**: Whether the program successfully runs on G-III models.
|
||||
This does **not** include older models like the fx-9860G II.
|
||||
* **Raw speedup**: Speedup from using PythonExtra instead of the official
|
||||
Python app, without changing the code (as a ratio of execution times).
|
||||
* **Full speedup**: Seedup from using PythonExtra-provided modules for
|
||||
rendering and input (usually `gint`), after changing the program's code.
|
||||
|
||||
For bugs and feature requests, please [raise an issue](https://github.com/micropython/micropython/issues/new/choose)
|
||||
and follow the templates there.
|
||||
| Program | fx-CG | G-III | Raw speedup | Full speedup |
|
||||
| ------- | ----- | ----- | ----------- | ------------ |
|
||||
| Chute tridimensionnelle | Yes | Yes | x1.36 | x2.26 ⁽¹⁾ |
|
||||
| Bad Apple | Meh⁽²⁾ | - | TODO | TODO |
|
||||
| Island of the Dead Kings | TODO | TODO | TODO | TODO |
|
||||
| Synchro-Donjon (AI mode) | Yes | TODO | x1.82 | - |
|
||||
| Flappy Bird | Yes | Yes | x1.04 | x2.35 |
|
||||
|
||||
For information about the [MicroPython pyboard](https://store.micropython.org/pyb-features),
|
||||
the officially supported board from the
|
||||
[original Kickstarter campaign](https://www.kickstarter.com/projects/214379695/micro-python-python-for-microcontrollers),
|
||||
see the [schematics and pinouts](http://github.com/micropython/pyboard) and
|
||||
[documentation](https://docs.micropython.org/en/latest/pyboard/quickref.html).
|
||||
⁽¹⁾ After upgrading to full-screen 396x224 instead of the original 120x80. (!)
|
||||
|
||||
Contributing
|
||||
------------
|
||||
⁽²⁾ Bad Apple requires unloading modules to not run out of memory, and I
|
||||
haven't been able to consistently do that. See the `unload-modules` branch.
|
||||
|
||||
MicroPython is an open-source project and welcomes contributions. To be
|
||||
productive, please be sure to follow the
|
||||
[Contributors' Guidelines](https://github.com/micropython/micropython/wiki/ContributorGuidelines)
|
||||
and the [Code Conventions](https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md).
|
||||
Note that MicroPython is licenced under the MIT license, and all contributions
|
||||
should follow this license.
|
||||
---
|
||||
|
||||
About this repository
|
||||
---------------------
|
||||
**Basic benchmarks**
|
||||
|
||||
This repository contains the following components:
|
||||
- [py/](py/) -- the core Python implementation, including compiler, runtime, and
|
||||
core library.
|
||||
- [mpy-cross/](mpy-cross/) -- the MicroPython cross-compiler which is used to turn scripts
|
||||
into precompiled bytecode.
|
||||
- [ports/](ports/) -- platform-specific code for the various ports and architectures that MicroPython runs on.
|
||||
- [lib/](lib/) -- submodules for external dependencies.
|
||||
- [tests/](tests/) -- test framework and test scripts.
|
||||
- [docs/](docs/) -- user documentation in Sphinx reStructuredText format. This is used to generate the [online documentation](http://docs.micropython.org).
|
||||
- [extmod/](extmod/) -- additional (non-core) modules implemented in C.
|
||||
- [tools/](tools/) -- various tools, including the pyboard.py module.
|
||||
- [examples/](examples/) -- a few example Python scripts.
|
||||
PythonExtra is slightly faster than the official Python app, probably due to
|
||||
optimization during compilation of the VM. The tests below show the effect on
|
||||
basic Python operations.
|
||||
|
||||
"make" is used to build the components, or "gmake" on BSD-based systems.
|
||||
You will also need bash, gcc, and Python 3.3+ available as the command `python3`
|
||||
(if your system only has Python 2.7 then invoke make with the additional option
|
||||
`PYTHON=python2`). Some ports (rp2 and esp32) additionally use CMake.
|
||||
| Test | Program | Official Python (fx-CG 50) | PythonExtra (fx-CG 50) |
|
||||
| ---- | ------- | -------------------------- | ---------------------- |
|
||||
| VM speed | `pe_loop.py` (1 million `pass`) | ~12 seconds | 8.9 seconds |
|
||||
| Shell output | `pe_print.py` (print 100000 integers) | ~22 seconds | 11.3 seconds |
|
||||
| Large integers | `pe_fact.py` (compute 250!, 500 times) | ~15 seconds | 8.6 seconds |
|
||||
|
||||
Supported platforms & architectures
|
||||
-----------------------------------
|
||||
---
|
||||
|
||||
MicroPython runs on a wide range of microcontrollers, as well as on Unix-like
|
||||
(including Linux, BSD, macOS, WSL) and Windows systems.
|
||||
**TODO list**
|
||||
|
||||
Microcontroller targets can be as small as 256kiB flash + 16kiB RAM, although
|
||||
devices with at least 512kiB flash + 128kiB RAM allow a much more
|
||||
full-featured experience.
|
||||
Bugs to fix:
|
||||
- Fix not world switching during filesystem accesses (very unstable)
|
||||
- Fix current working directory not changing during a module import (for
|
||||
relative imports)
|
||||
- Fix casioplot not stopping on the last `show_screen()`
|
||||
|
||||
The [Unix](ports/unix) and [Windows](ports/windows) ports allow both
|
||||
development and testing of MicroPython itself, as well as providing
|
||||
lightweight alternative to CPython on these platforms (in particular on
|
||||
embedded Linux systems).
|
||||
Python features:
|
||||
- Compare features with existing implementations and other brands
|
||||
- Get filesystem access (open etc) with the POSIX interface
|
||||
- Get a decent amount of RAM not just the fixed 32 kiB that's hardcoded so far
|
||||
|
||||
The ["minimal"](ports/minimal) port provides an example of a very basic
|
||||
MicroPython port and can be compiled as both a standalone Linux binary as
|
||||
well as for ARM Cortex M4. Start with this if you want to port MicroPython to
|
||||
another microcontroller. Additionally the ["bare-arm"](ports/bare-arm) port
|
||||
is an example of the absolute minimum configuration, and is used to keep
|
||||
track of the code size of the core runtime and VM.
|
||||
UI:
|
||||
- Add an option for fixed-width font which also sets $COLUMNS properly so that
|
||||
MicroPython paginates (requires better getenv/setenv support in fxlibc)
|
||||
- Use [unicode-fonts](/Lephenixnoir/unicode-fonts) to provide Unicode support
|
||||
* Extend it with a fixed-width uf8x9 which maybe changes some glyphs (like
|
||||
`i` and `l`; the usual fixed-width unambiguous styles)
|
||||
* Try and provide a font smaller than 5x7 for more compact shell on mono
|
||||
- A decent keymap that can input all relevant characters into the shell
|
||||
- Features that would match MicroPython's readline:
|
||||
* Multi-line input (figure out how to store it); also, auto-indent
|
||||
* History (use `MP_STATE_PORT(readline_hist)` with `readline_push_history()`
|
||||
for a start); also, zsh-style search
|
||||
* Autocompletion (use `mp_repl_autocomplete()` which should hook just fine)
|
||||
|
||||
In addition, the following ports are provided in this repository:
|
||||
- [cc3200](ports/cc3200) -- Texas Instruments CC3200 (including PyCom WiPy).
|
||||
- [esp32](ports/esp32) -- Espressif ESP32 SoC (including ESP32S2, ESP32S3, ESP32C3).
|
||||
- [esp8266](ports/esp8266) -- Espressif ESP8266 SoC.
|
||||
- [mimxrt](ports/mimxrt) -- NXP m.iMX RT (including Teensy 4.x).
|
||||
- [nrf](ports/nrf) -- Nordic Semiconductor nRF51 and nRF52.
|
||||
- [pic16bit](ports/pic16bit) -- Microchip PIC 16-bit.
|
||||
- [powerpc](ports/powerpc) -- IBM PowerPC (including Microwatt)
|
||||
- [qemu-arm](ports/qemu-arm) -- QEMU-based emulated target, for testing)
|
||||
- [renesas-ra](ports/renesas-ra) -- Renesas RA family.
|
||||
- [rp2](ports/rp2) -- Raspberry Pi RP2040 (including Pico and Pico W).
|
||||
- [samd](ports/samd) -- Microchip (formerly Atmel) SAMD21 and SAMD51.
|
||||
- [stm32](ports/stm32) -- STMicroelectronics STM32 family (including F0, F4, F7, G0, G4, H7, L0, L4, WB)
|
||||
- [teensy](ports/teensy) -- Teensy 3.x.
|
||||
- [webassembly](ports/webassembly) -- Emscripten port targeting browsers and NodeJS.
|
||||
- [zephyr](ports/zephyr) -- Zephyr RTOS.
|
||||
|
||||
The MicroPython cross-compiler, mpy-cross
|
||||
-----------------------------------------
|
||||
|
||||
Most ports require the [MicroPython cross-compiler](mpy-cross) to be built
|
||||
first. This program, called mpy-cross, is used to pre-compile Python scripts
|
||||
to .mpy files which can then be included (frozen) into the
|
||||
firmware/executable for a port. To build mpy-cross use:
|
||||
|
||||
$ cd mpy-cross
|
||||
$ make
|
||||
|
||||
External dependencies
|
||||
---------------------
|
||||
|
||||
The core MicroPython VM and runtime has no external dependencies, but a given
|
||||
port might depend on third-party drivers or vendor HALs. This repository
|
||||
includes [several submodules](lib/) linking to these external dependencies.
|
||||
Before compiling a given port, use
|
||||
|
||||
$ cd ports/name
|
||||
$ make submodules
|
||||
|
||||
to ensure that all required submodules are initialised.
|
||||
Future wishes:
|
||||
- Build for fx-9860G II (requires manual filesystem support)
|
||||
- Lephe's secret ideas (complete previous list to unlock)
|
||||
|
|
193
docs/conf.py
|
@ -19,58 +19,56 @@ import os
|
|||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
sys.path.insert(0, os.path.abspath("."))
|
||||
|
||||
# The MICROPY_VERSION env var should be "vX.Y.Z" (or unset).
|
||||
micropy_version = os.getenv('MICROPY_VERSION') or 'latest'
|
||||
micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',')
|
||||
url_pattern = '%s/en/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',)
|
||||
micropy_version = os.getenv("MICROPY_VERSION") or "latest"
|
||||
micropy_all_versions = (os.getenv("MICROPY_ALL_VERSIONS") or "latest").split(",")
|
||||
url_pattern = "%s/en/%%s" % (os.getenv("MICROPY_URL_PREFIX") or "/",)
|
||||
|
||||
# The members of the html_context dict are available inside topindex.html
|
||||
html_context = {
|
||||
'cur_version':micropy_version,
|
||||
'all_versions':[
|
||||
(ver, url_pattern % ver) for ver in micropy_all_versions
|
||||
"cur_version": micropy_version,
|
||||
"all_versions": [(ver, url_pattern % ver) for ver in micropy_all_versions],
|
||||
"downloads": [
|
||||
("PDF", url_pattern % micropy_version + "/micropython-docs.pdf"),
|
||||
],
|
||||
'downloads':[
|
||||
('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'),
|
||||
],
|
||||
'is_release': micropy_version != 'latest',
|
||||
"is_release": micropy_version != "latest",
|
||||
}
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinxcontrib.jquery',
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.doctest",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.todo",
|
||||
"sphinx.ext.coverage",
|
||||
"sphinxcontrib.jquery",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['templates']
|
||||
templates_path = ["templates"]
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
source_suffix = ".rst"
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = 'MicroPython'
|
||||
copyright = '- The MicroPython Documentation is Copyright © 2014-2023, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
project = "MicroPython"
|
||||
copyright = "- The MicroPython Documentation is Copyright © 2014-2023, Damien P. George, Paul Sokolovsky, and contributors"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
@ -82,41 +80,41 @@ version = release = micropy_version
|
|||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['build', '.venv']
|
||||
exclude_patterns = ["build", ".venv"]
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
default_role = 'any'
|
||||
default_role = "any"
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
# keep_warnings = False
|
||||
|
||||
# Global include files. Sphinx docs suggest using rst_epilog in preference
|
||||
# of rst_prolog, so we follow. Absolute paths below mean "from the base
|
||||
|
@ -128,144 +126,148 @@ rst_epilog = """
|
|||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# on_rtd is whether we are on readthedocs.org
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
|
||||
|
||||
if not on_rtd: # only import and set the theme if we're building docs locally
|
||||
try:
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.']
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
|
||||
except:
|
||||
html_theme = 'default'
|
||||
html_theme_path = ['.']
|
||||
html_theme = "default"
|
||||
html_theme_path = ["."]
|
||||
else:
|
||||
html_theme_path = ['.']
|
||||
html_theme_path = ["."]
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = ['.']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
# html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = '../../logo/trans-logo.png'
|
||||
# html_logo = '../../logo/trans-logo.png'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
html_favicon = 'static/favicon.ico'
|
||||
html_favicon = "static/favicon.ico"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['static']
|
||||
html_static_path = ["static"]
|
||||
|
||||
# Add a custom CSS file for HTML generation
|
||||
html_css_files = [
|
||||
'custom.css',
|
||||
"custom.css",
|
||||
]
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
# html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%d %b %Y'
|
||||
html_last_updated_fmt = "%d %b %Y"
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
html_additional_pages = {"index": "topindex.html"}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
# html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'MicroPythondoc'
|
||||
htmlhelp_basename = "MicroPythondoc"
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
# Include 3 levels of headers in PDF ToC
|
||||
'preamble': r'\setcounter{tocdepth}{2}',
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
# Include 3 levels of headers in PDF ToC
|
||||
"preamble": r"\setcounter{tocdepth}{2}",
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'MicroPython.tex', 'MicroPython Documentation',
|
||||
'Damien P. George, Paul Sokolovsky, and contributors', 'manual'),
|
||||
(
|
||||
master_doc,
|
||||
"MicroPython.tex",
|
||||
"MicroPython Documentation",
|
||||
"Damien P. George, Paul Sokolovsky, and contributors",
|
||||
"manual",
|
||||
),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
# latex_domain_indices = True
|
||||
|
||||
# Enable better Unicode support so that `make latexpdf` doesn't fail
|
||||
latex_engine = "xelatex"
|
||||
|
@ -275,12 +277,17 @@ latex_engine = "xelatex"
|
|||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'micropython', 'MicroPython Documentation',
|
||||
['Damien P. George, Paul Sokolovsky, and contributors'], 1),
|
||||
(
|
||||
"index",
|
||||
"micropython",
|
||||
"MicroPython Documentation",
|
||||
["Damien P. George, Paul Sokolovsky, and contributors"],
|
||||
1,
|
||||
),
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
@ -289,23 +296,29 @@ man_pages = [
|
|||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'MicroPython', 'MicroPython Documentation',
|
||||
'Damien P. George, Paul Sokolovsky, and contributors', 'MicroPython', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
(
|
||||
master_doc,
|
||||
"MicroPython",
|
||||
"MicroPython Documentation",
|
||||
"Damien P. George, Paul Sokolovsky, and contributors",
|
||||
"MicroPython",
|
||||
"One line description of project.",
|
||||
"Miscellaneous",
|
||||
),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
# texinfo_no_detailmenu = False
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None)}
|
||||
intersphinx_mapping = {"python": ("https://docs.python.org/3.5", None)}
|
||||
|
|
|
@ -141,7 +141,7 @@ These are working configurations for LAN interfaces of popular boards::
|
|||
# Olimex ESP32-GATEWAY: power controlled by Pin(5)
|
||||
# Olimex ESP32 PoE and ESP32-PoE ISO: power controlled by Pin(12)
|
||||
|
||||
lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5),
|
||||
lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5),
|
||||
phy_type=network.PHY_LAN8720, phy_addr=0,
|
||||
ref_clk=machine.Pin(17), ref_clk_mode=machine.Pin.OUT)
|
||||
|
||||
|
@ -330,6 +330,19 @@ possible at the same frequency.
|
|||
|
||||
See more examples in the :ref:`esp32_pwm` tutorial.
|
||||
|
||||
DAC (digital to analog conversion)
|
||||
----------------------------------
|
||||
|
||||
On the ESP32, DAC functionality is available on pins 25, 26.
|
||||
On the ESP32S2, DAC functionality is available on pins 17, 18.
|
||||
|
||||
Use the DAC::
|
||||
|
||||
from machine import DAC, Pin
|
||||
|
||||
dac = DAC(Pin(25)) # create an DAC object acting on a pin
|
||||
dac.write(128) # set a raw analog value in the range 0-255, 50% now
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
|
|
|
@ -201,10 +201,12 @@ class Lock
|
|||
TCP stream connections
|
||||
----------------------
|
||||
|
||||
.. function:: open_connection(host, port)
|
||||
.. function:: open_connection(host, port, ssl=None)
|
||||
|
||||
Open a TCP connection to the given *host* and *port*. The *host* address will be
|
||||
resolved using `socket.getaddrinfo`, which is currently a blocking call.
|
||||
If *ssl* is a `ssl.SSLContext` object, this context is used to create the transport;
|
||||
if *ssl* is ``True``, a default context is used.
|
||||
|
||||
Returns a pair of streams: a reader and a writer stream.
|
||||
Will raise a socket-specific ``OSError`` if the host could not be resolved or if
|
||||
|
@ -212,12 +214,14 @@ TCP stream connections
|
|||
|
||||
This is a coroutine.
|
||||
|
||||
.. function:: start_server(callback, host, port, backlog=5)
|
||||
.. function:: start_server(callback, host, port, backlog=5, ssl=None)
|
||||
|
||||
Start a TCP server on the given *host* and *port*. The *callback* will be
|
||||
called with incoming, accepted connections, and be passed 2 arguments: reader
|
||||
and writer streams for the connection.
|
||||
|
||||
If *ssl* is a `ssl.SSLContext` object, this context is used to create the transport.
|
||||
|
||||
Returns a `Server` object.
|
||||
|
||||
This is a coroutine.
|
||||
|
|
|
@ -62,12 +62,35 @@ Functions
|
|||
|
||||
.. function:: flash_erase(sector_no)
|
||||
|
||||
.. function:: osdebug(level)
|
||||
.. function:: osdebug(uart_no)
|
||||
|
||||
Turn esp os debugging messages on or off.
|
||||
.. note:: This is the ESP8266 form of this function.
|
||||
|
||||
The *level* parameter sets the threshold for the log messages for all esp components.
|
||||
The log levels are defined as constants:
|
||||
Change the level of OS serial debug log messages. On boot,
|
||||
OS serial debug log messages are disabled.
|
||||
|
||||
``uart_no`` is the number of the UART peripheral which should receive
|
||||
OS-level output, or ``None`` to disable OS serial debug log messages.
|
||||
|
||||
.. function:: osdebug(uart_no, [level])
|
||||
:no-index:
|
||||
|
||||
.. note:: This is the ESP32 form of this function.
|
||||
|
||||
Change the level of OS serial debug log messages. On boot, OS
|
||||
serial debug log messages are limited to Error output only.
|
||||
|
||||
The behaviour of this function depends on the arguments passed to it. The
|
||||
following combinations are supported:
|
||||
|
||||
``osdebug(None)`` restores the default OS debug log message level
|
||||
(``LOG_ERROR``).
|
||||
|
||||
``osdebug(0)`` enables all available OS debug log messages (in the
|
||||
default build configuration this is ``LOG_INFO``).
|
||||
|
||||
``osdebug(0, level)`` sets the OS debug log message level to the
|
||||
specified value. The log levels are defined as constants:
|
||||
|
||||
* ``LOG_NONE`` -- No log output
|
||||
* ``LOG_ERROR`` -- Critical errors, software module can not recover on its own
|
||||
|
@ -77,6 +100,15 @@ Functions
|
|||
* ``LOG_VERBOSE`` -- Bigger chunks of debugging information, or frequent messages
|
||||
which can potentially flood the output
|
||||
|
||||
.. note:: ``LOG_DEBUG`` and ``LOG_VERBOSE`` are not compiled into the
|
||||
MicroPython binary by default, to save size. A custom build with a
|
||||
modified "``sdkconfig``" source file is needed to see any output
|
||||
at these log levels.
|
||||
|
||||
.. note:: Log output on ESP32 is automatically suspended in "Raw REPL" mode,
|
||||
to prevent communications issues. This means OS level logging is never
|
||||
seen when using ``mpremote run`` and similar tools.
|
||||
|
||||
.. function:: set_native_code_location(start, length)
|
||||
|
||||
**Note**: ESP8266 only
|
||||
|
|
|
@ -193,7 +193,7 @@ numbers specified in ``write_pulses`` are multiplied by the resolution to
|
|||
define the pulses.
|
||||
|
||||
``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by
|
||||
multiplying the resolution by a 15-bit (0-32,768) number. There are eight
|
||||
multiplying the resolution by a 15-bit (1-``PULSE_MAX``) number. There are eight
|
||||
channels (0-7) and each can have a different clock divider.
|
||||
|
||||
So, in the example above, the 80MHz clock is divided by 8. Thus the
|
||||
|
@ -226,7 +226,7 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
|||
``100``) and the output level to apply the carrier to (a boolean as per
|
||||
*idle_level*).
|
||||
|
||||
.. method:: RMT.source_freq()
|
||||
.. classmethod:: RMT.source_freq()
|
||||
|
||||
Returns the source clock frequency. Currently the source clock is not
|
||||
configurable so this will always return 80MHz.
|
||||
|
@ -264,10 +264,10 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
|||
**Mode 3:** *duration* and *data* are lists or tuples of equal length,
|
||||
specifying individual durations and the output level for each.
|
||||
|
||||
Durations are in integer units of the channel resolution (as described
|
||||
above), between 1 and 32767 units. Output levels are any value that can
|
||||
be converted to a boolean, with ``True`` representing high voltage and
|
||||
``False`` representing low.
|
||||
Durations are in integer units of the channel resolution (as
|
||||
described above), between 1 and ``PULSE_MAX`` units. Output levels
|
||||
are any value that can be converted to a boolean, with ``True``
|
||||
representing high voltage and ``False`` representing low.
|
||||
|
||||
If transmission of an earlier sequence is in progress then this method will
|
||||
block until that transmission is complete before beginning the new sequence.
|
||||
|
@ -290,6 +290,13 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
|||
Passing in no argument will not change the channel. This function returns
|
||||
the current channel number.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: RMT.PULSE_MAX
|
||||
|
||||
Maximum integer that can be set for a pulse duration.
|
||||
|
||||
Ultra-Low-Power co-processor
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -86,16 +86,6 @@ Functions
|
|||
Classes
|
||||
-------
|
||||
|
||||
.. class:: FileIO(...)
|
||||
|
||||
This is type of a file open in binary mode, e.g. using ``open(name, "rb")``.
|
||||
You should not instantiate this class directly.
|
||||
|
||||
.. class:: TextIOWrapper(...)
|
||||
|
||||
This is type of a file open in text mode, e.g. using ``open(name, "rt")``.
|
||||
You should not instantiate this class directly.
|
||||
|
||||
.. class:: StringIO([string])
|
||||
.. class:: BytesIO([string])
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ Methods
|
|||
Configure the ADC peripheral. *bits* will set the resolution of the
|
||||
conversion process.
|
||||
|
||||
.. method:: ADCBlock.connect(channel)
|
||||
ADCBlock.connect(source)
|
||||
ADCBlock.connect(channel, source)
|
||||
.. method:: ADCBlock.connect(channel, *, ...)
|
||||
ADCBlock.connect(source, *, ...)
|
||||
ADCBlock.connect(channel, source, *, ...)
|
||||
|
||||
Connect up a channel on the ADC peripheral so it is ready for sampling,
|
||||
and return an :ref:`ADC <machine.ADC>` object that represents that connection.
|
||||
|
@ -56,3 +56,6 @@ Methods
|
|||
|
||||
If both *channel* and *source* are given then they are connected together
|
||||
and made ready for sampling.
|
||||
|
||||
Any additional keyword arguments are used to configure the returned ADC object,
|
||||
via its :meth:`init <machine.ADC.init>` method.
|
||||
|
|
|
@ -39,6 +39,33 @@ class SSLContext
|
|||
Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*``
|
||||
constants.
|
||||
|
||||
.. method:: SSLContext.load_cert_chain(certfile, keyfile)
|
||||
|
||||
Load a private key and the corresponding certificate. The *certfile* is a string
|
||||
with the file path of the certificate. The *keyfile* is a string with the file path
|
||||
of the private key.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
MicroPython extension: *certfile* and *keyfile* can be bytes objects instead of
|
||||
strings, in which case they are interpreted as the actual certificate/key data.
|
||||
|
||||
.. method:: SSLContext.load_verify_locations(cafile=None, cadata=None)
|
||||
|
||||
Load the CA certificate chain that will validate the peer's certificate.
|
||||
*cafile* is the file path of the CA certificates. *cadata* is a bytes object
|
||||
containing the CA certificates. Only one of these arguments should be provided.
|
||||
|
||||
.. method:: SSLContext.get_ciphers()
|
||||
|
||||
Get a list of enabled ciphers, returned as a list of strings.
|
||||
|
||||
.. method:: SSLContext.set_ciphers(ciphers)
|
||||
|
||||
Set the available ciphers for sockets created with this context. *ciphers* should be
|
||||
a list of strings in the `IANA cipher suite format <https://wiki.mozilla.org/Security/Cipher_Suites>`_ .
|
||||
|
||||
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None)
|
||||
|
||||
Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
|
||||
|
@ -77,6 +104,12 @@ class SSLContext
|
|||
Set or get the behaviour for verification of peer certificates. Must be one of the
|
||||
``CERT_*`` constants.
|
||||
|
||||
.. note::
|
||||
|
||||
``ssl.CERT_REQUIRED`` requires the device's date/time to be properly set, e.g. using
|
||||
`mpremote rtc --set <mpremote_command_rtc>` or ``ntptime``, and ``server_hostname``
|
||||
must be specified when on the client side.
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ MIMXRT1060-EVK Debug USB D0/D1 D7/D6 D8/D9
|
|||
MIMXRT1064-EVK Debug USB D0/D1 D7/D6 D8/D9
|
||||
MIMXRT1170-EVK Debug USB D0/D1 D12/D11 D10/D13
|
||||
Adafruit Metro M7 - D0/D1 D7/D3 A1/A0
|
||||
Olimex RT1010Py - RxD/TxD D5/D6 -
|
||||
Olimex RT1010Py - RxD/TxD D7/D8 D5/D6
|
||||
Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07
|
||||
================= =========== =========== =========== ===========
|
||||
|
||||
|
|
|
@ -92,9 +92,7 @@ Use the :ref:`machine.Pin <machine.Pin>` class::
|
|||
|
||||
Available Pins follow the ranges and labelling of the respective board, like:
|
||||
|
||||
- 0-33 for Teensy 4.0,
|
||||
- 0-21 for the MIMXRT10xx-EVK board, or 'D0-Dxx', or 'A0-Ann',
|
||||
- 0-14 for the Olimex RT1010Py board, or 'D0'-'Dxx' and 'A0'-'Ann'
|
||||
- 'D0-Dxx', or 'A0-Ann' for Teensy 4.0, MIMXRT10xx-EVK ns Olimex board,
|
||||
- 'J3_xx', 'J4_xx', 'J5_xx' for the Seeed ARCH MIX board,
|
||||
|
||||
or the pin names of the Pin.board or Pin.cpu classes.
|
||||
|
@ -106,9 +104,9 @@ Notes:
|
|||
* At the MIMXRT1010_EVK, pins D4, D5 and D9 of the Arduino connector are by
|
||||
default not connected to the MCU. For details refer to the schematics.
|
||||
* At the MIMXRT1170_EVK board, the inner rows of the Arduino connectors are assigned as follows:
|
||||
- D16 - D23: J9, odd pin numbers; D17 is by default not connected.
|
||||
- D24 - D27: J26, odd pin numbers; J63-J66 have to be closed to enable these pins.
|
||||
- D29 - D36: J25, odd pin numbers; D29 and D30 are by default not connected.
|
||||
- 'D16' - 'D23': J9, odd pin numbers; 'D17' is by default not connected.
|
||||
- 'D24' - 'D27': J26, odd pin numbers; J63-J66 have to be closed to enable these pins.
|
||||
- 'D29' - 'D36': J25, odd pin numbers; 'D29' and 'D30' are by default not connected.
|
||||
|
||||
There's a higher-level abstraction :ref:`machine.Signal <machine.Signal>`
|
||||
which can be used to invert a pin. Useful for illuminating active-low LEDs
|
||||
|
@ -146,22 +144,22 @@ handling signal groups. ::
|
|||
from machine import Pin, PWM
|
||||
|
||||
# create PWM object from a pin and set the frequency and duty cycle
|
||||
pwm2 = PWM(Pin(2), freq=2000, duty_u16=32768)
|
||||
pwm2 = PWM(Pin('D2'), freq=2000, duty_u16=32768)
|
||||
pwm2.freq() # get the current frequency
|
||||
pwm2.freq(1000) # set/change the frequency
|
||||
pwm2.duty_u16() # get the current duty cycle, range 0-65535
|
||||
pwm2.duty_u16(200) # set the duty cycle, range 0-65535
|
||||
pwm2.deinit() # turn off PWM on the pin
|
||||
# create a complementary signal pair on Pin 2 and 3
|
||||
pwm2 = PWM((2, 3), freq=2000, duty_ns=20000)
|
||||
pwm2 = PWM(('D2', 'D3'), freq=2000, duty_ns=20000)
|
||||
|
||||
# Create a group of four synchronized signals.
|
||||
# Start with Pin(4) at submodule 0, which creates the sync pulse.
|
||||
pwm4 = PWM(Pin(4), freq=1000, align=PWM.HEAD)
|
||||
# Pins 5, 6, and 9 are pins at the same module
|
||||
pwm5 = PWM(Pin(5), freq=1000, duty_u16=10000, align=PWM.HEAD, sync=True)
|
||||
pwm6 = PWM(Pin(6), freq=1000, duty_u16=20000, align=PWM.HEAD, sync=True)
|
||||
pwm9 = PWM(Pin(9), freq=1000, duty_u16=30000, align=PWM.HEAD, sync=True)
|
||||
# Start with Pin('D4') at submodule 0, which creates the sync pulse.
|
||||
pwm4 = PWM(Pin('D4'), freq=1000, align=PWM.HEAD)
|
||||
# Pins D5, D6, and D9 are pins at the same module
|
||||
pwm5 = PWM(Pin('D5'), freq=1000, duty_u16=10000, align=PWM.HEAD, sync=True)
|
||||
pwm6 = PWM(Pin('D6', freq=1000, duty_u16=20000, align=PWM.HEAD, sync=True)
|
||||
pwm9 = PWM(Pin('D9'), freq=1000, duty_u16=30000, align=PWM.HEAD, sync=True)
|
||||
|
||||
pwm3 # show the PWM objects properties
|
||||
|
||||
|
@ -256,7 +254,7 @@ Use the :ref:`machine.ADC <machine.ADC>` class::
|
|||
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC(Pin(32)) # create ADC object on ADC pin
|
||||
adc = ADC(Pin('A2')) # create ADC object on ADC pin
|
||||
adc.read_u16() # read value, 0-65536 across voltage range 0.0v - 3.3v
|
||||
|
||||
The resolution of the ADC is 12 bit with 10 to 11 bit accuracy, irrespective of the
|
||||
|
@ -274,7 +272,7 @@ Software SPI (using bit-banging) works on all pins, and is accessed via the
|
|||
# construct a SoftSPI bus on the given pins
|
||||
# polarity is the idle state of SCK
|
||||
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin('D0'), mosi=Pin('D2'), miso=Pin('D4'))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
|
@ -303,7 +301,7 @@ rates (up to 30Mhz). Hardware SPI is accessed via the
|
|||
from machine import SPI, Pin
|
||||
|
||||
spi = SPI(0, 10000000)
|
||||
cs_pin = Pin(6, Pin.OUT, value=1)
|
||||
cs_pin = Pin('D6', Pin.OUT, value=1)
|
||||
cs_pin(0)
|
||||
spi.write('Hello World')
|
||||
cs_pin(1)
|
||||
|
@ -331,7 +329,7 @@ accessed via the :ref:`machine.SoftI2C <machine.SoftI2C>` class::
|
|||
|
||||
from machine import Pin, SoftI2C
|
||||
|
||||
i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||
i2c = SoftI2C(scl=Pin('D5'), sda=Pin('D4'), freq=100000)
|
||||
|
||||
i2c.scan() # scan for devices
|
||||
|
||||
|
@ -365,7 +363,7 @@ See :ref:`machine.I2S <machine.I2S>`. Example using a Teensy 4.1 board with a si
|
|||
external Codec like UDA1334.::
|
||||
|
||||
from machine import I2S, Pin
|
||||
i2s = I2S(2, sck=Pin(26), ws=Pin(27), sd=Pin(7),
|
||||
i2s = I2S(2, sck=Pin('D26'), ws=Pin('D27'), sd=Pin('D7'),
|
||||
mode=I2S.TX, bts=16,format=I2S.STEREO,
|
||||
rate=44100,ibuf=40000)
|
||||
i2s.write(buf) # write buffer of audio samples to I2S device
|
||||
|
@ -397,7 +395,7 @@ Example using the Teensy audio shield::
|
|||
|
||||
from machine import I2C, I2S, Pin
|
||||
from sgtl5000 import CODEC
|
||||
i2s = I2S(1, sck=Pin(21), ws=Pin(20), sd=Pin(7), mck=Pin(23),
|
||||
i2s = I2S(1, sck=Pin('D21'), ws=Pin('D20'), sd=Pin('D7'), mck=Pin('D23'),
|
||||
mode=I2S.TX, bits=16,rate=44100,format=I2S.STEREO,
|
||||
ibuf=40000,
|
||||
)
|
||||
|
@ -475,7 +473,7 @@ The OneWire driver is implemented in software and works on all pins::
|
|||
from machine import Pin
|
||||
import onewire
|
||||
|
||||
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
|
||||
ow = onewire.OneWire(Pin('D12')) # create a OneWire bus on GPIO12
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.readbyte() # read a byte
|
||||
|
@ -505,12 +503,12 @@ The DHT driver is implemented in software and works on all pins::
|
|||
import dht
|
||||
import machine
|
||||
|
||||
d = dht.DHT11(machine.Pin(4))
|
||||
d = dht.DHT11(machine.Pin('D4'))
|
||||
d.measure()
|
||||
d.temperature() # eg. 23 (°C)
|
||||
d.humidity() # eg. 41 (% RH)
|
||||
|
||||
d = dht.DHT22(machine.Pin(4))
|
||||
d = dht.DHT22(machine.Pin('D4'))
|
||||
d.measure()
|
||||
d.temperature() # eg. 23.6 (°C)
|
||||
d.humidity() # eg. 41.3 (% RH)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import os
|
||||
|
||||
# Directory that the project lives in, aka ../..
|
||||
SITE_ROOT = '/'.join(os.path.dirname(__file__).split('/')[0:-2])
|
||||
SITE_ROOT = "/".join(os.path.dirname(__file__).split("/")[0:-2])
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
"%s/templates/" % SITE_ROOT, # Your custom template directory, before the RTD one to override it.
|
||||
"%s/readthedocs/templates/" % SITE_ROOT, # Default RTD template dir
|
||||
"%s/templates/"
|
||||
% SITE_ROOT, # Your custom template directory, before the RTD one to override it.
|
||||
"%s/readthedocs/templates/" % SITE_ROOT, # Default RTD template dir
|
||||
)
|
||||
|
|
|
@ -31,3 +31,4 @@ implementation and the best practices to use them.
|
|||
asm_thumb2_index.rst
|
||||
filesystem.rst
|
||||
pyboard.py.rst
|
||||
micropython2_migration.rst
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
.. _micropython2_migration:
|
||||
|
||||
MicroPython 2.0 Migration Guide
|
||||
===============================
|
||||
|
||||
MicroPython 2.0 is the (currently in development, not yet available) next major
|
||||
release of MicroPython.
|
||||
|
||||
After maintaining API compatibility for almost a decade with the ``1.x`` series, in
|
||||
order to unblock some project-wide improvements MicroPython 2.0 will introduce a
|
||||
small number of breaking API changes that will require some programs to be
|
||||
updated. This guide explains how to update your Python code to accommodate these
|
||||
changes.
|
||||
|
||||
This document is a work-in-progress. As more work is done on MicroPython 2.0,
|
||||
more items will be added to the lists below.
|
||||
|
||||
**Note:** There are currently no MicroPython 2.0 firmware builds available for
|
||||
download. You can build it yourself by enabling the ``MICROPY_PREVIEW_VERSION_2``
|
||||
config option. As it gets closer to being ready for release, builds will be
|
||||
provided for both ``1.x.y`` and ``2.0.0-preview``.
|
||||
|
||||
Hardware and peripherals
|
||||
------------------------
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
The goal is to improve consistency in the :mod:`machine` APIs across different
|
||||
ports, making it easier to write code, documentation, and tutorials that work on
|
||||
any supported microcontroller.
|
||||
|
||||
This means that some ports' APIs need to change to match other ports.
|
||||
|
||||
Changes
|
||||
~~~~~~~
|
||||
|
||||
*None yet*
|
||||
|
||||
OS & filesystem
|
||||
---------------
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
The primary goal is to support the ability to execute :term:`.mpy files <.mpy
|
||||
file>` directly from the filesystem without first copying them into RAM. This
|
||||
improves code deployment time and reduces memory overhead and fragmentation.
|
||||
|
||||
Additionally, a further goal is to support a more flexible way of configuring
|
||||
partitions, filesystem types, and options like USB mass storage.
|
||||
|
||||
Changes
|
||||
~~~~~~~
|
||||
|
||||
*None yet*
|
||||
|
||||
CPython compatibility
|
||||
---------------------
|
||||
|
||||
Overview
|
||||
~~~~~~~~
|
||||
|
||||
The goal is to improve compatibility with CPython by removing MicroPython
|
||||
extensions from CPython APIs. In most cases this means moving existing
|
||||
MicroPython-specific functions or classes to new modules.
|
||||
|
||||
This makes it easier to write code that works on both CPython and MicroPython,
|
||||
which is useful for development and testing.
|
||||
|
||||
Changes
|
||||
~~~~~~~
|
||||
|
||||
*None yet*
|
|
@ -86,7 +86,8 @@ and .mpy version.
|
|||
=================== ============
|
||||
MicroPython release .mpy version
|
||||
=================== ============
|
||||
v1.20 and up 6.1
|
||||
v1.22.0 and up 6.2
|
||||
v1.20 - v1.21.0 6.1
|
||||
v1.19.x 6
|
||||
v1.12 - v1.18 5
|
||||
v1.11 4
|
||||
|
@ -101,6 +102,7 @@ MicroPython repository at which the .mpy version was changed.
|
|||
=================== ========================================
|
||||
.mpy version change Git commit
|
||||
=================== ========================================
|
||||
6.1 to 6.2 6967ff3c581a66f73e9f3d78975f47528db39980
|
||||
6 to 6.1 d94141e1473aebae0d3c63aeaa8397651ad6fa01
|
||||
5 to 6 f2040bfc7ee033e48acef9f289790f3b4e6b74e5
|
||||
4 to 5 5716c5cf65e9b2cb46c2906f40302401bdd27517
|
||||
|
|
|
@ -17,44 +17,53 @@ Adafruit ItsyBitsy M0 Express pin assignment table
|
|||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
0 PA11 D0 11 19 0/3 2/3 1/1 0/3
|
||||
1 PA10 D1 10 18 0/2 2/2 1/0 0/2
|
||||
2 PA14 D2 14 - 2/2 4/2 3/0 0/4
|
||||
3 PA09 D3 9 17 0/1 2/1 0/1 1/3
|
||||
4 PA08 D4 - 16 0/0 2/0 0/0 1/2
|
||||
5 PA15 D5 15 - 2/3 4/3 3/1 0/5
|
||||
7 PA21 D7 5 - 5/3 3/3 7/1 0/7
|
||||
9 PA07 D9 7 7 - 0/3 1/1 -
|
||||
10 PA18 D10 2 - 1/2 3/2 3/0 0/2
|
||||
11 PA16 D11 0 - 1/0 3/0 2/0 0/6
|
||||
12 PA19 D12 3 - 1/3 3/3 3/1 0/3
|
||||
13 PA17 D13 1 - 1/1 3/1 2/1 0/7
|
||||
14 PA02 A0 2 0 - - - -
|
||||
15 PB08 A1 8 2 - 4/0 4/0 -
|
||||
16 PB09 A2 9 3 - 4/1 4/1 -
|
||||
17 PA04 A3 4 4 - 0/0 0/0 -
|
||||
18 PA05 A4 5 5 - 0/1 0/1 -
|
||||
19 PB02 A5 2 - - 5/0 6/0 -
|
||||
20 PA22 SDA 6 - 3/0 5/0 4/0 0/4
|
||||
21 PA23 SCL 7 - 3/1 5/1 4/1 0/5
|
||||
22 PB10 MOSI 10 - - 4/2 5/0 0/4
|
||||
23 PA12 MISO 12 - 2/0 4/0 2/0 0/6
|
||||
24 PB11 SCK 11 - - 4/3 5/1 0/5
|
||||
25 PA00 DOTSTAR_CLK 0 - - 1/0 2/0 -
|
||||
26 PA01 DOTSTAR_DATA 1 - - 1/1 2/1 -
|
||||
27 PB22 FLASH_MOSI 6 - - 5/2 7/0 -
|
||||
28 PB03 FLASH_MISO 3 - - 5/1 6/1 -
|
||||
29 PB23 FLASH_SCK 7 - - 5/3 7/1 -
|
||||
2 PA02 A0 2 0 - - - -
|
||||
40 PB08 A1 8 2 - 4/0 4/0 -
|
||||
41 PB09 A2 9 3 - 4/1 4/1 -
|
||||
4 PA04 A3 4 4 - 0/0 0/0 -
|
||||
5 PA05 A4 5 5 - 0/1 0/1 -
|
||||
34 PB02 A5 2 10 - 5/0 6/0 -
|
||||
11 PA11 D0 11 19 0/3 2/3 1/1 0/3
|
||||
10 PA10 D1 10 18 0/2 2/2 1/0 0/2
|
||||
14 PA14 D2 14 - 2/2 4/2 3/0 0/4
|
||||
9 PA09 D3 9 17 0/1 2/1 0/1 1/3
|
||||
8 PA08 D4 - 16 0/0 2/0 0/0 1/2
|
||||
15 PA15 D5 15 - 2/3 4/3 3/1 0/5
|
||||
21 PA21 D7 5 - 5/3 3/3 7/1 0/7
|
||||
7 PA07 D9 7 7 - 0/3 1/1 -
|
||||
18 PA18 D10 2 - 1/2 3/2 3/0 0/2
|
||||
16 PA16 D11 0 - 1/0 3/0 2/0 0/6
|
||||
19 PA19 D12 3 - 1/3 3/3 3/1 0/3
|
||||
17 PA17 D13 1 - 1/1 3/1 2/1 0/7
|
||||
0 PA00 DOTSTAR_CLK 0 - - 1/0 2/0 -
|
||||
1 PA01 DOTSTAR_DATA 1 - - 1/1 2/1 -
|
||||
27 PA27 FLASH_CS 15 - - - - -
|
||||
35 PB03 FLASH_MISO 3 11 - 5/1 6/1 -
|
||||
54 PB22 FLASH_MOSI 6 - - 5/2 7/0 -
|
||||
55 PB23 FLASH_SCK 7 - - 5/3 7/1 -
|
||||
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
|
||||
42 PB10 MOSI 10 - - 4/2 5/0 0/4
|
||||
43 PB11 SCK 11 - - 4/3 5/1 0/5
|
||||
23 PA23 SCL 7 - 3/1 5/1 4/1 0/5
|
||||
22 PA22 SDA 6 - 3/0 5/0 4/0 0/4
|
||||
30 PA30 SWCLK 10 - - 1/2 1/0 -
|
||||
31 PA31 SWDIO 11 - - 1/3 1/1 -
|
||||
24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2
|
||||
25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3
|
||||
3 PA03 3 1 - - - -
|
||||
6 PA06 6 6 - 0/2 1/0 -
|
||||
13 PA13 13 - 2/1 4/1 2/0 0/7
|
||||
20 PA20 4 - 5/2 3/2 7/0 0/4
|
||||
28 PA28 8 - - - - -
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
|
||||
|
||||
Description of the columns:
|
||||
|
||||
- *Pin* - The number that is expected at ``machine.Pin(n)``, if the pin is given
|
||||
as a number. This is NOT the GPIO number, but the board pin number, as
|
||||
given in the board specific definition file.
|
||||
- *GPIO* - The GPIO number.
|
||||
- *Pin Name* - The name of a Pin which is expected argument to ``machine.Pin("name")``.
|
||||
as a number.
|
||||
- *GPIO* - The GPIO name, which can be used as argument to ``machine.Pin("name")``.
|
||||
- *Pin Name* - The boards name, which can be used as argument to ``machine.Pin("name")``.
|
||||
- *IRQ* - The IRQ number assigned to that GPIO, used internally by ``Pin.irq()``. When
|
||||
using ``Pin.irq()``, different pins must use different IRQs
|
||||
- *ADC* - The ADC channel assigned to the pin. When using ADC, different pins must
|
||||
|
@ -183,10 +192,9 @@ Pin GPIO Pin name IRQ ADC ADC Serial Serial TC PWM PWM
|
|||
Description of the columns:
|
||||
|
||||
- *Pin* - The number that is expected at ``machine.Pin(n)``, if the pin is given
|
||||
as a number. This is NOT the GPIO number, but the board pin number, as
|
||||
given in the board specific definition file.
|
||||
- *GPIO* - The GPIO number.
|
||||
- *Pin Name* The name of a Pin which is expected argument to ``machine.Pin("name")``.
|
||||
as a number.
|
||||
- *GPIO* - The GPIO name, which can be used as argument to ``machine.Pin("name")``.
|
||||
- *Pin Name* - The boards name, which can be used as argument to ``machine.Pin("name")``.
|
||||
- *IRQ* - The IRQ number assigned to that GPIO, used internally by ``Pin.irq()``. When
|
||||
using ``Pin.irq()``, different pins must use different IRQs
|
||||
- *ADC* - The ADC0/1 channel assigned to the pin. When using ADC, different pins must
|
||||
|
@ -862,7 +870,7 @@ Adafruit ItsyBitsy M4 Express :ref:`samd51_pinout_table`.
|
|||
|
||||
The default devices at the board are:
|
||||
|
||||
- UART 1 at pins PB23/PB22, labelled RXD/TXD
|
||||
- UART 2 at pins PA13/PA12, labelled RXD/TXD
|
||||
- I2C 5 at pins PA22/PA23, labelled SDA/SCL
|
||||
- SPI 4 at pins PB12/PB11/PB13, labelled MOSI, MISO and SCK
|
||||
- DAC output on pins PA02 and PA05, labelled A0 and A4
|
||||
|
@ -876,36 +884,36 @@ The tables shown above were created with small a Python script running on the ta
|
|||
from machine import Pin
|
||||
import os
|
||||
|
||||
def print_entry(e, txt):
|
||||
def print_item(e, txt):
|
||||
print(txt, end=": ")
|
||||
if e == 255:
|
||||
print(" - ", end="")
|
||||
else:
|
||||
print("%d/%d" % (e >> 4, e & 0x0f), end="")
|
||||
|
||||
def print_pininfo(pin, info):
|
||||
print("%3d" % pin, end=" ")
|
||||
print("P%c%02d" % ("ABCD"[pin // 32], pin % 32), end="")
|
||||
print(" %12s" % info[0], end="")
|
||||
def print_pininfo(pin_id, name, info):
|
||||
|
||||
print("%3d" % pin_id, end=" ")
|
||||
print("%4s %12s" % (info[0], name), end="")
|
||||
print(" IRQ:%2s" % (info[1] if info[1] != 255 else "-"), end="")
|
||||
print(" ADC0:%2s" % (info[2] if info[2] != 255 else "-"), end="")
|
||||
if len(info) == 7:
|
||||
print_entry(info[3], " Serial1")
|
||||
print_entry(info[4], " Serial2")
|
||||
print_entry(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC")
|
||||
print_entry(info[6], " PWM2")
|
||||
print_item(info[3], " Serial1")
|
||||
print_item(info[4], " Serial2")
|
||||
print_item(info[5], " PWM1" if (info[5] >> 4) < 3 else " TC")
|
||||
print_item(info[6], " PWM2")
|
||||
else:
|
||||
print(" ADC1:%2s" % (info[3] if info[3] != 255 else "-"), end="")
|
||||
print_entry(info[4], " Serial1")
|
||||
print_entry(info[5], " Serial2")
|
||||
print_entry(info[6], " TC")
|
||||
print_entry(info[7], " PWM1")
|
||||
print_entry(info[8], " PWM2")
|
||||
print_item(info[4], " Serial1")
|
||||
print_item(info[5], " Serial2")
|
||||
print_item(info[6], " TC")
|
||||
print_item(info[7], " PWM1")
|
||||
print_item(info[8], " PWM2")
|
||||
print()
|
||||
|
||||
def tblkey(i):
|
||||
name = i[1][0]
|
||||
if name != "-":
|
||||
name = i[1]
|
||||
if name != "":
|
||||
if len(name) < 3:
|
||||
return " " + name
|
||||
else:
|
||||
|
@ -913,17 +921,25 @@ The tables shown above were created with small a Python script running on the ta
|
|||
else:
|
||||
return "zzzzzzz%03d" % i[0]
|
||||
|
||||
def table(num = 127):
|
||||
def table(num=127, sort=True):
|
||||
pintbl = []
|
||||
inv_bd = {v: k for k, v in Pin.board.__dict__.items()}
|
||||
for i in range(num):
|
||||
try:
|
||||
pintbl.append((i, pininfo(i)))
|
||||
p = Pin(i)
|
||||
pi = pininfo(p)
|
||||
if p in inv_bd.keys():
|
||||
name = inv_bd[p]
|
||||
else:
|
||||
name = ""
|
||||
pintbl.append((i, name, pininfo(i)))
|
||||
except:
|
||||
pass
|
||||
# print("not defined")
|
||||
|
||||
pintbl.sort(key=tblkey)
|
||||
if sort:
|
||||
pintbl.sort(key=tblkey)
|
||||
for item in pintbl:
|
||||
print_pininfo(item[0], item[1])
|
||||
print_pininfo(item[0], item[1], item[2])
|
||||
|
||||
table()
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
# Using Numworks' modules `kandinsky`, `ion` and `time` with PythonExtra
|
||||
|
||||
PythonExtra offers the possibility of using certain Numworks modules in order to make the scripts of this machine compatible as is on Casio fx-CG50 (no support on the fx9860G due to insufficient memory and lack of color screen ).
|
||||
|
||||
This is a Work in Progress (WIP) and the support is subject to extensive testing at this stage. The port concerns the Numworks `kandinsky`, `ion` and `time` modules which are machine specific and are now supported via this implementation. The `math`, `cmath`, `random` modules being identical between the `Numworks` version and the `builtins` modules of MicroPython, they are therefore not part of this implementation but are perfectly usable without modification in the scripts.
|
||||
|
||||
Note: the `turtle` and `matplotlib.pyplot` modules are not included in this implementation. It is possible to use the `turtle`, `matplotlib` and `casioplot` modules from Casio Education which are perfectly functional and provided as an example in `ports/sh/examples`.
|
||||
|
||||
|
||||
## `kandinsky`
|
||||
|
||||
The `kandinsky` module provides support for graphics primitives via high-performance `gint` routines. All the functions of this module are available:
|
||||
|
||||
- `color(r,g,b)`: Generates the value of the color r,g,b. You can also simply use a tuple to define a color: (r,g,b).
|
||||
|
||||
- `get_pixel(x,y)`: Returns the color of the pixel at x,y coordinates as a tuple (r,g,b).
|
||||
|
||||
- `set_pixel(x,y,color)`: Lights the pixel x,y of the color color.
|
||||
|
||||
- `draw_string(text,x,y,[color1],[color2])`: Displays the text at x,y coordinates. The arguments color1 (text color) and color2 (text background color) are optional.
|
||||
|
||||
- `fill_rect(x,y,width,height,color)`: Fills a rectangle of width width and height height with the color color at the point of x and y coordinates.
|
||||
|
||||
The module also offers a certain number of colors explicitly named and accessible by a character string. The following values can be used instead of the color parameters of the `kandinsky` functions:
|
||||
- "red", "r"
|
||||
- "green", "g"
|
||||
- "blue", "b"
|
||||
- "black", "k"
|
||||
- "white", "w"
|
||||
- "yellow", "y"
|
||||
- "pink"
|
||||
- "magenta"
|
||||
- "grey", "gray"
|
||||
- "purple"
|
||||
- "orange"
|
||||
- "cyan"
|
||||
- "brown"
|
||||
|
||||
The following functions are additions to take advantage of the wide screen of the fxCG and are therefore an extension of the `Kandinsky` module. They are therefore by definition not compatible with Python Numwork. These functions can be recognized by their names which all begin with `CGEXT_`:
|
||||
|
||||
- `CGEXT_Enable_Wide_Screen()`: Enables the fxCG wide screen, no settings are necessary. The x-coordinates of the physical screen can be negative to encroach on the left white stripe and greater than 319 pixels to encroach on the right white stripe;
|
||||
|
||||
- `CGEXT_Disable_Wide_Screen()`: Cancels the activation of the fxCG extended screen, no settings are necessary. The x coordinates of the physical screen will be constrained between 0 and 320 pixels. Beyond that, the route will not be carried out.
|
||||
|
||||
- `CGEXT_Is_Wide_Screen_Enabled()`: Returns `True` if the extended screen is active and `False` otherwise.
|
||||
|
||||
- `CGEXT_Set_Margin_Color( color )` : Paints the margin of the `Numworks` screen on fxCG with the specified color.
|
||||
|
||||
Note 1: after having made a plot in the extended area, it must be active to allow its deletion (typically via a call to the `fill_rect()` function with the appropriate parameters).
|
||||
|
||||
Note 2: In non-extended mode (by default when initializing the `Kandinsky` module) the screen coordinates go from (0,0) to (319,221) centered on the fxCG screen. In extended mode, the screen coordinates range from (-38,-1) to (358,223).
|
||||
|
||||
|
||||
## `ion`
|
||||
|
||||
The `ion` module gives access to the `keydown(k)` function which returns True if the key k placed as an argument is pressed and False otherwise.
|
||||
|
||||
The “conversion” of the keys between the Numworks machine and Casio fxCG50 is done according to the following mapping:
|
||||
|
||||
| Numworks | Casio fxCG50 | Numworks Key # |
|
||||
|----------|--------------|---------------------|
|
||||
| KEY_LEFT | KEY_LEFT | 0 |
|
||||
| KEY_UP | KEY_UP | 1 |
|
||||
| KEY_DOWN | KEY_DOWN | 2 |
|
||||
| KEY_RIGHT | KEY_RIGHT | 2 |
|
||||
| KEY_OK | KEY_F1 | 4 |
|
||||
| KEY_BACK | KEY_EXIT | 5 |
|
||||
| KEY_HOME | KEY_MENU | 6 |
|
||||
| KEY_ONOFF | KEY_ACON | 7 |
|
||||
| ... | ... | ... |
|
||||
| KEY_SHIFT | KEY_SHIFT | 12 |
|
||||
| KEY_ALPHA | KEY_ALPHA | 13 |
|
||||
| KEY_XNT | KEY_XOT | 14 |
|
||||
| KEY_VAR | KEY_VARS | 15 |
|
||||
| KEY_TOOLBOX | KEY_OPTN | 16 |
|
||||
| KEY_BACKSPACE | KEY_DEL | 17 |
|
||||
| KEY_EXP | KEY_EXP | 17 |
|
||||
| KEY_LN | KEY_LN | 19 |
|
||||
| KEY_LOG | KEY_LOG | 20 |
|
||||
| KEY_IMAGINARY | KEY_F2 | 21 |
|
||||
| KEY_COMMA | KEY_COMMA | 22 |
|
||||
| KEY_POWER | KEY_POWER | 23 |
|
||||
| KEY_SINE | KEY_SIN | 24 |
|
||||
| KEY_COSINE | KEY_COS | 25 |
|
||||
| KEY_TANGENT | KEY_TAN | 26 |
|
||||
| KEY_PI | KEY_F3 | 27 |
|
||||
| KEY_SQRT | KEY_F4 | 28 |
|
||||
| KEY_SQUARE | KEY_SQUARE | 29 |
|
||||
| KEY_SEVEN | KEY_7 | 30 |
|
||||
| KEY_EIGHT | KEY_8 | 31 |
|
||||
| KEY_NINE | KEY_9 | 32 |
|
||||
| KEY_LEFTPARENTHESIS | KEY_LEFTP | 33 |
|
||||
| KEY_RIGHTPARENTHESIS | KEY_RIGHTP | 34 |
|
||||
| ... | ... | ... |
|
||||
| KEY_FOUR | KEY_4 | 36 |
|
||||
| KEY_FIVE | KEY_5 | 37 |
|
||||
| KEY_SIX | KEY_6 | 38 |
|
||||
| KEY_MULTIPLICATION | KEY_MUL | 39 |
|
||||
| KEY_DIVISION | KEY_DIV | 40 |
|
||||
| ... | ... | ... |
|
||||
| KEY_ONE | KEY_1 | 42 |
|
||||
| KEY_TWO | KEY_2 | 43 |
|
||||
| KEY_THREE | KEY_3 | 44 |
|
||||
| KEY_PLUS | KEY_ADD | 45 |
|
||||
| KEY_MINUS | KEY_SUB | 46 |
|
||||
| ... | ... | ... |
|
||||
| KEY_ZERO | KEY_0 | 48 |
|
||||
| KEY_DOT | KEY_DOT | 49 |
|
||||
| KEY_EE | KEY_F5 | 50 |
|
||||
| KEY_ANS | KEY_NEG | 51 |
|
||||
| KEY_EXE | KEY_EXE | 52 |
|
||||
|
||||
|
||||
## `time`
|
||||
|
||||
The `time` module gives access to two functions:
|
||||
|
||||
- `monotonic()`: Returns the clock value at the time the function is called.
|
||||
|
||||
- `sleep(t)`: Suspends execution for t seconds.
|
|
@ -0,0 +1,120 @@
|
|||
# Utilisation des modules `kandinsky`, `ion` et `time` de l'implémentation Python `Numworks`
|
||||
|
||||
PythonExtra offre la possibilité d'utiliser certains modules de la Numworks afin de rendre les scripts de cette machine compatible en l'état sur Casio fx-CG50 (pas de support sur la fx9860G pour cause de mémoire insuffisante et d'abence d'écran couleur).
|
||||
|
||||
Il s'agit d'un Work in Progress (WIP) et le support est sujet à tests approfondis à ce stade. Le port concerne les modules `kandinsky`, `ion` et `time` de la Numworks qui sont spécifiques à la machine et sont désormais supportés via cette implémentation. Les modules `math`, `cmath`, `random` étant identiques entre la version `Numworks` et les modules `builtins` de MicroPython, ils ne font donc pas partie de cette implémentation mais sont parfaitement utilisables sans modification dans les scripts.
|
||||
|
||||
Note : les modules `turtle` et `matplotlib.pyplot` ne sont pas repris dans cette implémentation. Il est possible d'utiliser les modules `turtle`, `matplotlib` et `casioplot` de Casio Education qui sont parfaitement fonctionnels et fournis en example dans `ports/sh/examples`.
|
||||
|
||||
|
||||
## `kandinsky`
|
||||
|
||||
Le module `kandinsky` offre le support des primitives graphiques via les routines hautes performance de `gint`. Toutes les fonctions de ce module sont disponibles :
|
||||
|
||||
- `color(r,g,b)` : Génère la valeur de la couleur r,g,b. Vous pouvez aussi simplement utiliser un tuple pour définir une couleur : (r,g,b).
|
||||
|
||||
- `get_pixel(x,y)` : Renvoie la couleur du pixel aux coordonnées x,y sous forme de tuple (r,g,b).
|
||||
|
||||
- `set_pixel(x,y,color)` : Allume le pixel x,y de la couleur color.
|
||||
|
||||
- `draw_string(text,x,y,[color1],[color2])` : Affiche le texte text aux coordonnées x,y. Les arguments color1 (couleur du texte) et color2 (couleur de lʼarrière plan du texte) sont optionnels.
|
||||
|
||||
- `fill_rect(x,y,width,height,color)` : Remplit un rectangle de largeur width et de hauteur height avec la couleur color au point de coordonnées x et y.
|
||||
|
||||
Le module offre de plus un certain nombre de couleurs explicitement nommées et accessibles par une chaine de caractères. Les valeurs suivantes sont utilisables en lieu et place des paramètres de couleur des fonctions de `kandinsky` :
|
||||
- "red", "r"
|
||||
- "green", "g"
|
||||
- "blue", "b"
|
||||
- "black", "k"
|
||||
- "white", "w"
|
||||
- "yellow", "y"
|
||||
- "pink"
|
||||
- "magenta"
|
||||
- "grey", "gray"
|
||||
- "purple"
|
||||
- "orange"
|
||||
- "cyan"
|
||||
- "brown"
|
||||
|
||||
Les fonctions suivantes sont des ajouts pour tirer partie de l'écran large de la fxCG et qui sont donc une extension du module `Kandinsky`. Elles ne sont donc par définition pas compatible avec le Python Numwork. Ces fonctions sont reconnaisables à leurs appellations qui commencent toutes par `CGEXT_` :
|
||||
|
||||
- `CGEXT_Enable_Wide_Screen()` : Active l'écran étendu de la fxCG, aucun paramètre n'est nécessaire. Les coordonnées x de l'écran physique peuvent être négatives pour empiéter sur la bande blanche de gauche et supérieures à 319 pixels pour empièter sur la bande blanche de droite;
|
||||
|
||||
- `CGEXT_Disable_Wide_Screen()` : Annule l'activation de l'écran étendu de la fxCG, aucun paramètre n'est nécessaire. Les coordonnées x de l'écran physique seront contraintes entre 0 et 320 pixels. Au-delà, le tracé ne sera pas effectué.
|
||||
|
||||
- `CGEXT_Is_Wide_Screen_Enabled()` : Retourne `True` si l'écran étendu est actif et `False` dans le cas contraire.
|
||||
|
||||
- `CGEXT_Set_Margin_Color( color )` : Trace les marge de la fxCG50 (pourtours de l'écran `Numworks`) de la couleur passée en argument.
|
||||
|
||||
Note 1 : après avoir réalisé un tracé dans la zone étendue, il faut que celle-ci soit active pour permettre son effacement (typiquement via un appel à la fonction `fill_rect()` avec les paramètres adéquats).
|
||||
|
||||
Note 2 : En mode non étendu (par défaut à l'initialisation du module `Kandinsky`) les coordonnées de l'écran vont de (0,0) à (319,221) centré sur l'écran de la fxCG. En mode étendu, les coordonnées de l'écran vont de (-38,-1) à (358,223).
|
||||
|
||||
|
||||
## `ion`
|
||||
|
||||
Le module `ion` donne accès à la fonction `keydown(k)` qui renvoie True si la touche k placée en argument est appuyée et False sinon.
|
||||
|
||||
La "conversion" des touches entre la machine Numworks et Casio fxCG50 se fait selon le mapping suivant :
|
||||
|
||||
| Numworks | Casio fxCG50 | Numworks Key # |
|
||||
|----------|--------------|---------------------|
|
||||
| KEY_LEFT | KEY_LEFT | 0 |
|
||||
| KEY_UP | KEY_UP | 1 |
|
||||
| KEY_DOWN | KEY_DOWN | 2 |
|
||||
| KEY_RIGHT | KEY_RIGHT | 2 |
|
||||
| KEY_OK | KEY_F1 | 4 |
|
||||
| KEY_BACK | KEY_EXIT | 5 |
|
||||
| KEY_HOME | KEY_MENU | 6 |
|
||||
| KEY_ONOFF | KEY_ACON | 7 |
|
||||
| ... | ... | ... |
|
||||
| KEY_SHIFT | KEY_SHIFT | 12 |
|
||||
| KEY_ALPHA | KEY_ALPHA | 13 |
|
||||
| KEY_XNT | KEY_XOT | 14 |
|
||||
| KEY_VAR | KEY_VARS | 15 |
|
||||
| KEY_TOOLBOX | KEY_OPTN | 16 |
|
||||
| KEY_BACKSPACE | KEY_DEL | 17 |
|
||||
| KEY_EXP | KEY_EXP | 17 |
|
||||
| KEY_LN | KEY_LN | 19 |
|
||||
| KEY_LOG | KEY_LOG | 20 |
|
||||
| KEY_IMAGINARY | KEY_F2 | 21 |
|
||||
| KEY_COMMA | KEY_COMMA | 22 |
|
||||
| KEY_POWER | KEY_POWER | 23 |
|
||||
| KEY_SINE | KEY_SIN | 24 |
|
||||
| KEY_COSINE | KEY_COS | 25 |
|
||||
| KEY_TANGENT | KEY_TAN | 26 |
|
||||
| KEY_PI | KEY_F3 | 27 |
|
||||
| KEY_SQRT | KEY_F4 | 28 |
|
||||
| KEY_SQUARE | KEY_SQUARE | 29 |
|
||||
| KEY_SEVEN | KEY_7 | 30 |
|
||||
| KEY_EIGHT | KEY_8 | 31 |
|
||||
| KEY_NINE | KEY_9 | 32 |
|
||||
| KEY_LEFTPARENTHESIS | KEY_LEFTP | 33 |
|
||||
| KEY_RIGHTPARENTHESIS | KEY_RIGHTP | 34 |
|
||||
| ... | ... | ... |
|
||||
| KEY_FOUR | KEY_4 | 36 |
|
||||
| KEY_FIVE | KEY_5 | 37 |
|
||||
| KEY_SIX | KEY_6 | 38 |
|
||||
| KEY_MULTIPLICATION | KEY_MUL | 39 |
|
||||
| KEY_DIVISION | KEY_DIV | 40 |
|
||||
| ... | ... | ... |
|
||||
| KEY_ONE | KEY_1 | 42 |
|
||||
| KEY_TWO | KEY_2 | 43 |
|
||||
| KEY_THREE | KEY_3 | 44 |
|
||||
| KEY_PLUS | KEY_ADD | 45 |
|
||||
| KEY_MINUS | KEY_SUB | 46 |
|
||||
| ... | ... | ... |
|
||||
| KEY_ZERO | KEY_0 | 48 |
|
||||
| KEY_DOT | KEY_DOT | 49 |
|
||||
| KEY_EE | KEY_F5 | 50 |
|
||||
| KEY_ANS | KEY_NEG | 51 |
|
||||
| KEY_EXE | KEY_EXE | 52 |
|
||||
|
||||
|
||||
## `time`
|
||||
|
||||
Le module `time` donne accès à deux fonctions :
|
||||
|
||||
- `monotonic()` : Renvoie la valeur de lʼhorloge au moment où la fonction est appelée.
|
||||
|
||||
- `sleep(t)` : Suspend lʼexécution pendant t secondes.
|
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 4.4 KiB |
|
@ -0,0 +1,53 @@
|
|||
# `casioplot`: CASIO's official I/O module
|
||||
|
||||
`casioplot` is a drawing library provided by CASIO as support for the official `turtle` and `matplotlib` modules. It was [announced in February 2020](https://www.planet-casio.com/Fr/forums/topic16154-1-modules-graphiques-python-en-avril-matplotlib-et-turtle.html) and [released in April](https://www.planet-casio.com/Fr/forums/topic16243-1-rendu-graphique-en-python-partie-1-decouverte-de-matplotlib-et-turtle.html). The module is notably available on G-III and fx-CG models with the same API. As of March 2024, `casioplot` is the only custom module in CASIO's official port of MicroPython. PythonExtra also provides the module for source compatibility.
|
||||
|
||||
```py
|
||||
import casioplot
|
||||
# or
|
||||
from casioplot import *
|
||||
```
|
||||
|
||||
**Contents**
|
||||
- [Rendering functions](#rendering-functions)
|
||||
- [Considerations for rendering](#considerations-for-rendering)
|
||||
- [Differences with the official `casioplot` module](#differences-with-the-official-casioplot-module)
|
||||
|
||||
## Rendering functions
|
||||
|
||||
```py
|
||||
show_screen() -> None
|
||||
clear_screen() -> None
|
||||
set_pixel(x: int, y: int, ?color: (int, int, int)) -> None
|
||||
get_pixel(x: int, y: int) -> (int, int, int)
|
||||
draw_string(x: int, y: int, text: str, ?color: (int, int, int), ?size: str) -> None
|
||||
```
|
||||
|
||||
The rendering area is of size 128x64 on G-III and 384x216 on fx-CG. While the G-III supports only two colors (black and white), the fx-CG supports 65536 colors (16-bit RGB565). Still, the color format is _always_ (r,g,b) triplets with 0 ≤ r,g,b ≤ 255. This helps compatibility between models and with PC, at a performance cost. Calculators process these colors by _approximating_ them to the closest color they can represent.
|
||||
|
||||
Like the gint module, `casioplot` functions draw to an internal buffer called the VRAM, and the module only pushes that to the screen when explicitly asked to or at the end of the program.
|
||||
|
||||
`show_screen()` pushes the VRAM to screen after something has been drawn.
|
||||
|
||||
`clear_screen()` fills the VRAM in white.
|
||||
|
||||
`set_pixel()` changes the color of the pixel at (x,y) into the provided `color` encoded as an (r,g,b) triplet (black if not provided). Building triplets is a bit slow so don't write something like `set_pixel(x, y, (0,0,0))` in a loop, store the triplet in a variable and use that instead.
|
||||
|
||||
`get_pixel()` returns the color of the pixel at (x,y) in VRAM as an (r,g,b) triplet. Because VRAM stores colors in the same format as the display, which typically doesn't support all 16 million colors, `get_pixel()` immediately after `set_pixel()`usually returns an _approximation_ of the original color. Because it allocates a triplet, this function is also excruciatingly slow to call in a loop, to the point of creating GC-driven lag spikes that in some situations make it completely unusable.
|
||||
|
||||
`draw_string()` draws text. (x,y) is the location of the top-left corner of the rendered string. The text color is optional; if specified it should be an (r,g,b) triplet, otherwise it is black. The font size can be either of the strings `"small"`, `"medium"` or `"large"` and defaults to medium. On the G-III, the font sizes `"small"` and `"medium"` are identical, but on the fx-CG all three fonts are different. Any `'\n'` in the string is replaced with spaces when drawing.
|
||||
|
||||
TODO: Example
|
||||
|
||||
## Considerations for rendering
|
||||
|
||||
_Text mode._ `casioplot` automatically switches PythonExtra into graphics mode when imported. Programs that want to render graphics frames after a `print()` should `show_screen()` _before_ rendering the first frame since `print()` switches to text mode.
|
||||
|
||||
_Performance._ Writing to VRAM is the main reason why rendering in `casioplot` is sometimes much faster than in Basic. Basic pushes the rendered data to the display after every call, which is slow. Unfortunately, `casioplot` ends up losing for complex drawing tasks for which Basic has complex functions (like DrawStat) while `casioplot` just has single pixels. In this case, functions from the [gint module](modgint-en.md) can be of help.
|
||||
|
||||
## Differences with the official `casioplot` module
|
||||
|
||||
- PythonExtra's implementation doesn't automatically show the screen when the program finishes executing.
|
||||
- The fonts for `draw_string()` are not identical on the G-III port.
|
||||
- The fonts for `draw_string()` currently only support ASCII.
|
||||
- The drawable space on fx-CG is at the top left section of the screen.
|
|
@ -0,0 +1,53 @@
|
|||
# `casioplot` : Module officiel d'I/O de CASIO
|
||||
|
||||
`casioplot` est une bibliothèque de dessin fournie par CASIO pour supporter les modules officiels `turtle` et `matplotlib`. Le module a été [annoncé en Février 2020](https://www.planet-casio.com/Fr/forums/topic16154-1-modules-graphiques-python-en-avril-matplotlib-et-turtle.html) et [publié en Avril](https://www.planet-casio.com/Fr/forums/topic16243-1-rendu-graphique-en-python-partie-1-decouverte-de-matplotlib-et-turtle.html). Le module est disponible sur Graph 35+E II et Graph 90+E avec la même API. C'est le seul module personnalisé dans le port MicroPython de CASIO (à date de Mars 2024). PythonExtra fournit le module par compatibilité pour les scripts officiels.
|
||||
|
||||
```py
|
||||
import casioplot
|
||||
# or
|
||||
from casioplot import *
|
||||
```
|
||||
|
||||
**Sommaire**
|
||||
- [Fonctions de dessin](#fonctions-de-dessin)
|
||||
- [Considérations spéciales pour le rendu](#considérations-spéciales-pour-le-rendu)
|
||||
- [Différences avec le module `casioplot` officiel](#différences-avec-le-module-casioplot-officiel)
|
||||
|
||||
## Fonctions de dessin
|
||||
|
||||
```py
|
||||
show_screen() -> None
|
||||
clear_screen() -> None
|
||||
set_pixel(x: int, y: int, ?color: (int, int, int)) -> None
|
||||
get_pixel(x: int, y: int) -> (int, int, int)
|
||||
draw_string(x: int, y: int, text: str, ?color: (int, int, int), ?size: str) -> None
|
||||
```
|
||||
|
||||
La zone de dessin est de 128x64 pixels sur Graph 35+E II et 384x216 pixels sur la Graph 90+E. La Graph 35+E II ne supporte que deux couleurs (noir et blanc) tandis que la Graph 90+E peut afficher 65536 couleurs (RGB565 16 bits). Cependant, le format de couleurs est _quand même_ des triplets (r,g,b) avec 0 ≤ r,g,b ≤ 255. Ce choix maintient la compabilité entre les modèles et avec le PC, en échange d'un coût en performance. Les calculatrices approximent ces couleurs en les remplaçant par la couleur la plus proche qu'elles peuvent afficher.
|
||||
|
||||
Comme le module gint, `casioplot` dessine systématiquement dans un buffer interne qu'on appelle la VRAM, et n'affiche le résultat à l'écran que quand on lui demande explicitement, ou à la fin de l'exécution.
|
||||
|
||||
`show_screen()` affiche à l'écran les contenus de la VRAM après un dessin.
|
||||
|
||||
`clear_screen()` remplit la VRAM en blanc.
|
||||
|
||||
`set_pixel()` remplace la couleur du pixel à la position (x,y) par `color`, qui doit être un triplet (r,g,b) si fournie, et sera noir si absente. Construire des triplets est un peu lent donc il vaut mieux éviter d'écrire des appels comme `set_pixel(x, y, (0,0,0))` dans des boucles ; il est plus performant de stocker le triplet dans une variable et d'utiliser la variable.
|
||||
|
||||
`get_pixel()` renvoie la couleur du pixel à la position (x,y) de la VRAM sous la forme d'un triplet (r,g,b). Comme la VRAM stocke les couleurs au même format que l'écran, qui ne supporte généralement pas 16 millions de couleurs, appeler `get_pixel()` juste après `set_pixel()` renvoie une _approximation_ de la couleur originale. Comme cette fonction alloue un triplet, elle est atrocement lente à appeler en boucle, au point où elle peut créer du lag simplement par sa pression sur le GC, ce qui la rend parfois inutilisable.
|
||||
|
||||
`draw_string()` affiche du texte. (x,y) est la position du coin haut-gauche du rectangle dans lequel le texte est dessiné. La couleur est optionnelle ; si elle est spécifiée il faut que ce soit un triplet (r,g,b), sinon c'est noir. La taille peut être l'une des trois chaînes `"small"`, `"medium"` ou `"large"` ; la valeur par défaut est `"medium"`. Sur la Graph 35+E II, les polices `"small"` et `"medium"` sont identiques, tandis que sur la Graph 90+E les trois polices sont différentes. Tout `'\n'` dans la chaîne est remplacé par un espace avant d'afficher.
|
||||
|
||||
TODO: Exemple
|
||||
|
||||
## Considérations spéciales pour le rendu
|
||||
|
||||
_Mode texte._ `casioplot` passe automatiquement PythonExtra en mode graphique à l'import. Les programmes qui veulent faire du dessin graphique après un `print()` doivent appeler `show_screen()` _avant_ de commencer à dessiner le premier frame parce que `print()` repasse en mode texte.
|
||||
|
||||
_Performance._ Le fait que les fonctions de dessin écrivent silencieusement dans la VRAM est la principale raison pour laquelle `casioplot` est parfois beaucoup plus rapide que le dessin en Basic. PRGM réaffiche la VRAM à l'écran après chaque appel d'une fonction de dessin, ce qui est lent. Malheureusement, `casioplot` redevient plus lent que le Basic pour les dessins complexes pour lesquels il y a des fonctions spécialisées en Basic (comme `DrawStat`), puisque `casioplot` ne peut dessiner qu'un pixel à la fois. Dans ces situations, il vaut mieux utiliser les fonctions de dessin du [module gint](modgint-fr.md).
|
||||
|
||||
## Différences avec le module `casioplot` officiel
|
||||
|
||||
- L'implémentation PythonExtra du module n'affiche pas automatiquement l'écran à la fin du programme.
|
||||
- Les polices pour `draw_string()` diffèrent des polices officielles sur Graph 35+E II.
|
||||
- Les polices pour `draw_string()` ne supportent actuellement que les caractères ASCII.
|
||||
- Les zone de dessin sur Graph 90+E est en haut à gauche de l'écran.
|
|
@ -0,0 +1,433 @@
|
|||
# `gint`: Wrapper for the gint library
|
||||
|
||||
PythonExtra is developed with the [fxSDK](https://gitea.planet-casio.com/Lephenixnoir/fxsdk) and uses the [gint kernel](https://gitea.planet-casio.com/Lephenixnoir/gint) as a runtime. The Python module `gint` provides access to gint's internal functions for rendering, keyboard, and more. Since gint has many versatile functions with good performance, it is beneficial to use it instead of e.g. `casioplot` or `turtle`.
|
||||
|
||||
The `gint` module tries to match its API with the original API of the C library, which is why few functions use keyword arguments or overloading. There are a few differences documented at the end of this document. For details not described in this document, one can refer to [gint's header files](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint) which are always applicable unless this document explicitly says otherwise.
|
||||
|
||||
All constants, functions, etc. discussed here are in the `gint` module.
|
||||
|
||||
```py
|
||||
import gint
|
||||
# or:
|
||||
from gint import *
|
||||
```
|
||||
|
||||
**Contents**
|
||||
- [Keyboard input](#keyboard-input)
|
||||
- [Drawing and rendering](#drawing-and-rendering)
|
||||
- [Differences with gint's C API](#differences-with-gints-c-api)
|
||||
|
||||
## Keyboard input
|
||||
|
||||
Reference headers: [`<gint/keyboard.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/keyboard.h) and [`<gint/keycodes.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/keycodes.h).
|
||||
|
||||
The module provides integer constants to refer to keyboard keys, with the following names:
|
||||
|
||||
| | | | | | |
|
||||
|------------|------------|------------|------------|------------|-------------|
|
||||
|`KEY_F1` |`KEY_F2` |`KEY_F3` |`KEY_F4` |`KEY_F5` |`KEY_F6` |
|
||||
|`KEY_SHIFT` |`KEY_OPTN` |`KEY_VARS` |`KEY_MENU` |`KEY_LEFT` |`KEY_UP` |
|
||||
|`KEY_ALPHA` |`KEY_SQUARE`|`KEY_POWER` |`KEY_EXIT` |`KEY_DOWN` |`KEY_RIGHT` |
|
||||
|`KEY_XOT` |`KEY_LOG` |`KEY_LN` |`KEY_SIN` |`KEY_COS` |`KEY_TAN` |
|
||||
|`KEY_FRAC` |`KEY_FD` |`KEY_LEFTP` |`KEY_RIGHTP`|`KEY_COMMA` |`KEY_ARROW` |
|
||||
|`KEY_7` |`KEY_8` |`KEY_9` |`KEY_DEL` |`KEY_ACON` | |
|
||||
|`KEY_4` |`KEY_5` |`KEY_6` |`KEY_MUL` |`KEY_DIV` | |
|
||||
|`KEY_1` |`KEY_2` |`KEY_3` |`KEY_ADD` |`KEY_SUB` | |
|
||||
|`KEY_0` |`KEY_DOT` |`KEY_EXP` |`KEY_NEG` |`KEY_EXE` | |
|
||||
|
||||
### Keyboard events
|
||||
|
||||
```
|
||||
key_event:
|
||||
.time -> int
|
||||
.mod -> bool
|
||||
.shift -> bool
|
||||
.alpha -> bool
|
||||
.type -> KEYEV_NONE | KEYEV_DOWN | KEYEV_UP | KEYEV_HOLD
|
||||
.key -> KEY_*
|
||||
```
|
||||
|
||||
gint communicates information about keyboard activity through _events_. Events indicate when a key (`.key` field) is pressed, repeated or released (`.type` field equal to `KEYEV_DOWN`, `KEYEV_HOLD` and `KEYEV_UP` respectively), when (`.time` field), and whether modifiers (SHIFT, `.shift` field, and ALPHA, `.alpha` field) where active at that time.
|
||||
|
||||
(The `.mod` field isn't very interesting, and the `KEYEV_NONE` value for the `.type` field is discussed later with `pollevent()`.)
|
||||
|
||||
The functions `getkey()`, `getkey_opt()`, `pollevent()` and `waitevent()` all return events.
|
||||
|
||||
### Waiting for a key press
|
||||
|
||||
```py
|
||||
getkey() -> key_event
|
||||
getkey_opt(opts: GETKEY_*, timeout_ms: int | None) -> key_event
|
||||
```
|
||||
|
||||
The function `getkey()` pauses the program until a key is pressed or repeated, and returns the associated event (which is always of type `KEYEV_DOWN` or `KEYEV_HOLD`). By default, only arrow keys are repeated, once after 400 ms, then every 40 ms.
|
||||
|
||||
A few things can happen while `getkey()` is waiting. The user can press SHIFT or ALPHA which will trigger modifiers and affect the `.shift` and `.alpha` fields of the returned event. The user can also go to the main menu by pressing MENU or turn the calculator off with SHIFT+AC/ON.
|
||||
|
||||
_Example._ In a selection menu with N possible items, one could navigate with the up and down arrow keys, jump to the top or bottom with SHIFT up and SHIFT down, and validate with EXE.
|
||||
|
||||
```py
|
||||
ev = getkey()
|
||||
if ev.key == KEY_EXE:
|
||||
pass # Validate
|
||||
elif ev.key == KEY_UP and ev.shift:
|
||||
pos = 0 # Jump to top
|
||||
elif ev.key == KEY_DOWN and ev.shift:
|
||||
pos = N-1 # Jump to bottom
|
||||
elif ev.key == KEY_UP and pos > 0:
|
||||
pos -= 1 # Move one place up
|
||||
elif ev.key == KEY_DOWN and pos < N-1:
|
||||
pos += 1 # Move one place down
|
||||
```
|
||||
|
||||
The function `getkey_opt()` generalizes `getkey()` and provides more options to customize its behavior. The `opts` parameter accepts a combination (sum) of options from the table below, and the parameter `timeout_ms`, when not `None`, specifies how long `getkey_opt()` should wait before returning a `KEYEV_NONE` event if nothing happens. The delay is specified in milliseconds but the actual resolution is about 7-8 ms.
|
||||
|
||||
| Option | `getkey()` | Description |
|
||||
|------------------------|------------|--------------------------------------------------|
|
||||
| `GETKEY_MOD_SHIFT` | Yes | SHIFT is a modifier key |
|
||||
| `GETKEY_MOD_ALPHA` | Yes | ALPHA is a modifier key |
|
||||
| `GETKEY_BACKLIGHT` | Yes | SHIFT+OPTN toggles display backlight |
|
||||
| `GETKEY_MENU` | Yes | MENU brings up the calculator's main menu |
|
||||
| `GETKEY_REP_ARROWS` | Yes | Repeats arrow keys when held |
|
||||
| `GETKEY_REP_ALL` | No | Repeats all keys when held |
|
||||
| `GETKEY_REP_PROFILE` | Yes* | Enable custom repeat delays |
|
||||
| `GETKEY_FEATURES` | Yes* | Enable custom global shortcuts |
|
||||
| `GETKEY_MENU_DUPDATE` | Yes | Update display after return to menu (fx-CG) |
|
||||
| `GETKEY_MENU_EVENT` | No | Send a `KEYEV_OSMENU` event after return to menu |
|
||||
| `GETKEY_POWEROFF` | Yes | SHIFT+AC/ON turns the calculator off |
|
||||
|
||||
`getkey()` is equivalent to `getkey_opt(opts, None)` where `opts` is the sum of all options that have "Yes" in the `getkey()` column above.
|
||||
|
||||
The two options `GETKEY_REP_PROFILE` and `GETKEY_FEATURES` are only useful when configured through other functions that are not yet available in PythonExtra.
|
||||
|
||||
### Reading keyboard events in real time
|
||||
|
||||
```py
|
||||
pollevent() -> key_event
|
||||
waitevent() -> key_event
|
||||
clearevents() -> None
|
||||
```
|
||||
|
||||
gint records keyboard activity in the background while the program is running. Events are placed in a queue until the program reads them. This is how `getkey()` learns about keyboard activity, for example.
|
||||
|
||||
The `pollevent()` function provides direct access to events. `pollevent()` returns the oldest event that hasn't yet been read by the program. If there are no events waiting to be read, `pollevent()` returns a "fake" event with type `KEYEV_NONE` to indicate that the queue is empty.
|
||||
|
||||
Since `pollevent()` returns instantly, it can be used to read keyboard activity without pausing the program.
|
||||
|
||||
_Example._ A game loop could, at every frame, read all pending events to determine when the player pressed the SHIFT key (in this example the "action" key) to perform an action.
|
||||
|
||||
```py
|
||||
# Render game...
|
||||
|
||||
while True:
|
||||
ev = pollevent()
|
||||
if ev.type == KEYEV_NONE:
|
||||
break # We're done reading events
|
||||
if ev.type == KEYEV_DOWN and ev.key == KEY_SHIFT:
|
||||
pass # The SHIFT key was just pressed!
|
||||
# Implicitly ignores other keys
|
||||
|
||||
# Simulate game...
|
||||
```
|
||||
|
||||
The `waitevent()` function operates similarly, but if there are no pending events it waits for something to happen before returning. It is used quite rarely because in waiting situations one usually uses `getkey()` instead.
|
||||
|
||||
The function `clearevents()` reads and ignores all events, i.e. it "throws away" all the information about recent keyboard activity. It is useful to know the immediate state of the keyboard with `keydown()'` (see below). `clearevents()` is equivalent to the following definition:
|
||||
|
||||
```py
|
||||
def clearevents():
|
||||
ev = pollevent()
|
||||
while ev.type != KEYEV_NONE:
|
||||
ev = pollevent()
|
||||
```
|
||||
|
||||
### Reading the immediate state of the keyboard
|
||||
|
||||
```py
|
||||
keydown(key: int) -> bool
|
||||
keydown_all(*keys: [int]) -> bool
|
||||
keydown_any(*keys: [int]) -> bool
|
||||
```
|
||||
|
||||
After events have been read and the event queue is empty, one can query the immediate state of keys with the `keydown()` function. `keydown(k)` returns `True` if key `k` is currently pressed, `False` otherwise. This function only works **after events have been read**, which is usually done either with `pollevent()` or with `clearevents()`.
|
||||
|
||||
_Example._ A game loop could check the state of the left/right keys at every frame to move the player.
|
||||
|
||||
```py
|
||||
while True:
|
||||
ev = pollevent()
|
||||
# ... same thing as the pollevent() example
|
||||
|
||||
if keydown(KEY_LEFT):
|
||||
player_x -= 1
|
||||
if keydown(KEY_RIGHT):
|
||||
player_x += 1
|
||||
```
|
||||
|
||||
`keydown_all()` takes a series of keys as parameters and returns `True` if they are all pressed. `keydown_any()` is similar and returns `True` if at least one of the listed keys is pressed.
|
||||
|
||||
### Quickly querying key state changes
|
||||
|
||||
```py
|
||||
cleareventflips() -> None
|
||||
keypressed(key: int) -> bool
|
||||
keyreleased(key: int) -> bool
|
||||
```
|
||||
|
||||
`keydown()` only tells whether keys are pressed at a given time; it cannot be used to check when keys change from the released state to the pressed state or the other way around. To do this, one must either read individual events (which can be annoying), remember which keys were pressed at the previous frame, or use the functions described below.
|
||||
|
||||
`keypressed(k)` and `keyreleased(k)` indicate whether key `k` was pressed/released since the last call to `cleareventflips()`. As previously, here "pressed/released" means "as indicated by keyboard events read" not as a real-time state change.
|
||||
|
||||
_Example._ A game loop could test both the immediate state of some keys and state changes for other keys by using immediate functions after `cleareventflips()` followed by `clearevents()`.
|
||||
|
||||
```py
|
||||
# Render game...
|
||||
|
||||
cleareventflips()
|
||||
clearevents()
|
||||
|
||||
if keypressed(KEY_SHIFT):
|
||||
pass # Action !
|
||||
if keydown(KEY_LEFT):
|
||||
player_x -= 1
|
||||
if keydown(KEY_RIGHT):
|
||||
player_x += 1
|
||||
|
||||
# Simulate game...
|
||||
```
|
||||
|
||||
### Miscellaneous keyboard functions
|
||||
|
||||
```py
|
||||
keycode_function(key: int) -> int
|
||||
keycode_digit(key: int) -> int
|
||||
```
|
||||
|
||||
`keycode_function(k)` returns the F-key number of `k` (i.e. 1 for `KEY_F1`, 2 for `KEY_F2`, etc.) and -1 for other keys.
|
||||
|
||||
`keycode_digit(k)` returns the digit associated with `k` (i.e. 0 for `KEY_0`, 1 for `KEY_1`, etc.) and -1 for other keys.
|
||||
|
||||
## Drawing and rendering
|
||||
|
||||
Reference headers: [`<gint/display.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display.h), and for some details [`<gint/display-fx.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display-fx.h) and [`<gint/display-cg.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display-cg.h).
|
||||
|
||||
### Color manipulation
|
||||
|
||||
```py
|
||||
C_WHITE: int # White
|
||||
C_BLACK: int # Black
|
||||
C_LIGHT: int # Light gray (on B&W: gray engine)
|
||||
C_DARK: int # Dark gray (on B&W: gray engine)
|
||||
C_NONE: int # Transparent
|
||||
C_INVERT: int # Function: inverse
|
||||
|
||||
# Black-and-white (B&W) models only:
|
||||
C_LIGHTEN: int # Function: lighten (gray engine)
|
||||
C_DARKEN: int # Function: darken (gray engine)
|
||||
|
||||
# fx-CG models only:
|
||||
C_RED: int # Pure red
|
||||
C_GREEN: int # Pure green
|
||||
C_BLUE: int # Pure blue
|
||||
C_RGB(r: int, g: int, b: int) -> int
|
||||
```
|
||||
|
||||
Colors are all integers (manipulating `(r,g,b)` tuples is excruciatingly slow and requires memory allocations all over the place). A few default colors are provided.
|
||||
|
||||
On the fx-CG series, the `C_RGB()` function can be used to create colors from three components ranging from 0 to 31.
|
||||
|
||||
TODO: Explain the gray engine.
|
||||
|
||||
### Basic rendering functions
|
||||
|
||||
|
||||
```py
|
||||
DWIDTH: int
|
||||
DHEIGHT: int
|
||||
dupdate() -> None
|
||||
dclear(color: int) -> None
|
||||
dpixel(x: int, y: int, color: int) -> None
|
||||
dgetpixel(x: int, y: int) -> int
|
||||
```
|
||||
|
||||
The integers `DWIDTH` and `DHEIGHT` indicate the screen's dimensions. The screen is 128x64 on black-and-white models (like the G-III) and 396x224 on the fx-CG series (the full screen is available).
|
||||
|
||||
All rendering functions draw to an internal image called the "VRAM"; rendering calls are thus not immediate visible on the screen. For the result to be visible one must call the `dupdate()` function, which transfers the contents of the VRAM to the real display. Usually, this is done after rendering everything we need on one frame instead of after each drawing function call.
|
||||
|
||||
In PythonExtra, `dupdate()` also indicates a "switch to graphics mode". Due to certain optimizations any call to `print()` is considered a "switch to text mode", and while in text mode the shell might redraw at any time. In order to draw after using text mode, one must call `dupdate()` to force a switch to graphics mode before starting rendering. Otherwise the shell and program might render at the same time and produce incoherent results.
|
||||
|
||||
`dclear()` fills the screen with a uniform color.
|
||||
|
||||
`dpixel()` changes a pixel's color. Coordinates, as in every other drawing function, are (x,y) where `x` is in the range 0 to DWIDTH-1 inclusive (0 being left) and `y` is in the range 0 to DHEIGHT-1 inclusive (0 being top).
|
||||
|
||||
`dgetpixel()` returns the color of a pixel. Note that `dgetpixel()` reads from VRAM, not from the display.
|
||||
|
||||
_Example ([`ex_draw1.py`](../../ports/sh/examples/ex_draw1.py))._
|
||||
|
||||
```py
|
||||
from gint import *
|
||||
dclear(C_WHITE)
|
||||
for y in range(10):
|
||||
for x in range(10):
|
||||
if (x^y) & 1:
|
||||
dpixel(x, y, C_BLACK)
|
||||
dupdate()
|
||||
```
|
||||
|
||||
![](images/modgint-draw1-cg.png) ![](images/modgint-draw1-fx.png)
|
||||
|
||||
### Geometric shape rendering functions
|
||||
|
||||
```py
|
||||
drect(x1: int, y1: int, x2: int, y2: int, color: int) -> None
|
||||
drect_border(x1: int, y1: int, x2: int, y2: int, fill_color: int,
|
||||
border_width: int, border_color: int) -> None
|
||||
dline(x1: int, y1: int, x2: int, y2: int, color: int) -> None
|
||||
dhline(y: int, color: int) -> None
|
||||
dvline(x: int, color: int) -> None
|
||||
dcircle(x: int, y: int, radius: int, fill_color: int,
|
||||
border_color: int) -> None
|
||||
dellipse(x1: int, y1: int, x2: int, y2: int, fill_color: int,
|
||||
border_color: int) -> None
|
||||
```
|
||||
|
||||
`drect()` draws a flat rectangle spanning from (x1, y1) to (x2, y2) (both inclusive). The order of points does not matter, i.e. x1 ≥ x2 and y1 ≥ y2 are both allowed.
|
||||
|
||||
`drect_border()` is similar but also draws a border. The border is located _inside_ the rectangle.
|
||||
|
||||
`dline()` draws a straight line from (x1, y1) to (x2, y2). The shortcut functions `dhline()` and `dvline()` draw a full horizontal and vertical line across the screen respectively.
|
||||
|
||||
`dcircle()` draws a circle defined by its center and radius using the Bresenham algorithm. The colors for the circle's interior and its edge can be specified separately, including as `C_NONE` (transparent). By construction, `dcircle()` can only draw circles of odd diameter; for even diameters, use `dellipse()`.
|
||||
|
||||
`dellipse()` draws an ellipse defined by its bounding box. Both (x1, y1) and (x2, y2) are included in the bounding box. To render an ellipse from its center coordinates (x,y) and semi-major/minor axes a/b, use `dellipse(x-a, y-b, x+a, y+b, fill_color, border_color)`.
|
||||
|
||||
_Exemple ([`ex_draw2.py`](../../ports/sh/examples/ex_draw2.py))._
|
||||
|
||||
![](images/modgint-draw2-cg.png) ![](images/modgint-draw2-fx.png)
|
||||
|
||||
_Example ([`ex_circle.py`](../../ports/sh/examples/ex_circle.py))._
|
||||
|
||||
![](images/modgint-circle-cg.png) ![](images/modgint-circle-fx.png)
|
||||
|
||||
### Image rendering functions
|
||||
|
||||
```py
|
||||
dimage(x: int, y: int, img: image) -> None
|
||||
dsubimage(x: int, y: int, img: image, left: int, top: int, width: int, height: int) -> None
|
||||
```
|
||||
|
||||
**On black-and-white models**
|
||||
|
||||
```py
|
||||
image:
|
||||
.profile -> IMAGE_MONO | ...
|
||||
.width -> int
|
||||
.height -> int
|
||||
.data -> buffer-like
|
||||
|
||||
# Constructor
|
||||
image(profile: IMAGE_*, width: int, height: int, data: buffer-like) -> image
|
||||
```
|
||||
|
||||
Images on black-and-white models have either 2 or 4 colors (when the gray engine is enabled). Each image has a `.profile` field indicating the image format (the name "profile" comes from old gint versions), two fields `.width` and `.height` specifying its size, and a `.data` field providing direct access to pixel data.
|
||||
|
||||
The table below lists the four available formats.
|
||||
|
||||
| Format | Colors | Layers | Name in fxconv |
|
||||
|--------------------|---------------------------------|--------|----------------|
|
||||
| `IMAGE_MONO` | Black/white (2) | 1 | `mono` |
|
||||
| `IMAGE_MONO_ALPHA` | Black/white, transparent (3) | 2 | `mono_alpha` |
|
||||
| `IMAGE_GRAY` | Shades of gray (4) | 2 | `gray` |
|
||||
| `IMAGE_GRAY_ALPHA` | Shades of gray, transparent (5) | 3 | `gray_alpha` |
|
||||
|
||||
The raw storage format for data is a bit complicated. The image is stored in row-major order; each line is represented left-to-right by a series of words each covering 32 pixels. Each word contains one bit per pixel (as a 4-byte integer) for each layer.
|
||||
|
||||
The easiest way to obtain an image is to generate the associated code with the fxconv tool from the [fxSDK](https://gitea.planet-casio.com/Lephenixnoir/fxsdk). The options `--bopti-image-fx --fx` specify a conversion for black-and-white models and the metadata `profile:mono` selects the encoding. The table above lists the value of `profile:` to use for each desired format. For instance for [`fx_image_7seg.py`](../../ports/sh/examples/fx_image_7seg.png) :
|
||||
|
||||
![](../../ports/sh/examples/fx_image_7seg.png)
|
||||
|
||||
```bash
|
||||
% fxconv --bopti-image fx_image_7seg.png -o 7seg.py --fx profile:mono name:seg --py
|
||||
```
|
||||
```py
|
||||
import gint
|
||||
seg = gint.image(0, 79, 12, b'|\x00||\x00|||||\x00\x00\xba\x02::\x82\xb8\xb8:\xba\xba\x00\x00\xc6\x06\x06\x06\xc6\xc0\xc0\x06\xc6\xc6\x00\x00\xc6\x06\x06\x06\xc6\xc0\xc0\x06\xc6\xc6\x00\x00\x82\x02\x02\x02\x82\x80\x80\x02\x82\x82\x00\x00\x00\x00|||||\x00||\x00\x00\x82\x02\xb8:::\xba\x02\xba:\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xba\x02\xb8:\x02:\xba\x02\xba:\x00\x00|\x00||\x00||\x00||\x00\x00')
|
||||
```
|
||||
The option `--py-compact` generates much shorter code (less `\x`), however the resulting file can generally not be read or modified by a text editor. The only easy option to use that file is to send it to the calculator and import it as-is. (It can also by manipulated by a program if needed.)
|
||||
|
||||
`dimage()` renders an image, positioned so that the top-left corner of the image is located at (x, y).
|
||||
|
||||
`dsubimage()` renders a sub-rectangle of an image. The rectangle starts at position (left, top) within the image and is of size `width` by `height`. It is positioned so that the (left, top) pixel is drawn at (x, y) on the screen.
|
||||
|
||||
_Example ([`fx_image.py`](../../ports/sh/examples/fx_image.py))._
|
||||
|
||||
![](images/modgint-image-fx.png)
|
||||
|
||||
**On color models**
|
||||
|
||||
```py
|
||||
image:
|
||||
.format -> IMAGE_RGB565 | ...
|
||||
.flags -> int
|
||||
.color_count -> int
|
||||
.width -> int
|
||||
.height -> int
|
||||
.stride -> int
|
||||
.data -> buffer-like
|
||||
.palette -> buffer-like
|
||||
|
||||
# Constructor
|
||||
image(format: IMAGE_*, color_count: int, width: int, height: int, stride: int, data: buffer-like, palette: buffer-like) -> image
|
||||
|
||||
# Format-specific constructors
|
||||
image_rgb565(width: int, height: int, data: buffer-like) -> image
|
||||
image_rgb565a(width: int, height: int, data: buffer-like) -> image
|
||||
image_p8_rgb565(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p8_rgb565a(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p4_rgb565(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p4_rgb565a(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
```
|
||||
|
||||
Images on color models are available in multiple formats as indicated by the `.format` field; the possible values are listed below. Formats differ in the number of colors, the presence of a transparent color, and the presence of a palette. Of course, the less colors the smaller the memory footprint of the image, so in general it is very beneficial to use the smallest format in which an image fits.
|
||||
|
||||
| Format | Colors | Palette | Name in fxconv |
|
||||
|--------------------|---------------------|-------------|----------------|
|
||||
| `IMAGE_RGB565` | 65536 | No | `rgb565` |
|
||||
| `IMAGE_RGB565A` | 65535 + transparent | No | `rgb565a` |
|
||||
| `IMAGE_P8_RGB565` | 256 | Yes (1-256) | `p8_rgb565` |
|
||||
| `IMAGE_P8_RGB565A` | 255 + transparent | Yes (1-256) | `p8_rgb565a` |
|
||||
| `IMAGE_P4_RGB565` | 16 | Yes (16) | `p4_rgb565` |
|
||||
| `IMAGE_P4_RGB565A` | 15 + transparent | Yes (16) | `p4_rgb565a` |
|
||||
|
||||
The `.color_count` field indicates the number of colors in the palette, when there is one. For P8 formats this number varies between 1 and 256, and for P4 formats it is always equal to 16. The `.width` and `.height` fields indicate the image's size. Finally, the `.data` and `.palette` fields provide direct access to the raw data for the image's pixels and color palette.
|
||||
|
||||
(The `.flags` field has details of memory management that shouldn't be important to Python scripts. The `.stride` fields indicates the distance in bytes between rows of pixels in `.data` and should similarly be of rare use.)
|
||||
|
||||
The functions `dimage()` and `dsubimage()` work the same way as for black-and-white models; please see above.
|
||||
|
||||
As for black-and-white models, images can be converted into a Python format with fxconv. For instance with [`cg_image_puzzle.png`](../../ports/sh/examples/cg_image_puzzle.png) (full encoding elided):
|
||||
|
||||
![](../../ports/sh/examples/cg_image_puzzle.png)
|
||||
|
||||
```bash
|
||||
% fxconv --bopti-image cg_image_puzzle.png -o puzzle.py --cg profile:p4_rgb565 name:puzzle --py
|
||||
```
|
||||
```py
|
||||
import gint
|
||||
puzzle = gint.image(6, 16, 64, 32, 32,
|
||||
b'\xbb\xbb\xbb\xbb\xbb ... \xdd\xdd\xdd\xdd\xdd\xdd\xdd',
|
||||
b'\xff\xff\xcfW\x86\xd8\xbe|\xceP\xe5\x8a\x963f9u\x9c}\xa8\x9dxD\xfa\x83\xceLNZ\xcci\xa7')
|
||||
```
|
||||
The option `--py-compact` is recommended to reduce code size; please see details in the black-and-white section above.
|
||||
|
||||
_Exemple ([`cg_image.py`](../../ports/sh/examples/cg_image.py))._
|
||||
|
||||
![](images/modgint-image-cg.png)
|
||||
|
||||
## Differences with gint's C API
|
||||
|
||||
- `dsubimage()` doesn't have its final parameter `int flags`. The flags are only minor optimizations and could be removed in future gint versions.
|
||||
- Image constructors`image()` and `image_<format>()` don't exist in the C API.
|
||||
- Asynchronous volatile-flag-based timeouts are replaced with synchronous millisecond delays (integer value or `None`).
|
||||
|
||||
TODO: There are more.
|
|
@ -0,0 +1,434 @@
|
|||
# `gint`: Module d'accès aux fonctionnalités de gint
|
||||
|
||||
PythonExtra est écrit à l'aide du [fxSDK](https://gitea.planet-casio.com/Lephenixnoir/fxsdk) et utilise [gint](https://gitea.planet-casio.com/Lephenixnoir/gint) pour exécuter l'add-in. Le module Python `gint` permet d'accéder aux fonctions internes de gint en Python pour le dessin, le clavier, etc. Comme gint possède beaucoup de fonctions utiles avec de bonnes performances, il est intéressant de s'en servir au lieu d'utiliser e.g. `casioplot` ou `turtle`.
|
||||
|
||||
Le module `gint` essaie de garder en Python la même API que dans la version originale de la bibliothèque en C, c'est pourquoi peu de fonctions utilisent des arguments nommés ou autres fonctions surchargées. Il y a quelques différences, documentées à la fin de cette page. En cas de doute, la documentation fournie par les [fichiers d'en-tête de gint](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint) (les `.h`) est tout à fait applicable pour comprendre les comportements que cette page n'explique pas.
|
||||
|
||||
Tous les noms de constantes, fonctions, etc. discutés dans cet article sont dans le module `gint`.
|
||||
|
||||
```py
|
||||
import gint
|
||||
# ou:
|
||||
from gint import *
|
||||
```
|
||||
|
||||
**Sommaire**
|
||||
- [Saisie au clavier](#saisie-au-clavier)
|
||||
- [Dessin à l'écran](#dessin-à-lécran)
|
||||
- [Différences avec l'API C de gint](#différences-avec-lapi-c-de-gint)
|
||||
|
||||
## Saisie au clavier
|
||||
|
||||
Les en-têtes de référence sont [`<gint/keyboard.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/keyboard.h) et [`<gint/keycodes.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/keycodes.h).
|
||||
|
||||
### Noms des touches
|
||||
|
||||
Le module fournit des constantes entières désignant toutes les touches du clavier. Les noms sont les suivants :
|
||||
|
||||
| | | | | | |
|
||||
|------------|------------|------------|------------|------------|-------------|
|
||||
|`KEY_F1` |`KEY_F2` |`KEY_F3` |`KEY_F4` |`KEY_F5` |`KEY_F6` |
|
||||
|`KEY_SHIFT` |`KEY_OPTN` |`KEY_VARS` |`KEY_MENU` |`KEY_LEFT` |`KEY_UP` |
|
||||
|`KEY_ALPHA` |`KEY_SQUARE`|`KEY_POWER` |`KEY_EXIT` |`KEY_DOWN` |`KEY_RIGHT` |
|
||||
|`KEY_XOT` |`KEY_LOG` |`KEY_LN` |`KEY_SIN` |`KEY_COS` |`KEY_TAN` |
|
||||
|`KEY_FRAC` |`KEY_FD` |`KEY_LEFTP` |`KEY_RIGHTP`|`KEY_COMMA` |`KEY_ARROW` |
|
||||
|`KEY_7` |`KEY_8` |`KEY_9` |`KEY_DEL` |`KEY_ACON` | |
|
||||
|`KEY_4` |`KEY_5` |`KEY_6` |`KEY_MUL` |`KEY_DIV` | |
|
||||
|`KEY_1` |`KEY_2` |`KEY_3` |`KEY_ADD` |`KEY_SUB` | |
|
||||
|`KEY_0` |`KEY_DOT` |`KEY_EXP` |`KEY_NEG` |`KEY_EXE` | |
|
||||
|
||||
### Événements clavier
|
||||
|
||||
```
|
||||
key_event:
|
||||
.time -> int
|
||||
.mod -> bool
|
||||
.shift -> bool
|
||||
.alpha -> bool
|
||||
.type -> KEYEV_NONE | KEYEV_DOWN | KEYEV_UP | KEYEV_HOLD
|
||||
.key -> KEY_*
|
||||
```
|
||||
|
||||
gint communique les informations sur ce qu'il se passe au clavier via des _événements_. Les événements indiquent quand une touche (champ `.key`) a été pressée, maintenue, ou relâchée (champ `.type` égal à `KEYEV_DOWN`, `KEYEV_HOLD` et `KEYEV_UP` respectivement), quand (champ `.time`) et si des modifieurs (SHIFT ou ALPHA, champs `.shift` et `.alpha`) étaient actifs à ce moment-là.
|
||||
|
||||
(Le champ `.mod` n'est pas très intéressant, et la valeur `KEYEV_NONE` de `.type` est discutée dans `pollevent()`.)
|
||||
|
||||
Les fonctions `getkey()`, `getekey_opt()`, `pollevent()` et `waitevent()` renvoient toutes des événements.
|
||||
|
||||
### Saisie d'une touche avec attente
|
||||
|
||||
```py
|
||||
getkey() -> key_event
|
||||
getkey_opt(opts: GETKEY_*, timeout_ms: int | None) -> key_event
|
||||
```
|
||||
|
||||
La fonction `getkey()` met le programme en pause jusqu'à ce qu'une touche soit pressée ou répétée, et renvoie l'événement associé (qui est forcément de type `KEYEV_DOWN` ou `KEYEV_HOLD`). Par défaut, les seules touches qui sont répétées sont les touches directionnelles, une première fois après 400 ms, et ensuite toutes les 40 ms.
|
||||
|
||||
Pas mal de choses peuvent se produire pendant l'exécution de `getkey()`. L'utilisateur peut appuyer sur SHIFT ou ALPHA, ce qui affecte les champs `.shift` et `.alpha` de l'événement renvoyé. L'utilisateur peut également se rendre au menu principal avec MENU et éteindre la calculatrice avec SHIFT+AC/ON.
|
||||
|
||||
_Exemple._ Dans un menu de sélection de N éléments, on pourrait naviguer avec les touches haut et bas, sauter directement au début ou à la fin avec SHIFT haut et SHIFT bas, et valider avec EXE.
|
||||
|
||||
```py
|
||||
ev = getkey()
|
||||
if ev.key == KEY_EXE:
|
||||
pass # Valider
|
||||
elif ev.key == KEY_UP and ev.shift:
|
||||
pos = 0 # Revenir au début
|
||||
elif ev.key == KEY_DOWN and ev.shift:
|
||||
pos = N-1 # Aller à la fin
|
||||
elif ev.key == KEY_UP and pos > 0:
|
||||
pos -= 1 # Monter d'une position
|
||||
elif ev.key == KEY_DOWN and pos < N-1:
|
||||
pos += 1 # Descendre d'une position
|
||||
```
|
||||
|
||||
La fonction `getkey_opt()` est une généralisation de `getkey()` qui donne accès à plus d'options pour personnaliser le comportement de la fonction. Le paramètre `opts` accepte une combinaison d'options dans le tableau ci-dessous, et le paramètre `timeout_ms`, quand il n'est pas `None`, spécifie au bout de combien de temps la fonction doit s'arrêter et renvoyer un événement de type `KEYEV_NONE` s'il n'y a aucune activité sur le clavier. Le délai est exprimé en millisecondes mais la précision réelle est de l'ordre de 7-8 ms.
|
||||
|
||||
| Option | `getkey()` | Description |
|
||||
|------------------------|------------|------------------------------------------------------------|
|
||||
| `GETKEY_MOD_SHIFT` | Oui | La touche SHIFT est un modifieur |
|
||||
| `GETKEY_MOD_ALPHA` | Oui | La touche ALPHA est un modifieur |
|
||||
| `GETKEY_BACKLIGHT` | Oui | SHIFT+OPTN allume/éteint le rétroéclairage |
|
||||
| `GETKEY_MENU` | Oui | MENU retourne au menu principal de la calculatrice |
|
||||
| `GETKEY_REP_ARROWS` | Oui | Répète les touches directionnelles si maintenues |
|
||||
| `GETKEY_REP_ALL` | Non | Répète toutes les touches si maintenues |
|
||||
| `GETKEY_REP_PROFILE` | Oui* | Personnalisation des durées de répétition |
|
||||
| `GETKEY_FEATURES` | Oui* | Personnalisation des raccourcis claviers globaux |
|
||||
| `GETKEY_MENU_DUPDATE` | Oui | Rafraîchit l'écran après un retour au menu (Prizm/G90) |
|
||||
| `GETKEY_MENU_EVENT` | Non | Envoie un événement `KEYEV_OSMENU` après un retour au menu |
|
||||
| `GETKEY_POWEROFF` | Oui | SHIFT+AC/ON éteint la calculatrice |
|
||||
|
||||
`getkey()` est équivalent à `getkey_opt(opts, None)` où `opts` est la somme de toutes les options marquées "Oui" dans la colonne `getkey()` ci-dessus.
|
||||
|
||||
Les deux options `GETKEY_REP_PROFILE` et `GETKEY_FEATURES` ne sont utiles qu'au travers de fonctions de configuration qui ne sont pour l'instant pas disponibles dans PythonExtra.
|
||||
|
||||
### Lecture des événements en temps réel
|
||||
|
||||
```py
|
||||
pollevent() -> key_event
|
||||
waitevent() -> key_event
|
||||
clearevents() -> None
|
||||
```
|
||||
|
||||
gint enregistre l'activité du clavier en tâche de fond pendant que le programme s'exécute. Les événements sont mis dans une file d'attente jusqu'à ce que le programme les lise. C'est comme ça par exemple que `getkey()` détermine quoi renvoyer.
|
||||
|
||||
Il est possible d'accéder aux événements directement à l'aide de la fonction `pollevent()`. `pollevent()` renvoie l'événement le plus ancien qui n'a pas encore été lu par le programme. Si le programme a lu tous les événements et qu'il n'y a plus rien en attente, `pollevent()` renvoie un "faux" évenement de type `KEYEV_NONE` pour indiquer qu'il n'y a plus rien à lire.
|
||||
|
||||
Comme `pollevent()` retourne instanténement, on peut s'en servir pour lire l'activité du clavier sans mettre le programme en pause.
|
||||
|
||||
_Exemple._ Une boucle de jeu pourrait, à chaque frame, lire tous les événements en attente pour déterminer quand le joueur appuie sur la touche SHIFT ("action" dans cet exemple) pour déclencher une action.
|
||||
|
||||
```py
|
||||
# Dessiner le jeu...
|
||||
|
||||
while True:
|
||||
ev = pollevent()
|
||||
if ev.type == KEYEV_NONE:
|
||||
break # Fin de la lecture des événements
|
||||
if ev.type == KEYEV_DOWN and ev.key == KEY_SHIFT:
|
||||
pass # La touche SHIFT vient d'être pressée !
|
||||
# Ignore implicitement les autres touches
|
||||
|
||||
# Simuler le jeu...
|
||||
```
|
||||
|
||||
La fonction `waitevent()` est similaire, mais si tous les événements ont été lus elle attend qu'un événement se produise avant de retourner. Elle est plus rarement utilisée parce qu'en général quand on veut attendre on utilise `getkey()`.
|
||||
|
||||
La fonction `clearevents()` lit et ignore tous les événements, i.e. elle "jette" toutes les informations sur ce qu'il s'est passé au clavier. Elle est utile pour connaître l'état instantané du clavier avec `keydown()` (voir ci-dessous). `clearevents()` est équivalente à la définition suivante :
|
||||
|
||||
```py
|
||||
def clearevents():
|
||||
ev = pollevent()
|
||||
while ev.type != KEYEV_NONE:
|
||||
ev = pollevent()
|
||||
```
|
||||
|
||||
### Lecture de l'état instantané du clavier
|
||||
|
||||
```py
|
||||
keydown(key: int) -> bool
|
||||
keydown_all(*keys: [int]) -> bool
|
||||
keydown_any(*keys: [int]) -> bool
|
||||
```
|
||||
|
||||
Une fois les événements lus, on peut tester individuellement si les touches sont pressées ou pas à l'aide de la fonction `keydown()`. `keydown(k)` renvoie `True` si la touche `k` est pressée, `False` sinon. Cette fonction ne marche **que si les événements ont été lus**, ce qu'on fait souvent soit avec `pollevent()` soit avec `clearevents()`.
|
||||
|
||||
_Exemple._ Une boucle de jeu pourrait tester si les touches gauche/droite sont pressées à chaque frame pour déplacer le joueur.
|
||||
|
||||
```py
|
||||
while True:
|
||||
ev = pollevent()
|
||||
# ... comme dans l'exemple pollevent()
|
||||
|
||||
if keydown(KEY_LEFT):
|
||||
player_x -= 1
|
||||
if keydown(KEY_RIGHT):
|
||||
player_x += 1
|
||||
```
|
||||
|
||||
La fonction `keydown_all()` prent une série de touches en paramètre et renvoie `True` si elles sout toutes pressées. `keydown_any()` est similaire et renvoie `True` si au moins une des touches listées est pressée.
|
||||
|
||||
### Lecture rapide des changements de position des touches
|
||||
|
||||
```py
|
||||
cleareventflips() -> None
|
||||
keypressed(key: int) -> bool
|
||||
keyreleased(key: int) -> bool
|
||||
```
|
||||
|
||||
`keydown()` indique uniquement l'état instantané des touches. Elle ne permet pas de déterminer à quel moment une touche passe de l'état relâché à l'état pressé ou l'inverse. Pour ça, il faut soit utiliser les événements (ce qui est un peu lourd), soit se souvenir de quelles touches étaient pressées à "l'instant" précédent, soit utiliser les fonctions ci-dessous.
|
||||
|
||||
Les fonctions `keypressed(k)` et `keyreleased(k)` indiquent si la touche a été pressée/relâchée depuis le dernier appel à `cleareventflips()`. Attention la notion de "pressée/relâchée" ici n'est pas le temps réel mais la lecture des événements.
|
||||
|
||||
_Exemple._ Une boucle de jeu peut tester à la fois l'état immédiat et les changements d'état des touches en utilisant les fonctions instantanée après `cleareventflips()` suivi de `clearevents()`.
|
||||
|
||||
```py
|
||||
# Dessiner le jeu...
|
||||
|
||||
cleareventflips()
|
||||
clearevents()
|
||||
|
||||
if keypressed(KEY_SHIFT):
|
||||
pass # Action !
|
||||
if keydown(KEY_LEFT):
|
||||
player_x -= 1
|
||||
if keydown(KEY_RIGHT):
|
||||
player_x += 1
|
||||
|
||||
# Simuler le jeu...
|
||||
```
|
||||
|
||||
### Fonctions diverses concernant le clavier
|
||||
|
||||
```py
|
||||
keycode_function(key: int) -> int
|
||||
keycode_digit(key: int) -> int
|
||||
```
|
||||
|
||||
`keycode_function(k)` renvoie le numéro de F-touche de `k` (i.e. 1 pour `KEY_F1`, 2 pour `KEY_F2`, etc.) et -1 pour les autres touches.
|
||||
|
||||
`keycode_digit(k)` renvoie le chiffre associé à `k` (i.e. 0 pour `KEY_0`, 1 pour `KEY_1`, etc.) et -1 pour les autres touches.
|
||||
|
||||
## Dessin à l'écran
|
||||
|
||||
Les en-têtes de référence sont [`<gint/display.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display.h), et pour certains détails techniques [`<gint/display-fx.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display-fx.h) et [`<gint/display-cg.h>`](https://gitea.planet-casio.com/Lephenixnoir/gint/src/branch/master/include/gint/display-cg.h).
|
||||
|
||||
### Manipulation de couleurs
|
||||
|
||||
```py
|
||||
C_WHITE: int # Blanc
|
||||
C_BLACK: int # Noir
|
||||
C_LIGHT: int # Gris clair (sur mono: moteur de gris)
|
||||
C_DARK: int # Gris foncé (sur mono: moteur de gris)
|
||||
C_NONE: int # Transparent
|
||||
C_INVERT: int # Inverseur de couleur
|
||||
|
||||
# Graph mono uniquement :
|
||||
C_LIGHTEN: int # Éclaircisseur de couleur (moteur de gris)
|
||||
C_DARKEN: int # Assombrisseur de couleur (moteur de gris)
|
||||
|
||||
# Graph 90+E uniquement :
|
||||
C_RED: int # Rouge pur
|
||||
C_GREEN: int # Vert pur
|
||||
C_BLUE: int # Bleu pur
|
||||
C_RGB(r: int, g: int, b: int) -> int
|
||||
```
|
||||
|
||||
Les couleurs sont toutes des nombres entiers (manipuler des tuples `(r,g,b)` est atrocement lent par comparaison et requiert des allocations mémoire dans tous les sens). Une poignée de couleurs est fournie par défaut.
|
||||
|
||||
Sur Graph 90+E, la fonction `C_RGB()` peut être utilisée pour créer des couleurs à partir de trois composantes de valeur 0 à 31.
|
||||
|
||||
TODO: Expliquer le moteur de gris.
|
||||
|
||||
### Fonctions de dessin basiques
|
||||
|
||||
```py
|
||||
DWIDTH: int
|
||||
DHEIGHT: int
|
||||
dupdate() -> None
|
||||
dclear(color: int) -> None
|
||||
dpixel(x: int, y: int, color: int) -> None
|
||||
dgetpixel(x: int, y: int) -> int
|
||||
```
|
||||
|
||||
Les entiers `DWIDTH` et `DHEIGHT` indiquent la taille de l'écran. C'est 128x64 sur les Graph mono (type Graph 35+E II), 396x224 sur la Prizm et Graph 90+E (le plein écran est disponible).
|
||||
|
||||
Toutes les fonctions de dessin opèrent sur une image interne appellée "VRAM" ; l'effet du dessin n'est donc pas visible immédiatement à l'écran. Pour que le dessin se voie il faut appeler la fonction `dupdate()` qui transfère les contenus de la VRAM à l'écran réel. Généralement, on fait ça après avoir affiché tout ce dont on a besoin et pas après chaque appel de fonction de dessin.
|
||||
|
||||
Dans PythonExtra, la fonction `dupdate()` indique aussi implicitement qu'on « passe en mode graphique ». À cause de certaines optimisations tout appel à `print()` est considéré comme un « passage en mode texte » et pendant qu'on est en mode texte le shell peut redessiner à tout moment. Si on veut dessiner après avoir utilisé le mode texte, il faut appeler `dupdate()` pour forcer un passage en mode graphique avant de commencer à dessiner. Sinon le dessin du shell pourrait interférer avec le dessin du programme.
|
||||
|
||||
La fonction `dclear()` remplit l'écran d'une couleur unie.
|
||||
|
||||
La fonction `dpixel()` modifie la couleur d'un pixel. Les coordonnées, comme pour toutes les fonctions de dessin, sont (x,y) où `x` varie entre 0 et DWIDTH-1 inclus (0 étant à gauche), et `y` varie entre 0 et DHEIGHT-1 inclus (0 étant en haut).
|
||||
|
||||
La fonction `dgetpixel()` renvoie la couleur d'un pixel. Attention, `dgetpixel()` lit dans la VRAM, pas sur l'écran.
|
||||
|
||||
_Exemple ([`ex_draw1.py`](../../ports/sh/examples/ex_draw1.py))._
|
||||
|
||||
```py
|
||||
from gint import *
|
||||
dclear(C_WHITE)
|
||||
for y in range(10):
|
||||
for x in range(10):
|
||||
if (x^y) & 1:
|
||||
dpixel(x, y, C_BLACK)
|
||||
dupdate()
|
||||
```
|
||||
|
||||
![](images/modgint-draw1-cg.png) ![](images/modgint-draw1-fx.png)
|
||||
|
||||
### Fonctions de dessin de formes géométriques
|
||||
|
||||
```py
|
||||
drect(x1: int, y1: int, x2: int, y2: int, color: int) -> None
|
||||
drect_border(x1: int, y1: int, x2: int, y2: int, fill_color: int,
|
||||
border_width: int, border_color: int) -> None
|
||||
dline(x1: int, y1: int, x2: int, y2: int, color: int) -> None
|
||||
dhline(y: int, color: int) -> None
|
||||
dvline(x: int, color: int) -> None
|
||||
dcircle(x: int, y: int, radius: int, fill_color: int,
|
||||
border_color: int) -> None
|
||||
dellipse(x1: int, y1: int, x2: int, y2: int, fill_color: int,
|
||||
border_color: int) -> None
|
||||
```
|
||||
|
||||
`drect()` dessine un rectangle plein allant de (x1, y1) à (x2, y2) (tous les deux inclus). L'ordre des points ne compte pas, i.e. x1 ≥ x2 ou y1 ≥ y2 est autorisé.
|
||||
|
||||
`drect_border()` est similaire mais dessine une bordure de largeur `border_width` et de couleur `border_color`. La bordure est dessinée _à l'intérieur_ du rectangle.
|
||||
|
||||
`dline()` dessine une ligne droite entre les points (x1, y1) et (x2, y2). Les raccourcis `dhline()` et `dvline()` dessinent respectivement une ligne horizontale et verticale à travers tout l'écran.
|
||||
|
||||
`dcircle()` dessine un cercle défini par son centre et rayon avec l'algorithme de Bresenham. La couleur de l'intérieur et du bord peuvent être spécifiées séparément, y compris avec `C_NONE` (transparente). Par construction, `dcircle()` ne peut construire que des cercles de diamètre impair ; pour les diamètres plus fin, utilisez `dellipse()`.
|
||||
|
||||
`dellipse()` dessine une ellipse définie par son rectangle englobant. Les points (x1, y1) et (x2, y2) sont tous les deux inclus dans le rectangle. Pour dessiner une ellipse à partir de son centre (x, y) et de ses demi-grand/petit axes a/b, utilisez `dellipse(x-a, y-b, x+a, y+b, fill_color, border_color)`.
|
||||
|
||||
_Exemple ([`ex_draw2.py`](../../ports/sh/examples/ex_draw2.py))._
|
||||
|
||||
![](images/modgint-draw2-cg.png) ![](images/modgint-draw2-fx.png)
|
||||
|
||||
_Exemple ([`ex_circle.py`](../../ports/sh/examples/ex_circle.py))._
|
||||
|
||||
![](images/modgint-circle-cg.png) ![](images/modgint-circle-fx.png)
|
||||
|
||||
### Fonctions de dessin d'images
|
||||
|
||||
```py
|
||||
dimage(x: int, y: int, img: image) -> None
|
||||
dsubimage(x: int, y: int, img: image, left: int, top: int, width: int, height: int) -> None
|
||||
```
|
||||
|
||||
**Sur Graph mono**
|
||||
|
||||
```py
|
||||
image:
|
||||
.profile -> IMAGE_MONO | ...
|
||||
.width -> int
|
||||
.height -> int
|
||||
.data -> buffer-like
|
||||
|
||||
# Constructeur
|
||||
image(profile: IMAGE_*, width: int, height: int, data: buffer-like) -> image
|
||||
```
|
||||
|
||||
Les images sur Graph mono sont en noir-et-blanc ou 4 couleurs (quand le moteur de gris est utilisé). Chaque image a un champ `.profile` indiquant le format d'image (le nom "profile" est hérité d'anciennes versions de gint), deux champs `.width` et `.height` indiquant sa taille, et un champ `.data` donnant accès aux données brutes.
|
||||
|
||||
Les quatre formats disponibles sont les suivants.
|
||||
|
||||
| Format | Couleurs | Calques | Nom dans fxconv |
|
||||
|--------------------|----------------------------------|---------|-----------------|
|
||||
| `IMAGE_MONO` | Noir/blanc (2) | 1 | `mono` |
|
||||
| `IMAGE_MONO_ALPHA` | Noir/blanc, transparent (3) | 2 | `mono_alpha` |
|
||||
| `IMAGE_GRAY` | Niveaux de gris (4) | 2 | `gray` |
|
||||
| `IMAGE_GRAY_ALPHA` | Niveaux de gris, transparent (5) | 3 | `gray_alpha` |
|
||||
|
||||
Le format des données brutes est un peu compliqué. L'image est stockée ligne par ligne de haut en bas ; chaque ligne est représentée de gauche à droite par une série de mots représentant chacun 32 pixels. Chaque mot contient un bit par pixel (sous la forme d'un entier de 4 octets) pour chaque calque.
|
||||
|
||||
Le plus simple pour obtenir une image est de générer le code associé avec l'outil fxconv du [fxSDK](https://gitea.planet-casio.com/Lephenixnoir/fxsdk). Les options `--bopti-image-fx --fx` spécifient qu'on convertit une image pour Graph mono et la métadonnée `profile:mono` choisit le format de l'image produite. Le tableau ci-dessus liste la valeur de `profile:` à spécifier pour chaque format. Par exemple pour l'image [`fx_image_7seg.py`](../../ports/sh/examples/fx_image_7seg.png) :
|
||||
|
||||
![](../../ports/sh/examples/fx_image_7seg.png)
|
||||
|
||||
```bash
|
||||
% fxconv --bopti-image fx_image_7seg.png -o 7seg.py --fx profile:mono name:seg --py
|
||||
```
|
||||
```py
|
||||
import gint
|
||||
seg = gint.image(0, 79, 12, b'|\x00||\x00|||||\x00\x00\xba\x02::\x82\xb8\xb8:\xba\xba\x00\x00\xc6\x06\x06\x06\xc6\xc0\xc0\x06\xc6\xc6\x00\x00\xc6\x06\x06\x06\xc6\xc0\xc0\x06\xc6\xc6\x00\x00\x82\x02\x02\x02\x82\x80\x80\x02\x82\x82\x00\x00\x00\x00|||||\x00||\x00\x00\x82\x02\xb8:::\xba\x02\xba:\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xc6\x06\xc0\x06\x06\x06\xc6\x06\xc6\x06\x00\x00\xba\x02\xb8:\x02:\xba\x02\xba:\x00\x00|\x00||\x00||\x00||\x00\x00')
|
||||
```
|
||||
L'option `--py-compact` permet de générer du code beaucoup plus compact (avec moins de `\x`), par contre le fichier obtenu ne peut pas être lu par un éditeur de texte. La seule option simple pour l'utiliser est de l'envoyer sur la calculatrice et l'importer tel quel (on peut aussi le manipuler avec un programme).
|
||||
|
||||
La fonction `dimage()` dessine une image à l'écran en positionnant le coin haut gauche de l'image à la position (x, y).
|
||||
|
||||
La fonction `dsubimage()` permet de dessiner un sous-rectangle d'une image. Le sous-rectangle commence à la position (left, top) de l'image et s'étend sur une largeur `width` et une hauteur `height`. Le sous-rectangle est dessiné de façon à ce que le pixel (left, top) arrive à la position (x, y) de l'écran.
|
||||
|
||||
_Exemple ([`fx_image.py`](../../ports/sh/examples/fx_image.py))._
|
||||
|
||||
![](images/modgint-image-fx.png)
|
||||
|
||||
**Sur Graph couleur**
|
||||
|
||||
```py
|
||||
image:
|
||||
.format -> IMAGE_RGB565 | ...
|
||||
.flags -> int
|
||||
.color_count -> int
|
||||
.width -> int
|
||||
.height -> int
|
||||
.stride -> int
|
||||
.data -> buffer-like
|
||||
.palette -> buffer-like
|
||||
|
||||
# Constructeur
|
||||
image(format: IMAGE_*, color_count: int, width: int, height: int, stride: int, data: buffer-like, palette: buffer-like) -> image
|
||||
|
||||
# Constructeurs spécialisés par format
|
||||
image_rgb565(width: int, height: int, data: buffer-like) -> image
|
||||
image_rgb565a(width: int, height: int, data: buffer-like) -> image
|
||||
image_p8_rgb565(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p8_rgb565a(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p4_rgb565(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
image_p4_rgb565a(width: int, height: int, data: buffer-like, palette: buffer-like) -> image
|
||||
```
|
||||
|
||||
Les images sur Graph couleur sont déclinées en différents formats indiqués par le champ `.format`, dont les valeurs possibles sont listées ci-dessous. Les différences sont dans le nombre de couleurs, la présence ou pas de transparence, et la présence ou pas d'une palette de couleurs. Bien sûr, moins il y a de couleurs moins l'image prend de place en mémoire, donc de façon générale il est très bénéfique d'utiliser le plus petit format possible pour chaque image.
|
||||
|
||||
| Format | Couleurs | Palette | Nom dans fxconv |
|
||||
|--------------------|---------------------|-------------|-----------------|
|
||||
| `IMAGE_RGB565` | 65536 | Non | `rgb565` |
|
||||
| `IMAGE_RGB565A` | 65535 + transparent | Non | `rgb565a` |
|
||||
| `IMAGE_P8_RGB565` | 256 | Oui (1-256) | `p8_rgb565` |
|
||||
| `IMAGE_P8_RGB565A` | 255 + transparent | Oui (1-256) | `p8_rgb565a` |
|
||||
| `IMAGE_P4_RGB565` | 16 | Oui (16) | `p4_rgb565` |
|
||||
| `IMAGE_P4_RGB565A` | 15 + transparent | Oui (16) | `p4_rgb565a` |
|
||||
|
||||
Le champ `.color_count` indique le nombre de couleurs dans la palette quand il y en a une. Pour les formats P8 ce nombre varie entre 1 et 256, pour les formats P4 il est toujours égal à 16. Les deux champs `.width` et `.height` indiquent la taille de l'image. Enfin, les champs `.data` et `.palette` permettent d'accéder aux données brutes des pixels ainsi que de la palette.
|
||||
|
||||
(Le champ `.flags` est un détail de gestion de mémoire qui ne devrait pas importer aux scripts Python. Le champ `.stride` indique combien d'octets séparent chaque ligne de pixels dans `.data` et sera de même rarement utilisé.)
|
||||
|
||||
Les fonctions `dimage()` et `dsubimage()` ont le même fonctionnement que pour les Graph mono ; voir ci-dessus.
|
||||
|
||||
Comme pour Graph mono les images peuvent être converties avec fxconv. Par exemple pour l'image [`cg_image_puzzle.png`](../../ports/sh/examples/cg_image_puzzle.png) (code abrégé) :
|
||||
|
||||
![](../../ports/sh/examples/cg_image_puzzle.png)
|
||||
|
||||
```bash
|
||||
% fxconv --bopti-image cg_image_puzzle.png -o puzzle.py --cg profile:p4_rgb565 name:puzzle --py
|
||||
```
|
||||
```py
|
||||
import gint
|
||||
puzzle = gint.image(6, 16, 64, 32, 32,
|
||||
b'\xbb\xbb\xbb\xbb\xbb ... \xdd\xdd\xdd\xdd\xdd\xdd\xdd',
|
||||
b'\xff\xff\xcfW\x86\xd8\xbe|\xceP\xe5\x8a\x963f9u\x9c}\xa8\x9dxD\xfa\x83\xceLNZ\xcci\xa7')
|
||||
```
|
||||
L'option `--py-compact` est recommandée pour réduire la taille du code ; voir les détails dans la section Graph mono.
|
||||
|
||||
_Exemple ([`cg_image.py`](../../ports/sh/examples/cg_image.py))._
|
||||
|
||||
![](images/modgint-image-cg.png)
|
||||
|
||||
## Différences avec l'API C de gint
|
||||
|
||||
- `dsubimage()` n'a pas de paramètre `int flags`. Les flags en question ne ont que des optimisations mineures et pourraient disparaître dans une version future de gint.
|
||||
- Les constructeurs d'image `image()` et `image_<format>()` n'existent pas dans l'API C.
|
||||
- Les timeouts asynchrones à base d'entiers volatiles sont remplacés par des timeouts synchrones avec des durées optionnelles en millisecondes (entier ou `None`).
|
||||
|
||||
TODO : Il y en a d'autres.
|
|
@ -49,7 +49,7 @@ extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
|||
#include "uart.h"
|
||||
|
||||
// Provided by the port.
|
||||
extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
extern machine_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
|
||||
STATIC void cywbt_wait_cts_low(void) {
|
||||
mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||
|
@ -68,7 +68,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
|||
mp_bluetooth_hci_uart_write((void *)buf, len);
|
||||
for (int c, i = 0; i < 6; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
|||
int sz = buf[2] - 3;
|
||||
for (int c, i = 0; i < sz; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/machine_pulse.h"
|
||||
#include "extmod/modmachine.h"
|
||||
#include "drivers/dht/dht.h"
|
||||
|
||||
// Allow the open-drain-high call to be DHT specific for ports that need it
|
||||
|
|
|
@ -34,9 +34,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "modmachine.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "extmod/modmachine.h"
|
||||
#ifdef MICROPY_HW_WIFI_LED
|
||||
#include "led.h"
|
||||
#endif
|
||||
|
|
|
@ -42,9 +42,13 @@
|
|||
|
||||
#define NINA_GPIO_MODE (0x50)
|
||||
#define NINA_GPIO_READ (0x53)
|
||||
#define NINA_GPIO_READ_ANALOG (0x54)
|
||||
#define NINA_GPIO_WRITE (0x51)
|
||||
#define NINA_GPIO_IS_INPUT_ONLY(p) ((p >= 34 && p <= 36) || (p == 39))
|
||||
#define NINA_GPIO_IS_INPUT_ONLY(p) ((p >= 3 && p <= 6))
|
||||
#define NINA_GPIO_IS_ADC_CHANNEL(p) ((p >= 3 && p <= 6))
|
||||
|
||||
// This maps logical pin ID (0..MICROPY_HW_PIN_EXT_COUNT) to
|
||||
// physical pins on the Nina module.
|
||||
static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
||||
27, // LEDR
|
||||
25, // LEDG
|
||||
|
@ -55,10 +59,30 @@ static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
|||
35, // A7
|
||||
};
|
||||
|
||||
// This maps logical pin ID (0..MICROPY_HW_PIN_EXT_COUNT) to
|
||||
// ADC channel numbers on the Nina module.
|
||||
static uint8_t adc_map[MICROPY_HW_PIN_EXT_COUNT] = {
|
||||
-1, // LEDR
|
||||
-1, // LEDG
|
||||
-1, // LEDB
|
||||
6, // A4
|
||||
3, // A5
|
||||
0, // A6
|
||||
7, // A7
|
||||
};
|
||||
|
||||
void machine_pin_ext_init(void) {
|
||||
nina_init();
|
||||
}
|
||||
|
||||
bool machine_pin_ext_is_adc_channel(const machine_pin_obj_t *self) {
|
||||
return NINA_GPIO_IS_ADC_CHANNEL(self->id);
|
||||
}
|
||||
|
||||
uint32_t machine_pin_ext_to_adc_channel(const machine_pin_obj_t *self) {
|
||||
return adc_map[self->id];
|
||||
}
|
||||
|
||||
void machine_pin_ext_set(machine_pin_obj_t *self, bool value) {
|
||||
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
|
||||
uint8_t buf[] = {pin_map[self->id], value};
|
||||
|
@ -76,8 +100,14 @@ bool machine_pin_ext_get(machine_pin_obj_t *self) {
|
|||
return value;
|
||||
}
|
||||
|
||||
uint16_t machine_pin_ext_read_u16(uint32_t channel) {
|
||||
uint16_t buf = channel;
|
||||
nina_ioctl(NINA_GPIO_READ_ANALOG, sizeof(buf), (uint8_t *)&buf, 0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
|
||||
if (mode == MACHINE_PIN_MODE_IN) {
|
||||
if (mode == MACHINE_PIN_MODE_IN || mode == MACHINE_PIN_MODE_ANALOG) {
|
||||
mode = NINA_GPIO_INPUT;
|
||||
self->is_output = false;
|
||||
} else if (mode == MACHINE_PIN_MODE_OUT) {
|
||||
|
@ -89,7 +119,7 @@ void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
|
|||
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
|
||||
uint8_t buf[] = {pin_map[self->id], mode};
|
||||
if (mode == NINA_GPIO_OUTPUT) {
|
||||
if (NINA_GPIO_IS_INPUT_ONLY(buf[0])) {
|
||||
if (NINA_GPIO_IS_INPUT_ONLY(self->id)) {
|
||||
mp_raise_ValueError("only Pin.IN is supported for this pin");
|
||||
}
|
||||
machine_pin_ext_set(self, value);
|
||||
|
|
|
@ -75,12 +75,13 @@ static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param
|
|||
// Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen).
|
||||
for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) {
|
||||
while (!mp_bluetooth_hci_uart_any()) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_uint_t elapsed = mp_hal_ticks_ms() - start;
|
||||
// Timeout.
|
||||
if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
|
||||
if (elapsed > HCI_COMMAND_TIMEOUT) {
|
||||
error_printf("timeout waiting for HCI packet\n");
|
||||
return -1;
|
||||
}
|
||||
mp_event_wait_ms(HCI_COMMAND_TIMEOUT - elapsed);
|
||||
}
|
||||
|
||||
buf[i] = mp_bluetooth_hci_uart_readchar();
|
||||
|
|
|
@ -35,9 +35,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "modmachine.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#include "nina_bsp.h"
|
||||
#include "nina_wifi_drv.h"
|
||||
|
|
|
@ -684,6 +684,14 @@ int nina_ioctl(uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface) {
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
case NINA_CMD_GET_ANALOG_READ: {
|
||||
if (len != 2 || nina_send_command_read_vals(NINA_CMD_GET_ANALOG_READ,
|
||||
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(buf[0])),
|
||||
1, ARG_8BITS, NINA_VALS({(uint16_t *)&len, buf})) != 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
|||
MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, locals_dict, (void*)&framebuf_locals_dict, 2);
|
||||
|
||||
mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf));
|
||||
mp_store_global(MP_QSTR_FrameBuffer1, MP_OBJ_FROM_PTR(&legacy_framebuffer1_obj));
|
||||
mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
|
||||
mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB));
|
||||
mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565));
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
# Print a nice list of pins, their current settings, and available afs.
|
||||
# Requires pins_af.py from ports/stm32/build-PYBV10/ directory.
|
||||
|
||||
import pyb
|
||||
import pins_af
|
||||
|
||||
|
||||
def af():
|
||||
max_name_width = 0
|
||||
max_af_width = 0
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
max_name_width = max(max_name_width, len(pin_entry[0]))
|
||||
for af_entry in pin_entry[1:]:
|
||||
max_af_width = max(max_af_width, len(af_entry[1]))
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
pin_name = pin_entry[0]
|
||||
print("%-*s " % (max_name_width, pin_name), end="")
|
||||
for af_entry in pin_entry[1:]:
|
||||
print("%2d: %-*s " % (af_entry[0], max_af_width, af_entry[1]), end="")
|
||||
print("")
|
||||
|
||||
|
||||
def pins():
|
||||
mode_str = {
|
||||
pyb.Pin.IN: "IN",
|
||||
pyb.Pin.OUT_PP: "OUT_PP",
|
||||
pyb.Pin.OUT_OD: "OUT_OD",
|
||||
pyb.Pin.AF_PP: "AF_PP",
|
||||
pyb.Pin.AF_OD: "AF_OD",
|
||||
pyb.Pin.ANALOG: "ANALOG",
|
||||
}
|
||||
pull_str = {pyb.Pin.PULL_NONE: "", pyb.Pin.PULL_UP: "PULL_UP", pyb.Pin.PULL_DOWN: "PULL_DOWN"}
|
||||
width = [0, 0, 0, 0]
|
||||
rows = []
|
||||
for pin_entry in pins_af.PINS_AF:
|
||||
row = []
|
||||
pin_name = pin_entry[0]
|
||||
pin = pyb.Pin(pin_name)
|
||||
pin_mode = pin.mode()
|
||||
row.append(pin_name)
|
||||
row.append(mode_str[pin_mode])
|
||||
row.append(pull_str[pin.pull()])
|
||||
if pin_mode == pyb.Pin.AF_PP or pin_mode == pyb.Pin.AF_OD:
|
||||
pin_af = pin.af()
|
||||
for af_entry in pin_entry[1:]:
|
||||
if pin_af == af_entry[0]:
|
||||
af_str = "%d: %s" % (pin_af, af_entry[1])
|
||||
break
|
||||
else:
|
||||
af_str = "%d" % pin_af
|
||||
else:
|
||||
af_str = ""
|
||||
row.append(af_str)
|
||||
for col in range(len(width)):
|
||||
width[col] = max(width[col], len(row[col]))
|
||||
rows.append(row)
|
||||
for row in rows:
|
||||
for col in range(len(width)):
|
||||
print("%-*s " % (width[col], row[col]), end="")
|
||||
print("")
|
|
@ -1,9 +1,16 @@
|
|||
extern "C" {
|
||||
#include <examplemodule.h>
|
||||
#include <py/objstr.h>
|
||||
|
||||
// Here we implement the function using C++ code, but since it's
|
||||
// declaration has to be compatible with C everything goes in extern "C" scope.
|
||||
mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj) {
|
||||
// The following no-ops are just here to verify the static assertions used in
|
||||
// the public API all compile with C++.
|
||||
MP_STATIC_ASSERT_STR_ARRAY_COMPATIBLE;
|
||||
if (mp_obj_is_type(a_obj, &mp_type_BaseException)) {
|
||||
}
|
||||
|
||||
// Prove we have (at least) C++11 features.
|
||||
const auto a = mp_obj_get_int(a_obj);
|
||||
const auto b = mp_obj_get_int(b_obj);
|
||||
|
|
|
@ -272,9 +272,9 @@ class Loop:
|
|||
return Loop._exc_handler
|
||||
|
||||
def default_exception_handler(loop, context):
|
||||
print(context["message"])
|
||||
print("future:", context["future"], "coro=", context["future"].coro)
|
||||
sys.print_exception(context["exception"])
|
||||
print(context["message"], file=sys.stderr)
|
||||
print("future:", context["future"], "coro=", context["future"].coro, file=sys.stderr)
|
||||
sys.print_exception(context["exception"], sys.stderr)
|
||||
|
||||
def call_exception_handler(context):
|
||||
(Loop._exc_handler or Loop.default_exception_handler)(Loop, context)
|
||||
|
|
|
@ -13,12 +13,6 @@ class Stream:
|
|||
def get_extra_info(self, v):
|
||||
return self.e[v]
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb):
|
||||
await self.close()
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
@ -63,6 +57,8 @@ class Stream:
|
|||
while True:
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
l2 = self.s.readline() # may do multiple reads but won't block
|
||||
if l2 is None:
|
||||
continue
|
||||
l += l2
|
||||
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
|
||||
return l
|
||||
|
@ -100,19 +96,29 @@ StreamWriter = Stream
|
|||
# Create a TCP stream connection to a remote host
|
||||
#
|
||||
# async
|
||||
def open_connection(host, port):
|
||||
def open_connection(host, port, ssl=None, server_hostname=None):
|
||||
from errno import EINPROGRESS
|
||||
import socket
|
||||
|
||||
ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
|
||||
s = socket.socket(ai[0], ai[1], ai[2])
|
||||
s.setblocking(False)
|
||||
ss = Stream(s)
|
||||
try:
|
||||
s.connect(ai[-1])
|
||||
except OSError as er:
|
||||
if er.errno != EINPROGRESS:
|
||||
raise er
|
||||
# wrap with SSL, if requested
|
||||
if ssl:
|
||||
if ssl is True:
|
||||
import ssl as _ssl
|
||||
|
||||
ssl = _ssl.SSLContext(_ssl.PROTOCOL_TLS_CLIENT)
|
||||
if not server_hostname:
|
||||
server_hostname = host
|
||||
s = ssl.wrap_socket(s, server_hostname=server_hostname, do_handshake_on_connect=False)
|
||||
s.setblocking(False)
|
||||
ss = Stream(s)
|
||||
yield core._io_queue.queue_write(s)
|
||||
return ss, ss
|
||||
|
||||
|
@ -135,7 +141,7 @@ class Server:
|
|||
async def wait_closed(self):
|
||||
await self.task
|
||||
|
||||
async def _serve(self, s, cb):
|
||||
async def _serve(self, s, cb, ssl):
|
||||
self.state = False
|
||||
# Accept incoming connections
|
||||
while True:
|
||||
|
@ -156,6 +162,13 @@ class Server:
|
|||
except:
|
||||
# Ignore a failed accept
|
||||
continue
|
||||
if ssl:
|
||||
try:
|
||||
s2 = ssl.wrap_socket(s2, server_side=True, do_handshake_on_connect=False)
|
||||
except OSError as e:
|
||||
core.sys.print_exception(e)
|
||||
s2.close()
|
||||
continue
|
||||
s2.setblocking(False)
|
||||
s2s = Stream(s2, {"peername": addr})
|
||||
core.create_task(cb(s2s, s2s))
|
||||
|
@ -163,7 +176,7 @@ class Server:
|
|||
|
||||
# Helper function to start a TCP stream server, running as a new task
|
||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||
async def start_server(cb, host, port, backlog=5):
|
||||
async def start_server(cb, host, port, backlog=5, ssl=None):
|
||||
import socket
|
||||
|
||||
# Create and bind server socket.
|
||||
|
@ -176,7 +189,7 @@ async def start_server(cb, host, port, backlog=5):
|
|||
|
||||
# Create and return server object and task.
|
||||
srv = Server()
|
||||
srv.task = core.create_task(srv._serve(s, cb))
|
||||
srv.task = core.create_task(srv._serve(s, cb, ssl))
|
||||
try:
|
||||
# Ensure that the _serve task has been scheduled so that it gets to
|
||||
# handle cancellation.
|
||||
|
|
|
@ -552,7 +552,7 @@ STATIC void set_random_address(void) {
|
|||
volatile bool ready = false;
|
||||
btstack_crypto_random_generate(&sm_crypto_random_request, static_addr, 6, &btstack_static_address_ready, (void *)&ready);
|
||||
while (!ready) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
|
||||
#endif // MICROPY_BLUETOOTH_USE_MP_HAL_GET_MAC_STATIC_ADDRESS
|
||||
|
@ -574,7 +574,7 @@ STATIC void set_random_address(void) {
|
|||
break;
|
||||
}
|
||||
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
DEBUG_printf("set_random_address: Address loaded by controller\n");
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ int mp_bluetooth_init(void) {
|
|||
// Either the HCI event will set state to ACTIVE, or the timeout will set it to TIMEOUT.
|
||||
mp_bluetooth_btstack_port_start();
|
||||
while (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_STARTING) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
btstack_run_loop_remove_timer(&btstack_init_deinit_timeout);
|
||||
|
||||
|
@ -727,7 +727,7 @@ void mp_bluetooth_deinit(void) {
|
|||
// either timeout or clean shutdown.
|
||||
mp_bluetooth_btstack_port_deinit();
|
||||
while (mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_ACTIVE) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
btstack_run_loop_remove_timer(&btstack_init_deinit_timeout);
|
||||
|
||||
|
|
|
@ -7,16 +7,22 @@ set(MICROPY_SOURCE_EXTMOD
|
|||
${MICROPY_DIR}/shared/libc/abort_.c
|
||||
${MICROPY_DIR}/shared/libc/printf.c
|
||||
${MICROPY_EXTMOD_DIR}/btstack/modbluetooth_btstack.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_adc.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_adc_block.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_bitstream.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2c.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2s.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_mem.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_pulse.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_pwm.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_signal.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_spi.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_uart.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_wdt.c
|
||||
${MICROPY_EXTMOD_DIR}/modbluetooth.c
|
||||
${MICROPY_EXTMOD_DIR}/modframebuf.c
|
||||
${MICROPY_EXTMOD_DIR}/modlwip.c
|
||||
${MICROPY_EXTMOD_DIR}/modmachine.c
|
||||
${MICROPY_EXTMOD_DIR}/modnetwork.c
|
||||
${MICROPY_EXTMOD_DIR}/modonewire.c
|
||||
${MICROPY_EXTMOD_DIR}/modasyncio.c
|
||||
|
@ -56,6 +62,41 @@ set(MICROPY_SOURCE_EXTMOD
|
|||
${MICROPY_EXTMOD_DIR}/nimble/modbluetooth_nimble.c
|
||||
)
|
||||
|
||||
# Single-precision libm math library.
|
||||
|
||||
set(MICROPY_SOURCE_LIB_LIBM
|
||||
${MICROPY_DIR}/lib/libm/acoshf.c
|
||||
${MICROPY_DIR}/lib/libm/asinfacosf.c
|
||||
${MICROPY_DIR}/lib/libm/asinhf.c
|
||||
${MICROPY_DIR}/lib/libm/atan2f.c
|
||||
${MICROPY_DIR}/lib/libm/atanf.c
|
||||
${MICROPY_DIR}/lib/libm/atanhf.c
|
||||
${MICROPY_DIR}/lib/libm/ef_rem_pio2.c
|
||||
${MICROPY_DIR}/lib/libm/erf_lgamma.c
|
||||
${MICROPY_DIR}/lib/libm/fmodf.c
|
||||
${MICROPY_DIR}/lib/libm/kf_cos.c
|
||||
${MICROPY_DIR}/lib/libm/kf_rem_pio2.c
|
||||
${MICROPY_DIR}/lib/libm/kf_sin.c
|
||||
${MICROPY_DIR}/lib/libm/kf_tan.c
|
||||
${MICROPY_DIR}/lib/libm/log1pf.c
|
||||
${MICROPY_DIR}/lib/libm/math.c
|
||||
${MICROPY_DIR}/lib/libm/nearbyintf.c
|
||||
${MICROPY_DIR}/lib/libm/roundf.c
|
||||
${MICROPY_DIR}/lib/libm/sf_cos.c
|
||||
${MICROPY_DIR}/lib/libm/sf_erf.c
|
||||
${MICROPY_DIR}/lib/libm/sf_frexp.c
|
||||
${MICROPY_DIR}/lib/libm/sf_ldexp.c
|
||||
${MICROPY_DIR}/lib/libm/sf_modf.c
|
||||
${MICROPY_DIR}/lib/libm/sf_sin.c
|
||||
${MICROPY_DIR}/lib/libm/sf_tan.c
|
||||
${MICROPY_DIR}/lib/libm/wf_lgamma.c
|
||||
${MICROPY_DIR}/lib/libm/wf_tgamma.c
|
||||
)
|
||||
|
||||
# Choose only one of these sqrt implementations, software or hardware.
|
||||
set(MICROPY_SOURCE_LIB_LIBM_SQRT_SW ${MICROPY_DIR}/lib/libm/ef_sqrt.c)
|
||||
set(MICROPY_SOURCE_LIB_LIBM_SQRT_HW ${MICROPY_DIR}/lib/libm/thumb_vfp_sqrtf.c)
|
||||
|
||||
# Library for btree module and associated code
|
||||
|
||||
if(MICROPY_PY_BTREE)
|
||||
|
|
101
extmod/extmod.mk
|
@ -2,8 +2,11 @@
|
|||
# and provides rules to build 3rd-party components for extmod modules.
|
||||
|
||||
SRC_EXTMOD_C += \
|
||||
extmod/machine_adc.c \
|
||||
extmod/machine_adc_block.c \
|
||||
extmod/machine_bitstream.c \
|
||||
extmod/machine_i2c.c \
|
||||
extmod/machine_i2s.c \
|
||||
extmod/machine_mem.c \
|
||||
extmod/machine_pinbase.c \
|
||||
extmod/machine_pulse.c \
|
||||
|
@ -11,6 +14,8 @@ SRC_EXTMOD_C += \
|
|||
extmod/machine_signal.c \
|
||||
extmod/machine_spi.c \
|
||||
extmod/machine_timer.c \
|
||||
extmod/machine_uart.c \
|
||||
extmod/machine_wdt.c \
|
||||
extmod/modasyncio.c \
|
||||
extmod/modbinascii.c \
|
||||
extmod/modbluetooth.c \
|
||||
|
@ -22,6 +27,7 @@ SRC_EXTMOD_C += \
|
|||
extmod/modheapq.c \
|
||||
extmod/modjson.c \
|
||||
extmod/modlwip.c \
|
||||
extmod/modmachine.c \
|
||||
extmod/modnetwork.c \
|
||||
extmod/modonewire.c \
|
||||
extmod/modos.c \
|
||||
|
@ -64,6 +70,96 @@ SRC_QSTR += $(SRC_EXTMOD_C)
|
|||
CFLAGS += $(CFLAGS_EXTMOD) $(CFLAGS_THIRDPARTY)
|
||||
LDFLAGS += $(LDFLAGS_EXTMOD) $(LDFLAGS_THIRDPARTY)
|
||||
|
||||
################################################################################
|
||||
# libm/libm_dbl math library
|
||||
|
||||
# Single-precision math library.
|
||||
SRC_LIB_LIBM_C += $(addprefix lib/libm/,\
|
||||
acoshf.c \
|
||||
asinfacosf.c \
|
||||
asinhf.c \
|
||||
atan2f.c \
|
||||
atanf.c \
|
||||
atanhf.c \
|
||||
ef_rem_pio2.c \
|
||||
erf_lgamma.c \
|
||||
fmodf.c \
|
||||
kf_cos.c \
|
||||
kf_rem_pio2.c \
|
||||
kf_sin.c \
|
||||
kf_tan.c \
|
||||
log1pf.c \
|
||||
math.c \
|
||||
nearbyintf.c \
|
||||
roundf.c \
|
||||
sf_cos.c \
|
||||
sf_erf.c \
|
||||
sf_frexp.c \
|
||||
sf_ldexp.c \
|
||||
sf_modf.c \
|
||||
sf_sin.c \
|
||||
sf_tan.c \
|
||||
wf_lgamma.c \
|
||||
wf_tgamma.c \
|
||||
)
|
||||
|
||||
# Choose only one of these sqrt implementations, software or hardware.
|
||||
SRC_LIB_LIBM_SQRT_SW_C += lib/libm/ef_sqrt.c
|
||||
SRC_LIB_LIBM_SQRT_HW_C += lib/libm/thumb_vfp_sqrtf.c
|
||||
|
||||
# Double-precision math library.
|
||||
SRC_LIB_LIBM_DBL_C += $(addprefix lib/libm_dbl/,\
|
||||
__cos.c \
|
||||
__expo2.c \
|
||||
__fpclassify.c \
|
||||
__rem_pio2.c \
|
||||
__rem_pio2_large.c \
|
||||
__signbit.c \
|
||||
__sin.c \
|
||||
__tan.c \
|
||||
acos.c \
|
||||
acosh.c \
|
||||
asin.c \
|
||||
asinh.c \
|
||||
atan.c \
|
||||
atan2.c \
|
||||
atanh.c \
|
||||
ceil.c \
|
||||
cos.c \
|
||||
cosh.c \
|
||||
copysign.c \
|
||||
erf.c \
|
||||
exp.c \
|
||||
expm1.c \
|
||||
floor.c \
|
||||
fmod.c \
|
||||
frexp.c \
|
||||
ldexp.c \
|
||||
lgamma.c \
|
||||
log.c \
|
||||
log10.c \
|
||||
log1p.c \
|
||||
modf.c \
|
||||
nearbyint.c \
|
||||
pow.c \
|
||||
rint.c \
|
||||
round.c \
|
||||
scalbn.c \
|
||||
sin.c \
|
||||
sinh.c \
|
||||
tan.c \
|
||||
tanh.c \
|
||||
tgamma.c \
|
||||
trunc.c \
|
||||
)
|
||||
|
||||
# Choose only one of these sqrt implementations, software or hardware.
|
||||
SRC_LIB_LIBM_DBL_SQRT_SW_C += lib/libm_dbl/sqrt.c
|
||||
SRC_LIB_LIBM_DBL_SQRT_HW_C += lib/libm_dbl/thumb_vfp_sqrt.c
|
||||
|
||||
# Too many warnings in libm_dbl, disable for now.
|
||||
$(BUILD)/lib/libm_dbl/%.o: CFLAGS += -Wno-double-promotion -Wno-float-conversion
|
||||
|
||||
################################################################################
|
||||
# VFS FAT FS
|
||||
|
||||
|
@ -102,7 +198,7 @@ SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\
|
|||
lfs2_util.c \
|
||||
)
|
||||
|
||||
$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-missing-field-initializers
|
||||
$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-shadow
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
@ -262,6 +358,9 @@ SRC_THIRDPARTY_C += $(addprefix $(LWIP_DIR)/,\
|
|||
core/ipv6/nd6.c \
|
||||
netif/ethernet.c \
|
||||
)
|
||||
ifeq ($(MICROPY_PY_LWIP_LOOPBACK),1)
|
||||
CFLAGS_EXTMOD += -DLWIP_NETIF_LOOPBACK=1
|
||||
endif
|
||||
ifeq ($(MICROPY_PY_LWIP_SLIP),1)
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_LWIP_SLIP=1
|
||||
SRC_THIRDPARTY_C += $(LWIP_DIR)/netif/slipif.c
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
// The port must provide implementations of these low-level ADC functions.
|
||||
|
||||
STATIC void mp_machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
STATIC mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
STATIC mp_int_t mp_machine_adc_read_u16(machine_adc_obj_t *self);
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_INIT
|
||||
STATIC void mp_machine_adc_init_helper(machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_DEINIT
|
||||
STATIC void mp_machine_adc_deinit(machine_adc_obj_t *self);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
STATIC mp_obj_t mp_machine_adc_block(machine_adc_obj_t *self);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_READ_UV
|
||||
STATIC mp_int_t mp_machine_adc_read_uv(machine_adc_obj_t *self);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH
|
||||
STATIC void mp_machine_adc_atten_set(machine_adc_obj_t *self, mp_int_t atten);
|
||||
STATIC void mp_machine_adc_width_set(machine_adc_obj_t *self, mp_int_t width);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_READ
|
||||
STATIC mp_int_t mp_machine_adc_read(machine_adc_obj_t *self);
|
||||
#endif
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_ADC_INCLUDEFILE
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_INIT
|
||||
// ADC.init(...)
|
||||
STATIC mp_obj_t machine_adc_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_machine_adc_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adc_init_obj, 1, machine_adc_init);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_DEINIT
|
||||
// ADC.deinit()
|
||||
STATIC mp_obj_t machine_adc_deinit(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_adc_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_deinit_obj, machine_adc_deinit);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
// ADC.block()
|
||||
STATIC mp_obj_t machine_adc_block(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_machine_adc_block(self);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_block_obj, machine_adc_block);
|
||||
#endif
|
||||
|
||||
// ADC.read_u16()
|
||||
STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_adc_read_u16(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_READ_UV
|
||||
// ADC.read_uv()
|
||||
STATIC mp_obj_t machine_adc_read_uv(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_adc_read_uv(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_uv_obj, machine_adc_read_uv);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH
|
||||
|
||||
// ADC.atten(value) -- this is a legacy method.
|
||||
STATIC mp_obj_t machine_adc_atten(mp_obj_t self_in, mp_obj_t atten_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t atten = mp_obj_get_int(atten_in);
|
||||
mp_machine_adc_atten_set(self, atten);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_adc_atten_obj, machine_adc_atten);
|
||||
|
||||
// ADC.width(value) -- this is a legacy method.
|
||||
STATIC mp_obj_t machine_adc_width(mp_obj_t self_in, mp_obj_t width_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t width = mp_obj_get_int(width_in);
|
||||
mp_machine_adc_width_set(self, width);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_adc_width_obj, machine_adc_width);
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_READ
|
||||
// ADC.read() -- this is a legacy method.
|
||||
STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_adc_read(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {
|
||||
#if MICROPY_PY_MACHINE_ADC_INIT
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_adc_init_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_ADC_DEINIT
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_adc_deinit_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
{ MP_ROM_QSTR(MP_QSTR_block), MP_ROM_PTR(&machine_adc_block_obj) },
|
||||
#endif
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
|
||||
#if MICROPY_PY_MACHINE_ADC_READ_UV
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_uv), MP_ROM_PTR(&machine_adc_read_uv_obj) },
|
||||
#endif
|
||||
|
||||
// Legacy methods.
|
||||
#if MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH
|
||||
{ MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&machine_adc_atten_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&machine_adc_width_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_ADC_READ
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_adc_read_obj) },
|
||||
#endif
|
||||
|
||||
// A port must add ADC class constants defining the following macro.
|
||||
// It can be defined to nothing if there are no constants.
|
||||
MICROPY_PY_MACHINE_ADC_CLASS_CONSTANTS
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table);
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_adc_type,
|
||||
MP_QSTR_ADC,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, mp_machine_adc_make_new,
|
||||
print, mp_machine_adc_print,
|
||||
locals_dict, &machine_adc_locals_dict
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_ADC
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Jonathan Hogg
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
// The port must provide implementations of these low-level ADCBlock functions.
|
||||
STATIC void mp_machine_adc_block_print(const mp_print_t *print, machine_adc_block_obj_t *self);
|
||||
STATIC machine_adc_block_obj_t *mp_machine_adc_block_get(mp_int_t unit);
|
||||
STATIC void mp_machine_adc_block_bits_set(machine_adc_block_obj_t *self, mp_int_t bits);
|
||||
STATIC machine_adc_obj_t *mp_machine_adc_block_connect(machine_adc_block_obj_t *self, mp_int_t channel_id, mp_hal_pin_obj_t pin, mp_map_t *kw_args);
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_ADC_BLOCK_INCLUDEFILE
|
||||
|
||||
STATIC void machine_adc_block_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
machine_adc_block_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_adc_block_print(print, self);
|
||||
}
|
||||
|
||||
STATIC void machine_adc_block_init_helper(machine_adc_block_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum {
|
||||
ARG_bits,
|
||||
};
|
||||
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_int_t bits = args[ARG_bits].u_int;
|
||||
mp_machine_adc_block_bits_set(self, bits);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_adc_block_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
mp_int_t unit = mp_obj_get_int(args[0]);
|
||||
machine_adc_block_obj_t *self = mp_machine_adc_block_get(unit);
|
||||
if (self == NULL) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid block id"));
|
||||
}
|
||||
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
|
||||
machine_adc_block_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_adc_block_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
machine_adc_block_obj_t *self = pos_args[0];
|
||||
machine_adc_block_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adc_block_init_obj, 1, machine_adc_block_init);
|
||||
|
||||
STATIC mp_obj_t machine_adc_block_connect(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
machine_adc_block_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_int_t channel_id = -1;
|
||||
mp_hal_pin_obj_t pin = -1;
|
||||
if (n_pos_args == 2) {
|
||||
if (mp_obj_is_int(pos_args[1])) {
|
||||
channel_id = mp_obj_get_int(pos_args[1]);
|
||||
} else {
|
||||
pin = mp_hal_get_pin_obj(pos_args[1]);
|
||||
}
|
||||
} else if (n_pos_args == 3) {
|
||||
channel_id = mp_obj_get_int(pos_args[1]);
|
||||
pin = mp_hal_get_pin_obj(pos_args[2]);
|
||||
} else {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("too many positional args"));
|
||||
}
|
||||
|
||||
machine_adc_obj_t *adc = mp_machine_adc_block_connect(self, channel_id, pin, kw_args);
|
||||
if (adc == NULL) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("no matching ADC"));
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(adc);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_adc_block_connect_obj, 2, machine_adc_block_connect);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_adc_block_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_adc_block_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&machine_adc_block_connect_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_adc_block_locals_dict, machine_adc_block_locals_dict_table);
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_adc_block_type,
|
||||
MP_QSTR_ADCBlock,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, machine_adc_block_make_new,
|
||||
print, machine_adc_block_print,
|
||||
locals_dict, &machine_adc_block_locals_dict
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_ADC_BLOCK
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/machine_bitstream.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_BITSTREAM
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Jim Mussared
|
||||
* Copyright (c) 2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_BITSTREAM_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_BITSTREAM_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bitstream_obj);
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_BITSTREAM_H
|
|
@ -31,7 +31,7 @@
|
|||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_i2c.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#define SOFT_I2C_DEFAULT_TIMEOUT_US (50000) // 50ms
|
||||
|
||||
|
@ -328,9 +328,10 @@ STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
|
|||
if (ret == 0) {
|
||||
mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
|
||||
}
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
#endif
|
||||
// This scan loop may run for some time, so process any pending events/exceptions,
|
||||
// or allow the port to run any necessary background tasks. But do it as fast as
|
||||
// possible, in particular we are not waiting on any events.
|
||||
mp_event_handle_nowait();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
// Temporary support for legacy construction of SoftI2C via I2C type.
|
||||
#define MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||
do { \
|
||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead\n"); \
|
||||
if (n_args != 0) { \
|
||||
--n_args; \
|
||||
++all_args; \
|
||||
} \
|
||||
return MP_OBJ_TYPE_GET_SLOT(&mp_machine_soft_i2c_type, make_new)(&mp_machine_soft_i2c_type, n_args, n_kw, all_args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write
|
||||
#define MP_MACHINE_I2C_FLAG_STOP (0x02)
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
||||
// If set, the first mp_machine_i2c_buf_t in a transfer is a write.
|
||||
#define MP_MACHINE_I2C_FLAG_WRITE1 (0x04)
|
||||
#endif
|
||||
|
||||
typedef struct _mp_machine_i2c_buf_t {
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
} mp_machine_i2c_buf_t;
|
||||
|
||||
// I2C protocol
|
||||
// - init must be non-NULL
|
||||
// - start/stop/read/write can be NULL, meaning operation is not supported
|
||||
// - transfer must be non-NULL
|
||||
// - transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
||||
typedef struct _mp_machine_i2c_p_t {
|
||||
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
||||
bool transfer_supports_write1;
|
||||
#endif
|
||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
int (*start)(mp_obj_base_t *obj);
|
||||
int (*stop)(mp_obj_base_t *obj);
|
||||
int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);
|
||||
int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len);
|
||||
int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags);
|
||||
} mp_machine_i2c_p_t;
|
||||
|
||||
typedef struct _mp_machine_soft_i2c_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t us_delay;
|
||||
uint32_t us_timeout;
|
||||
mp_hal_pin_obj_t scl;
|
||||
mp_hal_pin_obj_t sda;
|
||||
} mp_machine_soft_i2c_obj_t;
|
||||
|
||||
extern const mp_obj_type_t mp_machine_soft_i2c_type;
|
||||
extern const mp_obj_dict_t mp_machine_i2c_locals_dict;
|
||||
|
||||
int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H
|
|
@ -0,0 +1,698 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Mike Teachman
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2S
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
// The I2S class has 3 modes of operation:
|
||||
//
|
||||
// Mode1: Blocking
|
||||
// - readinto() and write() methods block until the supplied buffer is filled (read) or emptied (write)
|
||||
// - this is the default mode of operation
|
||||
//
|
||||
// Mode2: Non-Blocking
|
||||
// - readinto() and write() methods return immediately
|
||||
// - buffer filling and emptying happens asynchronously to the main MicroPython task
|
||||
// - a callback function is called when the supplied buffer has been filled (read) or emptied (write)
|
||||
// - non-blocking mode is enabled when a callback is set with the irq() method
|
||||
// - implementation of asynchronous background operations is port specific
|
||||
//
|
||||
// Mode3: Asyncio
|
||||
// - implements the stream protocol
|
||||
// - asyncio mode is enabled when the ioctl() function is called
|
||||
// - the state of the internal ring buffer is used to detect that I2S samples can be read or written
|
||||
//
|
||||
// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
|
||||
// Mono: little endian format
|
||||
// Stereo: little endian format, left channel first
|
||||
//
|
||||
// I2S terms:
|
||||
// "frame": consists of two audio samples (Left audio sample + Right audio sample)
|
||||
//
|
||||
// Misc:
|
||||
// - for Mono configuration:
|
||||
// - readinto method: samples are gathered from the L channel only
|
||||
// - write method: every sample is output to both the L and R channels
|
||||
// - for readinto method the I2S hardware is read using 8-byte frames
|
||||
// (this is standard for almost all I2S hardware, such as MEMS microphones)
|
||||
|
||||
#define NUM_I2S_USER_FORMATS (4)
|
||||
#define I2S_RX_FRAME_SIZE_IN_BYTES (8)
|
||||
|
||||
typedef enum {
|
||||
MONO,
|
||||
STEREO
|
||||
} format_t;
|
||||
|
||||
typedef enum {
|
||||
BLOCKING,
|
||||
NON_BLOCKING,
|
||||
ASYNCIO
|
||||
} io_mode_t;
|
||||
|
||||
// Arguments for I2S() constructor and I2S.init().
|
||||
enum {
|
||||
ARG_sck,
|
||||
ARG_ws,
|
||||
ARG_sd,
|
||||
#if MICROPY_PY_MACHINE_I2S_MCK
|
||||
ARG_mck,
|
||||
#endif
|
||||
ARG_mode,
|
||||
ARG_bits,
|
||||
ARG_format,
|
||||
ARG_rate,
|
||||
ARG_ibuf,
|
||||
};
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
|
||||
typedef struct _ring_buf_t {
|
||||
uint8_t *buffer;
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t size;
|
||||
} ring_buf_t;
|
||||
|
||||
typedef struct _non_blocking_descriptor_t {
|
||||
mp_buffer_info_t appbuf;
|
||||
uint32_t index;
|
||||
bool copy_in_progress;
|
||||
} non_blocking_descriptor_t;
|
||||
|
||||
STATIC void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size);
|
||||
STATIC bool ringbuf_push(ring_buf_t *rbuf, uint8_t data);
|
||||
STATIC bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data);
|
||||
STATIC size_t ringbuf_available_data(ring_buf_t *rbuf);
|
||||
STATIC size_t ringbuf_available_space(ring_buf_t *rbuf);
|
||||
STATIC void fill_appbuf_from_ringbuf_non_blocking(machine_i2s_obj_t *self);
|
||||
STATIC void copy_appbuf_to_ringbuf_non_blocking(machine_i2s_obj_t *self);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
|
||||
// The port must provide implementations of these low-level I2S functions.
|
||||
STATIC void mp_machine_i2s_init_helper(machine_i2s_obj_t *self, mp_arg_val_t *args);
|
||||
STATIC machine_i2s_obj_t *mp_machine_i2s_make_new_instance(mp_int_t i2s_id);
|
||||
STATIC void mp_machine_i2s_deinit(machine_i2s_obj_t *self);
|
||||
STATIC void mp_machine_i2s_irq_update(machine_i2s_obj_t *self);
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_I2S_INCLUDEFILE
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
|
||||
// Ring Buffer
|
||||
// Thread safe when used with these constraints:
|
||||
// - Single Producer, Single Consumer
|
||||
// - Sequential atomic operations
|
||||
// One byte of capacity is used to detect buffer empty/full
|
||||
|
||||
STATIC void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) {
|
||||
rbuf->buffer = buffer;
|
||||
rbuf->size = size;
|
||||
rbuf->head = 0;
|
||||
rbuf->tail = 0;
|
||||
}
|
||||
|
||||
STATIC bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) {
|
||||
size_t next_tail = (rbuf->tail + 1) % rbuf->size;
|
||||
|
||||
if (next_tail != rbuf->head) {
|
||||
rbuf->buffer[rbuf->tail] = data;
|
||||
rbuf->tail = next_tail;
|
||||
return true;
|
||||
}
|
||||
|
||||
// full
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) {
|
||||
if (rbuf->head == rbuf->tail) {
|
||||
// empty
|
||||
return false;
|
||||
}
|
||||
|
||||
*data = rbuf->buffer[rbuf->head];
|
||||
rbuf->head = (rbuf->head + 1) % rbuf->size;
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC bool ringbuf_is_empty(ring_buf_t *rbuf) {
|
||||
return rbuf->head == rbuf->tail;
|
||||
}
|
||||
|
||||
STATIC bool ringbuf_is_full(ring_buf_t *rbuf) {
|
||||
return ((rbuf->tail + 1) % rbuf->size) == rbuf->head;
|
||||
}
|
||||
|
||||
STATIC size_t ringbuf_available_data(ring_buf_t *rbuf) {
|
||||
return (rbuf->tail - rbuf->head + rbuf->size) % rbuf->size;
|
||||
}
|
||||
|
||||
STATIC size_t ringbuf_available_space(ring_buf_t *rbuf) {
|
||||
return rbuf->size - ringbuf_available_data(rbuf) - 1;
|
||||
}
|
||||
|
||||
STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
|
||||
|
||||
// copy audio samples from the ring buffer to the app buffer
|
||||
// loop, copying samples until the app buffer is filled
|
||||
// For asyncio mode, the loop will make an early exit if the ring buffer becomes empty
|
||||
// Example:
|
||||
// a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
|
||||
// For every frame coming from the ring buffer (8 bytes), 2 bytes are "cherry picked" and
|
||||
// copied to the supplied app buffer.
|
||||
// Thus, for every 1 byte copied to the app buffer, 4 bytes are read from the ring buffer.
|
||||
// If a 8kB app buffer is supplied, 32kB of audio samples is read from the ring buffer.
|
||||
|
||||
uint32_t num_bytes_copied_to_appbuf = 0;
|
||||
uint8_t *app_p = (uint8_t *)appbuf->buf;
|
||||
uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
|
||||
uint32_t num_bytes_needed_from_ringbuf = appbuf->len * (I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
|
||||
uint8_t discard_byte;
|
||||
while (num_bytes_needed_from_ringbuf) {
|
||||
|
||||
uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
|
||||
|
||||
for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
|
||||
int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
|
||||
if (r_to_a_mapping != -1) {
|
||||
if (self->io_mode == BLOCKING) {
|
||||
// poll the ringbuf until a sample becomes available, copy into appbuf using the mapping transform
|
||||
while (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
|
||||
;
|
||||
}
|
||||
num_bytes_copied_to_appbuf++;
|
||||
} else if (self->io_mode == ASYNCIO) {
|
||||
if (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
|
||||
// ring buffer is empty, exit
|
||||
goto exit;
|
||||
} else {
|
||||
num_bytes_copied_to_appbuf++;
|
||||
}
|
||||
} else {
|
||||
return 0; // should never get here (non-blocking mode does not use this function)
|
||||
}
|
||||
} else { // r_a_mapping == -1
|
||||
// discard unused byte from ring buffer
|
||||
if (self->io_mode == BLOCKING) {
|
||||
// poll the ringbuf until a sample becomes available
|
||||
while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
|
||||
;
|
||||
}
|
||||
} else if (self->io_mode == ASYNCIO) {
|
||||
if (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
|
||||
// ring buffer is empty, exit
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
return 0; // should never get here (non-blocking mode does not use this function)
|
||||
}
|
||||
}
|
||||
num_bytes_needed_from_ringbuf--;
|
||||
}
|
||||
app_p += appbuf_sample_size_in_bytes;
|
||||
}
|
||||
exit:
|
||||
return num_bytes_copied_to_appbuf;
|
||||
}
|
||||
|
||||
// function is used in IRQ context
|
||||
STATIC void fill_appbuf_from_ringbuf_non_blocking(machine_i2s_obj_t *self) {
|
||||
|
||||
// attempt to copy a block of audio samples from the ring buffer to the supplied app buffer.
|
||||
// audio samples will be formatted as part of the copy operation
|
||||
|
||||
uint32_t num_bytes_copied_to_appbuf = 0;
|
||||
uint8_t *app_p = &(((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index]);
|
||||
|
||||
uint8_t appbuf_sample_size_in_bytes = (self->bits == 16? 2 : 4) * (self->format == STEREO ? 2: 1);
|
||||
uint32_t num_bytes_remaining_to_copy_to_appbuf = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
|
||||
uint32_t num_bytes_remaining_to_copy_from_ring_buffer = num_bytes_remaining_to_copy_to_appbuf *
|
||||
(I2S_RX_FRAME_SIZE_IN_BYTES / appbuf_sample_size_in_bytes);
|
||||
uint32_t num_bytes_needed_from_ringbuf = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy_from_ring_buffer);
|
||||
uint8_t discard_byte;
|
||||
if (ringbuf_available_data(&self->ring_buffer) >= num_bytes_needed_from_ringbuf) {
|
||||
while (num_bytes_needed_from_ringbuf) {
|
||||
|
||||
uint8_t f_index = get_frame_mapping_index(self->bits, self->format);
|
||||
|
||||
for (uint8_t i = 0; i < I2S_RX_FRAME_SIZE_IN_BYTES; i++) {
|
||||
int8_t r_to_a_mapping = i2s_frame_map[f_index][i];
|
||||
if (r_to_a_mapping != -1) {
|
||||
ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping);
|
||||
num_bytes_copied_to_appbuf++;
|
||||
} else { // r_a_mapping == -1
|
||||
// discard unused byte from ring buffer
|
||||
ringbuf_pop(&self->ring_buffer, &discard_byte);
|
||||
}
|
||||
num_bytes_needed_from_ringbuf--;
|
||||
}
|
||||
app_p += appbuf_sample_size_in_bytes;
|
||||
}
|
||||
self->non_blocking_descriptor.index += num_bytes_copied_to_appbuf;
|
||||
|
||||
if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
|
||||
self->non_blocking_descriptor.copy_in_progress = false;
|
||||
mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t *appbuf) {
|
||||
|
||||
// copy audio samples from the app buffer to the ring buffer
|
||||
// loop, reading samples until the app buffer is emptied
|
||||
// for asyncio mode, the loop will make an early exit if the ring buffer becomes full
|
||||
|
||||
uint32_t a_index = 0;
|
||||
|
||||
while (a_index < appbuf->len) {
|
||||
if (self->io_mode == BLOCKING) {
|
||||
// copy a byte to the ringbuf when space becomes available
|
||||
while (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
|
||||
;
|
||||
}
|
||||
a_index++;
|
||||
} else if (self->io_mode == ASYNCIO) {
|
||||
if (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
|
||||
// ring buffer is full, exit
|
||||
break;
|
||||
} else {
|
||||
a_index++;
|
||||
}
|
||||
} else {
|
||||
return 0; // should never get here (non-blocking mode does not use this function)
|
||||
}
|
||||
}
|
||||
|
||||
return a_index;
|
||||
}
|
||||
|
||||
// function is used in IRQ context
|
||||
STATIC void copy_appbuf_to_ringbuf_non_blocking(machine_i2s_obj_t *self) {
|
||||
|
||||
// copy audio samples from app buffer into ring buffer
|
||||
uint32_t num_bytes_remaining_to_copy = self->non_blocking_descriptor.appbuf.len - self->non_blocking_descriptor.index;
|
||||
uint32_t num_bytes_to_copy = MIN(SIZEOF_NON_BLOCKING_COPY_IN_BYTES, num_bytes_remaining_to_copy);
|
||||
|
||||
if (ringbuf_available_space(&self->ring_buffer) >= num_bytes_to_copy) {
|
||||
for (uint32_t i = 0; i < num_bytes_to_copy; i++) {
|
||||
ringbuf_push(&self->ring_buffer,
|
||||
((uint8_t *)self->non_blocking_descriptor.appbuf.buf)[self->non_blocking_descriptor.index + i]);
|
||||
}
|
||||
|
||||
self->non_blocking_descriptor.index += num_bytes_to_copy;
|
||||
if (self->non_blocking_descriptor.index >= self->non_blocking_descriptor.appbuf.len) {
|
||||
self->non_blocking_descriptor.copy_in_progress = false;
|
||||
mp_sched_schedule(self->callback_for_non_blocking, MP_OBJ_FROM_PTR(self));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
|
||||
MP_NOINLINE STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_ws, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_sd, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
#if MICROPY_PY_MACHINE_I2S_MCK
|
||||
{ MP_QSTR_mck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
#endif
|
||||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_ibuf, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_machine_i2s_init_helper(self, args);
|
||||
}
|
||||
|
||||
STATIC void machine_i2s_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "I2S(id=%u,\n"
|
||||
"sck="MP_HAL_PIN_FMT ",\n"
|
||||
"ws="MP_HAL_PIN_FMT ",\n"
|
||||
"sd="MP_HAL_PIN_FMT ",\n"
|
||||
#if MICROPY_PY_MACHINE_I2S_MCK
|
||||
"mck="MP_HAL_PIN_FMT ",\n"
|
||||
#endif
|
||||
"mode=%u,\n"
|
||||
"bits=%u, format=%u,\n"
|
||||
"rate=%d, ibuf=%d)",
|
||||
self->i2s_id,
|
||||
mp_hal_pin_name(self->sck),
|
||||
mp_hal_pin_name(self->ws),
|
||||
mp_hal_pin_name(self->sd),
|
||||
#if MICROPY_PY_MACHINE_I2S_MCK
|
||||
mp_hal_pin_name(self->mck),
|
||||
#endif
|
||||
self->mode,
|
||||
self->bits, self->format,
|
||||
self->rate, self->ibuf
|
||||
);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
mp_int_t i2s_id = mp_obj_get_int(args[0]);
|
||||
|
||||
machine_i2s_obj_t *self = mp_machine_i2s_make_new_instance(i2s_id);
|
||||
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
|
||||
machine_i2s_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
// I2S.init(...)
|
||||
STATIC mp_obj_t machine_i2s_init(size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_machine_i2s_deinit(self);
|
||||
machine_i2s_init_helper(self, n_pos_args - 1, pos_args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_init_obj, 1, machine_i2s_init);
|
||||
|
||||
// I2S.deinit()
|
||||
STATIC mp_obj_t machine_i2s_deinit(mp_obj_t self_in) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_i2s_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_i2s_deinit_obj, machine_i2s_deinit);
|
||||
|
||||
// I2S.irq(handler)
|
||||
STATIC mp_obj_t machine_i2s_irq(mp_obj_t self_in, mp_obj_t handler) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid callback"));
|
||||
}
|
||||
|
||||
if (handler != mp_const_none) {
|
||||
self->io_mode = NON_BLOCKING;
|
||||
} else {
|
||||
self->io_mode = BLOCKING;
|
||||
}
|
||||
|
||||
self->callback_for_non_blocking = handler;
|
||||
|
||||
mp_machine_i2s_irq_update(self);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_i2s_irq_obj, machine_i2s_irq);
|
||||
|
||||
// Shift() is typically used as a volume control.
|
||||
// shift=1 increases volume by 6dB, shift=-1 decreases volume by 6dB
|
||||
STATIC mp_obj_t machine_i2s_shift(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_buf, ARG_bits, ARG_shift};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_bits, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_shift, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
|
||||
// parse 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);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_RW);
|
||||
|
||||
int16_t *buf_16 = bufinfo.buf;
|
||||
int32_t *buf_32 = bufinfo.buf;
|
||||
|
||||
uint8_t bits = args[ARG_bits].u_int;
|
||||
int8_t shift = args[ARG_shift].u_int;
|
||||
|
||||
uint32_t num_audio_samples;
|
||||
switch (bits) {
|
||||
case 16:
|
||||
num_audio_samples = bufinfo.len / sizeof(uint16_t);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
num_audio_samples = bufinfo.len / sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_audio_samples; i++) {
|
||||
switch (bits) {
|
||||
case 16:
|
||||
if (shift >= 0) {
|
||||
buf_16[i] = buf_16[i] << shift;
|
||||
} else {
|
||||
buf_16[i] = buf_16[i] >> abs(shift);
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
if (shift >= 0) {
|
||||
buf_32[i] = buf_32[i] << shift;
|
||||
} else {
|
||||
buf_32[i] = buf_32[i] >> abs(shift);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2s_shift_fun_obj, 0, machine_i2s_shift);
|
||||
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(machine_i2s_shift_obj, MP_ROM_PTR(&machine_i2s_shift_fun_obj));
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_i2s_locals_dict_table[] = {
|
||||
// Methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2s_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2s_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2s_irq_obj) },
|
||||
#if MICROPY_PY_MACHINE_I2S_FINALISER
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_i2s_deinit_obj) },
|
||||
#endif
|
||||
|
||||
// Static method
|
||||
{ MP_ROM_QSTR(MP_QSTR_shift), MP_ROM_PTR(&machine_i2s_shift_obj) },
|
||||
|
||||
// Constants
|
||||
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_INT(MICROPY_PY_MACHINE_I2S_CONSTANT_RX) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_INT(MICROPY_PY_MACHINE_I2S_CONSTANT_TX) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STEREO), MP_ROM_INT(STEREO) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MONO), MP_ROM_INT(MONO) },
|
||||
};
|
||||
MP_DEFINE_CONST_DICT(machine_i2s_locals_dict, machine_i2s_locals_dict_table);
|
||||
|
||||
STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->mode != MICROPY_PY_MACHINE_I2S_CONSTANT_RX) {
|
||||
*errcode = MP_EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
uint8_t appbuf_sample_size_in_bytes = (self->bits / 8) * (self->format == STEREO ? 2: 1);
|
||||
if (size % appbuf_sample_size_in_bytes != 0) {
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->io_mode == NON_BLOCKING) {
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
|
||||
self->non_blocking_descriptor.appbuf.len = size;
|
||||
self->non_blocking_descriptor.index = 0;
|
||||
self->non_blocking_descriptor.copy_in_progress = true;
|
||||
#else
|
||||
non_blocking_descriptor_t descriptor;
|
||||
descriptor.appbuf.buf = (void *)buf_in;
|
||||
descriptor.appbuf.len = size;
|
||||
descriptor.callback = self->callback_for_non_blocking;
|
||||
descriptor.direction = I2S_RX_TRANSFER;
|
||||
// send the descriptor to the task that handles non-blocking mode
|
||||
xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
|
||||
#endif
|
||||
|
||||
return size;
|
||||
} else { // blocking or asyncio mode
|
||||
mp_buffer_info_t appbuf;
|
||||
appbuf.buf = (void *)buf_in;
|
||||
appbuf.len = size;
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
uint32_t num_bytes_read = fill_appbuf_from_ringbuf(self, &appbuf);
|
||||
#else
|
||||
uint32_t num_bytes_read = fill_appbuf_from_dma(self, &appbuf);
|
||||
#endif
|
||||
return num_bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->mode != MICROPY_PY_MACHINE_I2S_CONSTANT_TX) {
|
||||
*errcode = MP_EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->io_mode == NON_BLOCKING) {
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
self->non_blocking_descriptor.appbuf.buf = (void *)buf_in;
|
||||
self->non_blocking_descriptor.appbuf.len = size;
|
||||
self->non_blocking_descriptor.index = 0;
|
||||
self->non_blocking_descriptor.copy_in_progress = true;
|
||||
#else
|
||||
non_blocking_descriptor_t descriptor;
|
||||
descriptor.appbuf.buf = (void *)buf_in;
|
||||
descriptor.appbuf.len = size;
|
||||
descriptor.callback = self->callback_for_non_blocking;
|
||||
descriptor.direction = I2S_TX_TRANSFER;
|
||||
// send the descriptor to the task that handles non-blocking mode
|
||||
xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
|
||||
#endif
|
||||
|
||||
return size;
|
||||
} else { // blocking or asyncio mode
|
||||
mp_buffer_info_t appbuf;
|
||||
appbuf.buf = (void *)buf_in;
|
||||
appbuf.len = size;
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
uint32_t num_bytes_written = copy_appbuf_to_ringbuf(self, &appbuf);
|
||||
#else
|
||||
uint32_t num_bytes_written = copy_appbuf_to_dma(self, &appbuf);
|
||||
#endif
|
||||
return num_bytes_written;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_uint_t ret;
|
||||
uintptr_t flags = arg;
|
||||
self->io_mode = ASYNCIO; // a call to ioctl() is an indication that asyncio is being used
|
||||
|
||||
if (request == MP_STREAM_POLL) {
|
||||
ret = 0;
|
||||
|
||||
if (flags & MP_STREAM_POLL_RD) {
|
||||
if (self->mode != MICROPY_PY_MACHINE_I2S_CONSTANT_RX) {
|
||||
*errcode = MP_EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
if (!ringbuf_is_empty(&self->ring_buffer)) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
#else
|
||||
// check event queue to determine if a DMA buffer has been filled
|
||||
// (which is an indication that at least one DMA buffer is available to be read)
|
||||
// note: timeout = 0 so the call is non-blocking
|
||||
i2s_event_t i2s_event;
|
||||
if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) {
|
||||
if (i2s_event.type == I2S_EVENT_RX_DONE) {
|
||||
// getting here means that at least one DMA buffer is now full
|
||||
// indicating that audio samples can be read from the I2S object
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (flags & MP_STREAM_POLL_WR) {
|
||||
if (self->mode != MICROPY_PY_MACHINE_I2S_CONSTANT_TX) {
|
||||
*errcode = MP_EPERM;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2S_RING_BUF
|
||||
if (!ringbuf_is_full(&self->ring_buffer)) {
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
#else
|
||||
// check event queue to determine if a DMA buffer has been emptied
|
||||
// (which is an indication that at least one DMA buffer is available to be written)
|
||||
// note: timeout = 0 so the call is non-blocking
|
||||
i2s_event_t i2s_event;
|
||||
if (xQueueReceive(self->i2s_event_queue, &i2s_event, 0)) {
|
||||
if (i2s_event.type == I2S_EVENT_TX_DONE) {
|
||||
// getting here means that at least one DMA buffer is now empty
|
||||
// indicating that audio samples can be written to the I2S object
|
||||
ret |= MP_STREAM_POLL_WR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
*errcode = MP_EINVAL;
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC const mp_stream_p_t i2s_stream_p = {
|
||||
.read = machine_i2s_stream_read,
|
||||
.write = machine_i2s_stream_write,
|
||||
.ioctl = machine_i2s_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_i2s_type,
|
||||
MP_QSTR_I2S,
|
||||
MP_TYPE_FLAG_ITER_IS_STREAM,
|
||||
make_new, machine_i2s_make_new,
|
||||
print, machine_i2s_print,
|
||||
protocol, &i2s_stream_p,
|
||||
locals_dict, &machine_i2s_locals_dict
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2S
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/machine_mem.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct _machine_mem_obj_t {
|
||||
mp_obj_base_t base;
|
||||
unsigned elem_size; // in bytes
|
||||
} machine_mem_obj_t;
|
||||
|
||||
extern const mp_obj_type_t machine_mem_type;
|
||||
|
||||
extern const machine_mem_obj_t machine_mem8_obj;
|
||||
extern const machine_mem_obj_t machine_mem16_obj;
|
||||
extern const machine_mem_obj_t machine_mem32_obj;
|
||||
|
||||
#if defined(MICROPY_MACHINE_MEM_GET_READ_ADDR)
|
||||
uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align);
|
||||
#endif
|
||||
#if defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR)
|
||||
uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_MEM_H
|
|
@ -24,13 +24,12 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_PIN_BASE
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "extmod/virtpin.h"
|
||||
#include "extmod/machine_pinbase.h"
|
||||
|
||||
// PinBase class
|
||||
|
||||
|
@ -85,4 +84,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
|
|||
protocol, &pinbase_pin_p
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE
|
||||
#endif // MICROPY_PY_MACHINE_PIN_BASE
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
extern const mp_obj_type_t machine_pinbase_type;
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PINBASE_H
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "extmod/machine_pulse.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_PULSE
|
||||
|
||||
|
|
|
@ -28,11 +28,26 @@
|
|||
|
||||
#if MICROPY_PY_MACHINE_PWM
|
||||
|
||||
#include "extmod/machine_pwm.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
#ifdef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||
#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||
// The port must provide implementations of these low-level PWM functions.
|
||||
STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self);
|
||||
STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self);
|
||||
STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq);
|
||||
#if MICROPY_PY_MACHINE_PWM_DUTY
|
||||
STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self);
|
||||
STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty);
|
||||
#endif
|
||||
STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self);
|
||||
STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16);
|
||||
STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self);
|
||||
STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns);
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||
|
||||
STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
mp_machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// A port must provide this type, but it's otherwise opaque.
|
||||
typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
|
||||
|
||||
// This PWM class is implemented by machine_pwm.c.
|
||||
extern const mp_obj_type_t machine_pwm_type;
|
||||
|
||||
// A port must provide implementations of these low-level PWM functions, either as global
|
||||
// linker symbols, or included directly if MICROPY_PY_MACHINE_PWM_INCLUDEFILE is defined.
|
||||
#ifndef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||
void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
void mp_machine_pwm_deinit(machine_pwm_obj_t *self);
|
||||
mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self);
|
||||
void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq);
|
||||
mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self);
|
||||
void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty);
|
||||
mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self);
|
||||
void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16);
|
||||
mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self);
|
||||
void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
|
@ -29,10 +29,9 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/modmachine.h"
|
||||
#include "extmod/virtpin.h"
|
||||
#include "extmod/machine_signal.h"
|
||||
|
||||
// Signal class
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||
|
||||
#include "extmod/machine_spi.h"
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
// if a port didn't define MSB/LSB constants then provide them
|
||||
#ifndef MICROPY_PY_MACHINE_SPI_MSB
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/mphal.h"
|
||||
#include "drivers/bus/spi.h"
|
||||
|
||||
// Temporary support for legacy construction of SoftSPI via SPI type.
|
||||
#define MP_MACHINE_SPI_CHECK_FOR_LEGACY_SOFTSPI_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||
do { \
|
||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: SPI(-1, ...) is deprecated, use SoftSPI(...) instead\n"); \
|
||||
if (n_args != 0) { \
|
||||
--n_args; \
|
||||
++all_args; \
|
||||
} \
|
||||
return MP_OBJ_TYPE_GET_SLOT(&mp_machine_soft_spi_type, make_new)(&mp_machine_soft_spi_type, n_args, n_kw, all_args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// SPI protocol
|
||||
typedef struct _mp_machine_spi_p_t {
|
||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
void (*deinit)(mp_obj_base_t *obj); // can be NULL
|
||||
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
|
||||
} mp_machine_spi_p_t;
|
||||
|
||||
typedef struct _mp_machine_soft_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_soft_spi_obj_t spi;
|
||||
} mp_machine_soft_spi_obj_t;
|
||||
|
||||
extern const mp_machine_spi_p_t mp_machine_soft_spi_p;
|
||||
extern const mp_obj_type_t mp_machine_soft_spi_type;
|
||||
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
|
||||
|
||||
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj);
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "shared/runtime/mpirq.h"
|
||||
|
||||
// The port must provide implementations of these low-level UART functions.
|
||||
|
||||
STATIC void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
STATIC void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
STATIC void mp_machine_uart_deinit(machine_uart_obj_t *self);
|
||||
STATIC mp_int_t mp_machine_uart_any(machine_uart_obj_t *self);
|
||||
STATIC bool mp_machine_uart_txdone(machine_uart_obj_t *self);
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_SENDBREAK
|
||||
STATIC void mp_machine_uart_sendbreak(machine_uart_obj_t *self);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR
|
||||
STATIC mp_int_t mp_machine_uart_readchar(machine_uart_obj_t *self);
|
||||
STATIC void mp_machine_uart_writechar(machine_uart_obj_t *self, uint16_t data);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
STATIC mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args, mp_arg_val_t *args);
|
||||
#endif
|
||||
|
||||
STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode);
|
||||
STATIC mp_uint_t mp_machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode);
|
||||
STATIC mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_UART_INCLUDEFILE
|
||||
|
||||
// UART.init(...)
|
||||
STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
mp_machine_uart_init_helper(MP_OBJ_TO_PTR(args[0]), n_args - 1, args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
|
||||
|
||||
// UART.deinit()
|
||||
STATIC mp_obj_t machine_uart_deinit(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_uart_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_deinit_obj, machine_uart_deinit);
|
||||
|
||||
// UART.any()
|
||||
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_uart_any(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
|
||||
|
||||
// UART.txdone()
|
||||
STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_bool(mp_machine_uart_txdone(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone);
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_SENDBREAK
|
||||
|
||||
// UART.sendbreak()
|
||||
STATIC mp_obj_t machine_uart_sendbreak(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_uart_sendbreak(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_sendbreak_obj, machine_uart_sendbreak);
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR
|
||||
|
||||
// UART.readchar()
|
||||
STATIC mp_obj_t machine_uart_readchar(mp_obj_t self_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_uart_readchar(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_readchar_obj, machine_uart_readchar);
|
||||
|
||||
// UART.writechar(char)
|
||||
STATIC mp_obj_t machine_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_uart_writechar(self, mp_obj_get_int(char_in));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_uart_writechar_obj, machine_uart_writechar);
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
|
||||
// UART.irq(handler, trigger, hard)
|
||||
STATIC mp_obj_t machine_uart_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
machine_uart_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
bool any_args = n_args > 1 || kw_args->used != 0;
|
||||
return MP_OBJ_FROM_PTR(mp_machine_uart_irq(self, any_args, args));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_irq_obj, 1, machine_uart_irq);
|
||||
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_uart_deinit_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_txdone), MP_ROM_PTR(&machine_uart_txdone_obj) },
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_SENDBREAK
|
||||
{ MP_ROM_QSTR(MP_QSTR_sendbreak), MP_ROM_PTR(&machine_uart_sendbreak_obj) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR
|
||||
{ MP_ROM_QSTR(MP_QSTR_readchar), MP_ROM_PTR(&machine_uart_readchar_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_writechar), MP_ROM_PTR(&machine_uart_writechar_obj) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_UART_IRQ
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_uart_irq_obj) },
|
||||
#endif
|
||||
|
||||
// A port must add UART class constants defining the following macro.
|
||||
// It can be defined to nothing if there are no constants.
|
||||
MICROPY_PY_MACHINE_UART_CLASS_CONSTANTS
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
|
||||
|
||||
STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.read = mp_machine_uart_read,
|
||||
.write = mp_machine_uart_write,
|
||||
.ioctl = mp_machine_uart_ioctl,
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_uart_type,
|
||||
MP_QSTR_UART,
|
||||
MP_TYPE_FLAG_ITER_IS_STREAM,
|
||||
make_new, mp_machine_uart_make_new,
|
||||
print, mp_machine_uart_print,
|
||||
protocol, &uart_stream_p,
|
||||
locals_dict, &machine_uart_locals_dict
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_UART
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_WDT
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
|
||||
// The port must provide implementations of these low-level WDT functions.
|
||||
STATIC machine_wdt_obj_t *mp_machine_wdt_make_new_instance(mp_int_t id, mp_int_t timeout_ms);
|
||||
STATIC void mp_machine_wdt_feed(machine_wdt_obj_t *self);
|
||||
#if MICROPY_PY_MACHINE_WDT_TIMEOUT_MS
|
||||
STATIC void mp_machine_wdt_timeout_ms_set(machine_wdt_obj_t *self_in, mp_int_t timeout_ms);
|
||||
#endif
|
||||
|
||||
// The port provides implementations of the above in this file.
|
||||
#include MICROPY_PY_MACHINE_WDT_INCLUDEFILE
|
||||
|
||||
STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
enum { ARG_id, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} },
|
||||
};
|
||||
|
||||
// Parse the arguments.
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Create WDT instance.
|
||||
machine_wdt_obj_t *self = mp_machine_wdt_make_new_instance(args[ARG_id].u_int, args[ARG_timeout].u_int);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
// WDT.feed()
|
||||
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
|
||||
machine_wdt_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_machine_wdt_feed(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
|
||||
|
||||
#if MICROPY_PY_MACHINE_WDT_TIMEOUT_MS
|
||||
// WDT.timeout_ms(timeout)
|
||||
STATIC mp_obj_t machine_wdt_timeout_ms(mp_obj_t self_in, mp_obj_t timeout_in) {
|
||||
machine_wdt_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t timeout_ms = mp_obj_get_int(timeout_in);
|
||||
mp_machine_wdt_timeout_ms_set(self, timeout_ms);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_wdt_timeout_ms_obj, machine_wdt_timeout_ms);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
|
||||
#if MICROPY_PY_MACHINE_WDT_TIMEOUT_MS
|
||||
{ MP_ROM_QSTR(MP_QSTR_timeout_ms), MP_ROM_PTR(&machine_wdt_timeout_ms_obj) },
|
||||
#endif
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_wdt_type,
|
||||
MP_QSTR_WDT,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, machine_wdt_make_new,
|
||||
locals_dict, &machine_wdt_locals_dict
|
||||
);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_WDT
|
|
@ -31,6 +31,8 @@
|
|||
// #define MBEDTLS_DEBUG_C
|
||||
|
||||
// Set mbedtls configuration.
|
||||
#define MBEDTLS_HAVE_TIME
|
||||
#define MBEDTLS_HAVE_TIME_DATE
|
||||
#define MBEDTLS_DEPRECATED_REMOVED
|
||||
#define MBEDTLS_AES_ROM_TABLES
|
||||
#define MBEDTLS_CIPHER_MODE_CBC
|
||||
|
|
|
@ -39,10 +39,12 @@ bool mp_os_dupterm_is_builtin_stream(mp_const_obj_t stream);
|
|||
void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached);
|
||||
uintptr_t mp_os_dupterm_poll(uintptr_t poll_flags);
|
||||
int mp_os_dupterm_rx_chr(void);
|
||||
void mp_os_dupterm_tx_strn(const char *str, size_t len);
|
||||
int mp_os_dupterm_tx_strn(const char *str, size_t len);
|
||||
void mp_os_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
|
||||
#else
|
||||
#define mp_os_dupterm_tx_strn(s, l)
|
||||
static inline int mp_os_dupterm_tx_strn(const char *s, size_t l) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MISC_H
|
||||
|
|
|
@ -1276,6 +1276,7 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
|
|||
mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan
|
||||
mp_stack_set_limit(MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE - 1024);
|
||||
ts.gc_lock_depth = 0;
|
||||
ts.nlr_jump_callback_top = NULL;
|
||||
ts.mp_pending_exception = MP_OBJ_NULL;
|
||||
mp_locals_set(mp_state_ctx.thread.dict_locals); // set from the outer context
|
||||
mp_globals_set(mp_state_ctx.thread.dict_globals); // set from the outer context
|
||||
|
|
|
@ -273,42 +273,59 @@ STATIC void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, u
|
|||
STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
mp_arg_check_num(n_args, n_kw, 4, 5, false);
|
||||
|
||||
mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, type);
|
||||
o->buf_obj = args_in[0];
|
||||
mp_int_t width = mp_obj_get_int(args_in[1]);
|
||||
mp_int_t height = mp_obj_get_int(args_in[2]);
|
||||
mp_int_t format = mp_obj_get_int(args_in[3]);
|
||||
mp_int_t stride = n_args >= 5 ? mp_obj_get_int(args_in[4]) : width;
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
o->buf = bufinfo.buf;
|
||||
|
||||
o->width = mp_obj_get_int(args_in[1]);
|
||||
o->height = mp_obj_get_int(args_in[2]);
|
||||
o->format = mp_obj_get_int(args_in[3]);
|
||||
if (n_args >= 5) {
|
||||
o->stride = mp_obj_get_int(args_in[4]);
|
||||
} else {
|
||||
o->stride = o->width;
|
||||
if (width < 1 || height < 1 || width > 0xffff || height > 0xffff || stride > 0xffff || stride < width) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
switch (o->format) {
|
||||
size_t height_required = height;
|
||||
size_t bpp = 1;
|
||||
|
||||
switch (format) {
|
||||
case FRAMEBUF_MVLSB:
|
||||
case FRAMEBUF_RGB565:
|
||||
height_required = (height + 7) & ~7;
|
||||
break;
|
||||
case FRAMEBUF_MHLSB:
|
||||
case FRAMEBUF_MHMSB:
|
||||
o->stride = (o->stride + 7) & ~7;
|
||||
stride = (stride + 7) & ~7;
|
||||
break;
|
||||
case FRAMEBUF_GS2_HMSB:
|
||||
o->stride = (o->stride + 3) & ~3;
|
||||
stride = (stride + 3) & ~3;
|
||||
bpp = 2;
|
||||
break;
|
||||
case FRAMEBUF_GS4_HMSB:
|
||||
o->stride = (o->stride + 1) & ~1;
|
||||
stride = (stride + 1) & ~1;
|
||||
bpp = 4;
|
||||
break;
|
||||
case FRAMEBUF_GS8:
|
||||
bpp = 8;
|
||||
break;
|
||||
case FRAMEBUF_RGB565:
|
||||
bpp = 16;
|
||||
break;
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
|
||||
}
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
if (height_required * stride * bpp / 8 > bufinfo.len) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, type);
|
||||
o->buf_obj = args_in[0];
|
||||
o->buf = bufinfo.buf;
|
||||
o->width = width;
|
||||
o->height = height;
|
||||
o->format = format;
|
||||
o->stride = stride;
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
|
@ -319,12 +336,8 @@ STATIC void framebuf_args(const mp_obj_t *args_in, mp_int_t *args_out, int n) {
|
|||
}
|
||||
|
||||
STATIC mp_int_t framebuf_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||
(void)flags;
|
||||
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
bufinfo->buf = self->buf;
|
||||
bufinfo->len = self->stride * self->height * (self->format == FRAMEBUF_RGB565 ? 2 : 1);
|
||||
bufinfo->typecode = 'B'; // view framebuf as bytes
|
||||
return 0;
|
||||
return mp_get_buffer(self->buf_obj, bufinfo, flags) ? 0 : 1;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {
|
||||
|
@ -851,28 +864,15 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
|||
);
|
||||
#endif
|
||||
|
||||
// this factory function is provided for backwards compatibility with old FrameBuffer1 class
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
// This factory function is provided for backwards compatibility with the old
|
||||
// FrameBuffer1 class which did not support a format argument.
|
||||
STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args_in) {
|
||||
mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, (mp_obj_type_t *)&mp_type_framebuf);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
o->buf = bufinfo.buf;
|
||||
|
||||
o->width = mp_obj_get_int(args_in[1]);
|
||||
o->height = mp_obj_get_int(args_in[2]);
|
||||
o->format = FRAMEBUF_MVLSB;
|
||||
if (n_args >= 4) {
|
||||
o->stride = mp_obj_get_int(args_in[3]);
|
||||
} else {
|
||||
o->stride = o->width;
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
mp_obj_t args[] = {args_in[0], args_in[1], args_in[2], MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB), n_args >= 4 ? args_in[3] : args_in[1] };
|
||||
return framebuf_make_new(&mp_type_framebuf, 5, 0, args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1);
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) },
|
||||
|
|
|
@ -297,7 +297,7 @@ STATIC mp_obj_t hashlib_md5_digest(mp_obj_t self_in) {
|
|||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#define mbedtls_md5_starts_ret mbedtls_md5_starts
|
||||
#define mbedtls_md5_update_ret mbedtls_md5_update
|
||||
#define mbedtls_md5_finish_ret mbedtls_md5_finish
|
||||
|
|
|
@ -318,11 +318,7 @@ typedef struct _lwip_socket_obj_t {
|
|||
} lwip_socket_obj_t;
|
||||
|
||||
static inline void poll_sockets(void) {
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK;
|
||||
#else
|
||||
mp_hal_delay_ms(1);
|
||||
#endif
|
||||
mp_event_wait_ms(1);
|
||||
}
|
||||
|
||||
STATIC struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *socket) {
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "shared/runtime/pyexec.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE_DHT_READINTO
|
||||
#include "drivers/dht/dht.h"
|
||||
#endif
|
||||
|
||||
// The port must provide implementations of these low-level machine functions.
|
||||
|
||||
STATIC void mp_machine_idle(void);
|
||||
|
||||
#if MICROPY_PY_MACHINE_BOOTLOADER
|
||||
NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_BARE_METAL_FUNCS
|
||||
STATIC mp_obj_t mp_machine_unique_id(void);
|
||||
NORETURN STATIC void mp_machine_reset(void);
|
||||
STATIC mp_int_t mp_machine_reset_cause(void);
|
||||
STATIC mp_obj_t mp_machine_get_freq(void);
|
||||
STATIC void mp_machine_set_freq(size_t n_args, const mp_obj_t *args);
|
||||
STATIC void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args);
|
||||
NORETURN STATIC void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
|
||||
#endif
|
||||
|
||||
// The port can provide additional machine-module implementation in this file.
|
||||
#ifdef MICROPY_PY_MACHINE_INCLUDEFILE
|
||||
#include MICROPY_PY_MACHINE_INCLUDEFILE
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t machine_soft_reset(void) {
|
||||
pyexec_system_exit = PYEXEC_FORCED_EXIT;
|
||||
mp_raise_type(&mp_type_SystemExit);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset);
|
||||
|
||||
#if MICROPY_PY_MACHINE_BOOTLOADER
|
||||
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
mp_machine_bootloader(n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
mp_machine_idle();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
#if MICROPY_PY_MACHINE_BARE_METAL_FUNCS
|
||||
|
||||
STATIC mp_obj_t machine_unique_id(void) {
|
||||
return mp_machine_unique_id();
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
NORETURN STATIC mp_obj_t machine_reset(void) {
|
||||
mp_machine_reset();
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
||||
STATIC mp_obj_t machine_reset_cause(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_reset_cause());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
return mp_machine_get_freq();
|
||||
} else {
|
||||
mp_machine_set_freq(n_args, args);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq);
|
||||
|
||||
STATIC mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) {
|
||||
mp_machine_lightsleep(n_args, args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep);
|
||||
|
||||
NORETURN STATIC mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
|
||||
mp_machine_deepsleep(n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep);
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_DISABLE_IRQ_ENABLE_IRQ
|
||||
|
||||
STATIC mp_obj_t machine_disable_irq(void) {
|
||||
uint32_t state = MICROPY_BEGIN_ATOMIC_SECTION();
|
||||
return mp_obj_new_int(state);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
|
||||
|
||||
STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
|
||||
uint32_t state = mp_obj_get_int(state_in);
|
||||
MICROPY_END_ATOMIC_SECTION(state);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
|
||||
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
|
||||
|
||||
// Memory access objects.
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
|
||||
|
||||
// Miscellaneous functions.
|
||||
#if MICROPY_PY_MACHINE_BARE_METAL_FUNCS
|
||||
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
|
||||
#endif
|
||||
|
||||
// Reset related functions.
|
||||
{ MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) },
|
||||
#if MICROPY_PY_MACHINE_BOOTLOADER
|
||||
{ MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_BARE_METAL_FUNCS
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
|
||||
#endif
|
||||
|
||||
// Power related functions.
|
||||
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
|
||||
#if MICROPY_PY_MACHINE_BARE_METAL_FUNCS
|
||||
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
|
||||
#endif
|
||||
|
||||
// Interrupt related functions.
|
||||
#if MICROPY_PY_MACHINE_DISABLE_IRQ_ENABLE_IRQ
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
|
||||
#endif
|
||||
|
||||
// Functions for bit protocols.
|
||||
#if MICROPY_PY_MACHINE_BITSTREAM
|
||||
{ MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_DHT_READINTO
|
||||
{ MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_PULSE
|
||||
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
|
||||
#endif
|
||||
|
||||
// Classes for PinBase and Signal.
|
||||
#if MICROPY_PY_MACHINE_PIN_BASE
|
||||
{ MP_ROM_QSTR(MP_QSTR_PinBase), MP_ROM_PTR(&machine_pinbase_type) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
|
||||
// Classes for software bus protocols.
|
||||
#if MICROPY_PY_MACHINE_SOFTI2C
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_SOFTSPI
|
||||
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
|
||||
#endif
|
||||
|
||||
// Classes for hardware peripherals.
|
||||
#if MICROPY_PY_MACHINE_ADC
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADCBlock), MP_ROM_PTR(&machine_adc_block_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_DAC
|
||||
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_I2C
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_I2S
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_PWM
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_SPI
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_UART
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_WDT
|
||||
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
|
||||
#endif
|
||||
|
||||
// A port can add extra entries to the module by defining the following macro.
|
||||
#ifdef MICROPY_PY_MACHINE_EXTRA_GLOBALS
|
||||
MICROPY_PY_MACHINE_EXTRA_GLOBALS
|
||||
#endif
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_machine = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&machine_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
|
||||
|
||||
#endif // MICROPY_PY_MACHINE
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MODMACHINE_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MODMACHINE_H
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
#include "drivers/bus/spi.h"
|
||||
|
||||
// Whether to enable the ADC.init() method.
|
||||
// Requires a port to implement mp_machine_adc_init_helper().
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_INIT
|
||||
#define MICROPY_PY_MACHINE_ADC_INIT (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the ADC.deinit() method.
|
||||
// Requires a port to implement mp_machine_adc_deinit().
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_DEINIT
|
||||
#define MICROPY_PY_MACHINE_ADC_DEINIT (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the ADC.block() method.
|
||||
// Requires a port to implement mp_machine_adc_block().
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_BLOCK
|
||||
#define MICROPY_PY_MACHINE_ADC_BLOCK (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the ADC.read_uv() method.
|
||||
// Requires a port to implement mp_machine_adc_read_uv().
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_READ_UV
|
||||
#define MICROPY_PY_MACHINE_ADC_READ_UV (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the ADC.atten() and ADC.width() methods.
|
||||
// Note: these are legacy and should not be used on new ports.
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH
|
||||
#define MICROPY_PY_MACHINE_ADC_ATTEN_WIDTH (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the ADC.read() method.
|
||||
// Note: this is legacy and should not be used on new ports.
|
||||
#ifndef MICROPY_PY_MACHINE_ADC_READ
|
||||
#define MICROPY_PY_MACHINE_ADC_READ (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the UART.sendbreak() method.
|
||||
// Requires a port to implement mp_machine_uart_sendbreak().
|
||||
#ifndef MICROPY_PY_MACHINE_UART_SENDBREAK
|
||||
#define MICROPY_PY_MACHINE_UART_SENDBREAK (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the UART.readchar() and UART.writechar() methods.
|
||||
// Requires a port to implement mp_machine_uart_readchar() and mp_machine_uart_writechar().
|
||||
#ifndef MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR
|
||||
#define MICROPY_PY_MACHINE_UART_READCHAR_WRITECHAR (0)
|
||||
#endif
|
||||
|
||||
// Whether to enable the UART.irq() method.
|
||||
// Requires a port to implement mp_machine_uart_irq().
|
||||
#ifndef MICROPY_PY_MACHINE_UART_IRQ
|
||||
#define MICROPY_PY_MACHINE_UART_IRQ (0)
|
||||
#endif
|
||||
|
||||
// Temporary support for legacy construction of SoftI2C via I2C type.
|
||||
#define MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||
do { \
|
||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead\n"); \
|
||||
if (n_args != 0) { \
|
||||
--n_args; \
|
||||
++all_args; \
|
||||
} \
|
||||
return MP_OBJ_TYPE_GET_SLOT(&mp_machine_soft_i2c_type, make_new)(&mp_machine_soft_i2c_type, n_args, n_kw, all_args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Temporary support for legacy construction of SoftSPI via SPI type.
|
||||
#define MP_MACHINE_SPI_CHECK_FOR_LEGACY_SOFTSPI_CONSTRUCTION(n_args, n_kw, all_args) \
|
||||
do { \
|
||||
if (n_args == 0 || all_args[0] == MP_OBJ_NEW_SMALL_INT(-1)) { \
|
||||
mp_print_str(MICROPY_ERROR_PRINTER, "Warning: SPI(-1, ...) is deprecated, use SoftSPI(...) instead\n"); \
|
||||
if (n_args != 0) { \
|
||||
--n_args; \
|
||||
++all_args; \
|
||||
} \
|
||||
return MP_OBJ_TYPE_GET_SLOT(&mp_machine_soft_spi_type, make_new)(&mp_machine_soft_spi_type, n_args, n_kw, all_args); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||
|
||||
#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write
|
||||
#define MP_MACHINE_I2C_FLAG_STOP (0x02)
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
||||
// If set, the first mp_machine_i2c_buf_t in a transfer is a write.
|
||||
#define MP_MACHINE_I2C_FLAG_WRITE1 (0x04)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// A port must provide these types, but they are otherwise opaque.
|
||||
typedef struct _machine_adc_obj_t machine_adc_obj_t;
|
||||
typedef struct _machine_adc_block_obj_t machine_adc_block_obj_t;
|
||||
typedef struct _machine_i2s_obj_t machine_i2s_obj_t;
|
||||
typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
|
||||
typedef struct _machine_uart_obj_t machine_uart_obj_t;
|
||||
typedef struct _machine_wdt_obj_t machine_wdt_obj_t;
|
||||
|
||||
typedef struct _machine_mem_obj_t {
|
||||
mp_obj_base_t base;
|
||||
unsigned elem_size; // in bytes
|
||||
} machine_mem_obj_t;
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||
|
||||
typedef struct _mp_machine_i2c_buf_t {
|
||||
size_t len;
|
||||
uint8_t *buf;
|
||||
} mp_machine_i2c_buf_t;
|
||||
|
||||
// I2C protocol:
|
||||
// - init must be non-NULL
|
||||
// - start/stop/read/write can be NULL, meaning operation is not supported
|
||||
// - transfer must be non-NULL
|
||||
// - transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
|
||||
typedef struct _mp_machine_i2c_p_t {
|
||||
#if MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1
|
||||
bool transfer_supports_write1;
|
||||
#endif
|
||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
int (*start)(mp_obj_base_t *obj);
|
||||
int (*stop)(mp_obj_base_t *obj);
|
||||
int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);
|
||||
int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len);
|
||||
int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags);
|
||||
} mp_machine_i2c_p_t;
|
||||
|
||||
// SoftI2C object.
|
||||
typedef struct _mp_machine_soft_i2c_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t us_delay;
|
||||
uint32_t us_timeout;
|
||||
mp_hal_pin_obj_t scl;
|
||||
mp_hal_pin_obj_t sda;
|
||||
} mp_machine_soft_i2c_obj_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||
|
||||
// SPI protocol.
|
||||
typedef struct _mp_machine_spi_p_t {
|
||||
void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
void (*deinit)(mp_obj_base_t *obj); // can be NULL
|
||||
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
|
||||
} mp_machine_spi_p_t;
|
||||
|
||||
// SoftSPI object.
|
||||
typedef struct _mp_machine_soft_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_soft_spi_obj_t spi;
|
||||
} mp_machine_soft_spi_obj_t;
|
||||
|
||||
#endif
|
||||
|
||||
// Objects for machine.mem8, machine.mem16 and machine.mem32.
|
||||
extern const machine_mem_obj_t machine_mem8_obj;
|
||||
extern const machine_mem_obj_t machine_mem16_obj;
|
||||
extern const machine_mem_obj_t machine_mem32_obj;
|
||||
|
||||
// These classes correspond to machine.Type entries in the machine module.
|
||||
// Their Python bindings are implemented in extmod, and their implementation
|
||||
// is provided by a port.
|
||||
extern const mp_obj_type_t machine_adc_type;
|
||||
extern const mp_obj_type_t machine_adc_block_type;
|
||||
extern const mp_obj_type_t machine_i2c_type;
|
||||
extern const mp_obj_type_t machine_i2s_type;
|
||||
extern const mp_obj_type_t machine_mem_type;
|
||||
extern const mp_obj_type_t machine_pin_type;
|
||||
extern const mp_obj_type_t machine_pinbase_type;
|
||||
extern const mp_obj_type_t machine_pwm_type;
|
||||
extern const mp_obj_type_t machine_rtc_type;
|
||||
extern const mp_obj_type_t machine_signal_type;
|
||||
extern const mp_obj_type_t machine_spi_type;
|
||||
extern const mp_obj_type_t machine_timer_type;
|
||||
extern const mp_obj_type_t machine_uart_type;
|
||||
extern const mp_obj_type_t machine_wdt_type;
|
||||
|
||||
#if MICROPY_PY_MACHINE_SOFTI2C
|
||||
extern const mp_obj_type_t mp_machine_soft_i2c_type;
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||
extern const mp_obj_dict_t mp_machine_i2c_locals_dict;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_SOFTSPI
|
||||
extern const mp_obj_type_t mp_machine_soft_spi_type;
|
||||
extern const mp_machine_spi_p_t mp_machine_soft_spi_p;
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_MACHINE_MEM_GET_READ_ADDR)
|
||||
uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align);
|
||||
#endif
|
||||
#if defined(MICROPY_MACHINE_MEM_GET_WRITE_ADDR)
|
||||
uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align);
|
||||
#endif
|
||||
|
||||
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len);
|
||||
mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_cause_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bitstream_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj);
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C
|
||||
int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_SPI
|
||||
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_MACHINE
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MODMACHINE_H
|
|
@ -65,6 +65,15 @@ void mod_network_init(void) {
|
|||
}
|
||||
|
||||
void mod_network_deinit(void) {
|
||||
#if !MICROPY_PY_LWIP
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
|
||||
mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
|
||||
const mod_network_nic_protocol_t *nic_protocol = MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(nic), protocol);
|
||||
if (nic_protocol->deinit) {
|
||||
nic_protocol->deinit();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void mod_network_register_nic(mp_obj_t nic) {
|
||||
|
|
|
@ -80,6 +80,7 @@ struct _mod_network_socket_obj_t;
|
|||
typedef struct _mod_network_nic_protocol_t {
|
||||
// API for non-socket operations
|
||||
int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
|
||||
void (*deinit)(void);
|
||||
|
||||
// API for socket operations; return -1 on error
|
||||
int (*socket)(struct _mod_network_socket_obj_t *socket, int *_errno);
|
||||
|
|
|
@ -38,11 +38,11 @@
|
|||
#define TIMING_RESET1 (480)
|
||||
#define TIMING_RESET2 (70)
|
||||
#define TIMING_RESET3 (410)
|
||||
#define TIMING_READ1 (5)
|
||||
#define TIMING_READ2 (5)
|
||||
#define TIMING_READ3 (40)
|
||||
#define TIMING_WRITE1 (10)
|
||||
#define TIMING_WRITE2 (50)
|
||||
#define TIMING_READ1 (6)
|
||||
#define TIMING_READ2 (9)
|
||||
#define TIMING_READ3 (55)
|
||||
#define TIMING_WRITE1 (6)
|
||||
#define TIMING_WRITE2 (54)
|
||||
#define TIMING_WRITE3 (10)
|
||||
|
||||
STATIC int onewire_bus_reset(mp_hal_pin_obj_t pin) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
|
@ -48,6 +49,13 @@
|
|||
#include "extmod/vfs_posix.h"
|
||||
#endif
|
||||
|
||||
#if MICROPY_MBFS
|
||||
#if MICROPY_VFS
|
||||
#error "MICROPY_MBFS requires MICROPY_VFS to be disabled"
|
||||
#endif
|
||||
#include "ports/nrf/modules/os/microbitfs.h"
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_OS_UNAME
|
||||
#include "genhdr/mpversion.h"
|
||||
#endif
|
||||
|
@ -121,6 +129,21 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_os_uname_obj, mp_os_uname);
|
|||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_OS_DUPTERM_NOTIFY
|
||||
STATIC mp_obj_t mp_os_dupterm_notify(mp_obj_t obj_in) {
|
||||
(void)obj_in;
|
||||
for (;;) {
|
||||
int c = mp_os_dupterm_rx_chr();
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
ringbuf_put(&stdin_ringbuf, c);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_dupterm_notify_obj, mp_os_dupterm_notify);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
|
||||
|
||||
|
@ -187,6 +210,14 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_MBFS
|
||||
// For special micro:bit filesystem only.
|
||||
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&os_mbfs_listdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&os_mbfs_ilistdir_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_mbfs_stat_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_mbfs_remove_obj) },
|
||||
#endif
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
|
|
|
@ -207,12 +207,12 @@ STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
|||
subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||
subj.end = subj.begin + len;
|
||||
int caps_num = (self->re.sub + 1) * 2;
|
||||
mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char *, caps_num);
|
||||
mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, caps, char *, caps_num);
|
||||
// cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
|
||||
memset((char *)match->caps, 0, caps_num * sizeof(char *));
|
||||
int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
|
||||
if (res == 0) {
|
||||
m_del_var(mp_obj_match_t, char *, caps_num, match);
|
||||
m_del_var(mp_obj_match_t, caps, char *, caps_num, match);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if !((MP_STREAM_POLL_RD) == (POLLIN) && \
|
||||
|
@ -142,14 +143,47 @@ STATIC void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) {
|
|||
}
|
||||
}
|
||||
|
||||
// How much (in pollfds) to grow the allocation for poll_set->pollfds by.
|
||||
#define POLL_SET_ALLOC_INCREMENT (4)
|
||||
|
||||
STATIC struct pollfd *poll_set_add_fd(poll_set_t *poll_set, int fd) {
|
||||
struct pollfd *free_slot = NULL;
|
||||
|
||||
if (poll_set->used == poll_set->max_used) {
|
||||
// No free slots below max_used, so expand max_used (and possibly allocate).
|
||||
if (poll_set->max_used >= poll_set->alloc) {
|
||||
poll_set->pollfds = m_renew(struct pollfd, poll_set->pollfds, poll_set->alloc, poll_set->alloc + 4);
|
||||
poll_set->alloc += 4;
|
||||
size_t new_alloc = poll_set->alloc + POLL_SET_ALLOC_INCREMENT;
|
||||
// Try to grow in-place.
|
||||
struct pollfd *new_fds = m_renew_maybe(struct pollfd, poll_set->pollfds, poll_set->alloc, new_alloc, false);
|
||||
if (!new_fds) {
|
||||
// Failed to grow in-place. Do a new allocation and copy over the pollfd values.
|
||||
new_fds = m_new(struct pollfd, new_alloc);
|
||||
memcpy(new_fds, poll_set->pollfds, sizeof(struct pollfd) * poll_set->alloc);
|
||||
|
||||
// Update existing poll_obj_t to update their pollfd field to
|
||||
// point to the same offset inside the new allocation.
|
||||
for (mp_uint_t i = 0; i < poll_set->map.alloc; ++i) {
|
||||
if (!mp_map_slot_is_filled(&poll_set->map, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set->map.table[i].value);
|
||||
if (!poll_obj) {
|
||||
// This is the one we're currently adding,
|
||||
// poll_set_add_obj doesn't assign elem->value until
|
||||
// afterwards.
|
||||
continue;
|
||||
}
|
||||
|
||||
poll_obj->pollfd = new_fds + (poll_obj->pollfd - poll_set->pollfds);
|
||||
}
|
||||
|
||||
// Delete the old allocation.
|
||||
m_del(struct pollfd, poll_set->pollfds, poll_set->alloc);
|
||||
}
|
||||
|
||||
poll_set->pollfds = new_fds;
|
||||
poll_set->alloc = new_alloc;
|
||||
}
|
||||
free_slot = &poll_set->pollfds[poll_set->max_used++];
|
||||
} else {
|
||||
|
@ -306,6 +340,7 @@ STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) {
|
|||
|
||||
STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size_t *rwx_num, mp_uint_t timeout) {
|
||||
mp_uint_t start_ticks = mp_hal_ticks_ms();
|
||||
bool has_timeout = timeout != (mp_uint_t)-1;
|
||||
|
||||
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||
|
||||
|
@ -350,12 +385,12 @@ STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size
|
|||
}
|
||||
|
||||
// Return if an object is ready, or if the timeout expired.
|
||||
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) {
|
||||
if (n_ready > 0 || (has_timeout && mp_hal_ticks_ms() - start_ticks >= timeout)) {
|
||||
return n_ready;
|
||||
}
|
||||
|
||||
// This would be MICROPY_EVENT_POLL_HOOK but the call to poll() above already includes a delay.
|
||||
mp_handle_pending(true);
|
||||
// This would be mp_event_wait_ms() but the call to poll() above already includes a delay.
|
||||
mp_event_handle_nowait();
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -363,10 +398,15 @@ STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size
|
|||
for (;;) {
|
||||
// poll the objects
|
||||
mp_uint_t n_ready = poll_set_poll_once(poll_set, rwx_num);
|
||||
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) {
|
||||
uint32_t elapsed = mp_hal_ticks_ms() - start_ticks;
|
||||
if (n_ready > 0 || (has_timeout && elapsed >= timeout)) {
|
||||
return n_ready;
|
||||
}
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
if (has_timeout) {
|
||||
mp_event_wait_ms(timeout - elapsed);
|
||||
} else {
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/reader.h"
|
||||
#include "extmod/vfs.h"
|
||||
|
||||
// mbedtls_time_t
|
||||
#include "mbedtls/platform.h"
|
||||
|
@ -46,6 +48,11 @@
|
|||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/error.h"
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#include "mbedtls/build_info.h"
|
||||
#else
|
||||
#include "mbedtls/version.h"
|
||||
#endif
|
||||
|
||||
#define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)
|
||||
|
||||
|
@ -59,6 +66,7 @@ typedef struct _mp_obj_ssl_context_t {
|
|||
mbedtls_x509_crt cert;
|
||||
mbedtls_pk_context pkey;
|
||||
int authmode;
|
||||
int *ciphersuites;
|
||||
} mp_obj_ssl_context_t;
|
||||
|
||||
// This corresponds to an SSLSocket object.
|
||||
|
@ -75,12 +83,32 @@ typedef struct _mp_obj_ssl_socket_t {
|
|||
STATIC const mp_obj_type_t ssl_context_type;
|
||||
STATIC const mp_obj_type_t ssl_socket_type;
|
||||
|
||||
STATIC const MP_DEFINE_STR_OBJ(mbedtls_version_obj, MBEDTLS_VERSION_STRING_FULL);
|
||||
|
||||
STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
|
||||
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname);
|
||||
|
||||
/******************************************************************************/
|
||||
// Helper functions.
|
||||
|
||||
STATIC mp_obj_t read_file(mp_obj_t self_in) {
|
||||
// file = open(args[0], "rb")
|
||||
mp_obj_t f_args[2] = {
|
||||
self_in,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
|
||||
};
|
||||
mp_obj_t file = mp_vfs_open(2, &f_args[0], (mp_map_t *)&mp_const_empty_map);
|
||||
|
||||
// data = file.read()
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method(file, MP_QSTR_read, dest);
|
||||
mp_obj_t data = mp_call_method_n_kw(0, 0, dest);
|
||||
|
||||
// file.close()
|
||||
mp_stream_close(file);
|
||||
return data;
|
||||
}
|
||||
|
||||
#ifdef MBEDTLS_DEBUG_C
|
||||
STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
|
||||
(void)ctx;
|
||||
|
@ -138,6 +166,46 @@ STATIC NORETURN void mbedtls_raise_error(int err) {
|
|||
#endif
|
||||
}
|
||||
|
||||
STATIC void ssl_check_async_handshake_failure(mp_obj_ssl_socket_t *sslsock, int *errcode) {
|
||||
if (
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
(*errcode < 0) && (mbedtls_ssl_is_handshake_over(&sslsock->ssl) == 0) && (*errcode != MBEDTLS_ERR_SSL_CONN_EOF)
|
||||
#else
|
||||
(*errcode < 0) && (*errcode != MBEDTLS_ERR_SSL_CONN_EOF)
|
||||
#endif
|
||||
) {
|
||||
// Asynchronous handshake is done by mbdetls_ssl_read/write. If the return code is
|
||||
// MBEDTLS_ERR_XX (i.e < 0) and the handshake is not done due to a handshake failure,
|
||||
// then notify peer with proper error code and raise local error with mbedtls_raise_error.
|
||||
|
||||
if (*errcode == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) {
|
||||
// Check if TLSv1.3 and use proper alert for this case (to be implemented)
|
||||
// uint8_t alert = MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED; tlsv1.3
|
||||
// uint8_t alert = MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE; tlsv1.2
|
||||
mbedtls_ssl_send_alert_message(&sslsock->ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
|
||||
MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE);
|
||||
}
|
||||
|
||||
if (*errcode == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
||||
// The certificate may have been rejected for several reasons.
|
||||
char xcbuf[256];
|
||||
uint32_t flags = mbedtls_ssl_get_verify_result(&sslsock->ssl);
|
||||
int ret = mbedtls_x509_crt_verify_info(xcbuf, sizeof(xcbuf), "\n", flags);
|
||||
// The length of the string written (not including the terminated nul byte),
|
||||
// or a negative err code.
|
||||
if (ret > 0) {
|
||||
sslsock->sock = MP_OBJ_NULL;
|
||||
mbedtls_ssl_free(&sslsock->ssl);
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%s"), xcbuf);
|
||||
}
|
||||
}
|
||||
|
||||
sslsock->sock = MP_OBJ_NULL;
|
||||
mbedtls_ssl_free(&sslsock->ssl);
|
||||
mbedtls_raise_error(*errcode);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// SSLContext type.
|
||||
|
||||
|
@ -162,6 +230,7 @@ STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
|
|||
mbedtls_x509_crt_init(&self->cacert);
|
||||
mbedtls_x509_crt_init(&self->cert);
|
||||
mbedtls_pk_init(&self->pkey);
|
||||
self->ciphersuites = NULL;
|
||||
|
||||
#ifdef MBEDTLS_DEBUG_C
|
||||
// Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose
|
||||
|
@ -236,6 +305,52 @@ STATIC mp_obj_t ssl_context___del__(mp_obj_t self_in) {
|
|||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_context___del___obj, ssl_context___del__);
|
||||
#endif
|
||||
|
||||
// SSLContext.get_ciphers()
|
||||
STATIC mp_obj_t ssl_context_get_ciphers(mp_obj_t self_in) {
|
||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
||||
for (const int *cipher_list = mbedtls_ssl_list_ciphersuites(); *cipher_list; ++cipher_list) {
|
||||
const char *cipher_name = mbedtls_ssl_get_ciphersuite_name(*cipher_list);
|
||||
mp_obj_list_append(list, MP_OBJ_FROM_PTR(mp_obj_new_str(cipher_name, strlen(cipher_name))));
|
||||
cipher_list++;
|
||||
if (!*cipher_list) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_context_get_ciphers_obj, ssl_context_get_ciphers);
|
||||
|
||||
// SSLContext.set_ciphers(ciphersuite)
|
||||
STATIC mp_obj_t ssl_context_set_ciphers(mp_obj_t self_in, mp_obj_t ciphersuite) {
|
||||
mp_obj_ssl_context_t *ssl_context = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
// Check that ciphersuite is a list or tuple.
|
||||
size_t len = 0;
|
||||
mp_obj_t *ciphers;
|
||||
mp_obj_get_array(ciphersuite, &len, &ciphers);
|
||||
if (len == 0) {
|
||||
mbedtls_raise_error(MBEDTLS_ERR_SSL_BAD_CONFIG);
|
||||
}
|
||||
|
||||
// Parse list of ciphers.
|
||||
ssl_context->ciphersuites = m_new(int, len + 1);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
const char *ciphername = mp_obj_str_get_str(ciphers[i]);
|
||||
const int id = mbedtls_ssl_get_ciphersuite_id(ciphername);
|
||||
if (id == 0) {
|
||||
mbedtls_raise_error(MBEDTLS_ERR_SSL_BAD_CONFIG);
|
||||
}
|
||||
ssl_context->ciphersuites[i] = id;
|
||||
}
|
||||
ssl_context->ciphersuites[len] = 0;
|
||||
|
||||
// Configure ciphersuite.
|
||||
mbedtls_ssl_conf_ciphersuites(&ssl_context->conf, (const int *)ssl_context->ciphersuites);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_context_set_ciphers_obj, ssl_context_set_ciphers);
|
||||
|
||||
STATIC void ssl_context_load_key(mp_obj_ssl_context_t *self, mp_obj_t key_obj, mp_obj_t cert_obj) {
|
||||
size_t key_len;
|
||||
const byte *key = (const byte *)mp_obj_str_get_data(key_obj, &key_len);
|
||||
|
@ -264,6 +379,30 @@ STATIC void ssl_context_load_key(mp_obj_ssl_context_t *self, mp_obj_t key_obj, m
|
|||
}
|
||||
}
|
||||
|
||||
// SSLContext.load_cert_chain(certfile, keyfile)
|
||||
STATIC mp_obj_t ssl_context_load_cert_chain(mp_obj_t self_in, mp_obj_t certfile, mp_obj_t keyfile) {
|
||||
mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_t pkey;
|
||||
mp_obj_t cert;
|
||||
if (certfile != mp_const_none) {
|
||||
// check if key is a string/path
|
||||
if (!(mp_obj_is_type(keyfile, &mp_type_bytes))) {
|
||||
pkey = read_file(keyfile);
|
||||
} else {
|
||||
pkey = keyfile;
|
||||
}
|
||||
// check if cert is a string/path
|
||||
if (!(mp_obj_is_type(certfile, &mp_type_bytes))) {
|
||||
cert = read_file(certfile);
|
||||
} else {
|
||||
cert = certfile;
|
||||
}
|
||||
ssl_context_load_key(self, pkey, cert);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(ssl_context_load_cert_chain_obj, ssl_context_load_cert_chain);
|
||||
|
||||
STATIC void ssl_context_load_cadata(mp_obj_ssl_context_t *self, mp_obj_t cadata_obj) {
|
||||
size_t cacert_len;
|
||||
const byte *cacert = (const byte *)mp_obj_str_get_data(cadata_obj, &cacert_len);
|
||||
|
@ -276,6 +415,30 @@ STATIC void ssl_context_load_cadata(mp_obj_ssl_context_t *self, mp_obj_t cadata_
|
|||
mbedtls_ssl_conf_ca_chain(&self->conf, &self->cacert, NULL);
|
||||
}
|
||||
|
||||
// SSLContext.load_verify_locations(cafile=None, *, cadata=None)
|
||||
STATIC mp_obj_t ssl_context_load_verify_locations(size_t n_args, const mp_obj_t *pos_args,
|
||||
mp_map_t *kw_args) {
|
||||
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_cafile, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_cadata, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
|
||||
mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
// cafile
|
||||
if (args[0].u_obj != mp_const_none) {
|
||||
ssl_context_load_cadata(self, read_file(args[0].u_obj));
|
||||
}
|
||||
// cadata
|
||||
if (args[1].u_obj != mp_const_none) {
|
||||
ssl_context_load_cadata(self, args[1].u_obj);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_load_verify_locations_obj, 1, ssl_context_load_verify_locations);
|
||||
|
||||
STATIC mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
|
@ -300,6 +463,10 @@ STATIC const mp_rom_map_elem_t ssl_context_locals_dict_table[] = {
|
|||
#if MICROPY_PY_SSL_FINALISER
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ssl_context___del___obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_ciphers), MP_ROM_PTR(&ssl_context_get_ciphers_obj)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_ciphers), MP_ROM_PTR(&ssl_context_set_ciphers_obj)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_load_cert_chain), MP_ROM_PTR(&ssl_context_load_cert_chain_obj)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_load_verify_locations), MP_ROM_PTR(&ssl_context_load_verify_locations_obj)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&ssl_context_wrap_socket_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(ssl_context_locals_dict, ssl_context_locals_dict_table);
|
||||
|
@ -369,6 +536,8 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
|||
o->last_error = 0;
|
||||
|
||||
int ret;
|
||||
uint32_t flags = 0;
|
||||
|
||||
mbedtls_ssl_init(&o->ssl);
|
||||
|
||||
ret = mbedtls_ssl_setup(&o->ssl, &ssl_context->conf);
|
||||
|
@ -382,6 +551,11 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
|||
if (ret != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (ssl_context->authmode == MBEDTLS_SSL_VERIFY_REQUIRED && server_side == false) {
|
||||
|
||||
o->sock = MP_OBJ_NULL;
|
||||
mbedtls_ssl_free(&o->ssl);
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("CERT_REQUIRED requires server_hostname"));
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
|
||||
|
@ -391,20 +565,34 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
|||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
goto cleanup;
|
||||
}
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
#endif
|
||||
mp_event_wait_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
|
||||
cleanup:
|
||||
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
||||
flags = mbedtls_ssl_get_verify_result(&o->ssl);
|
||||
}
|
||||
|
||||
o->sock = MP_OBJ_NULL;
|
||||
mbedtls_ssl_free(&o->ssl);
|
||||
|
||||
if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
||||
char xcbuf[256];
|
||||
int ret_info = mbedtls_x509_crt_verify_info(xcbuf, sizeof(xcbuf), "\n", flags);
|
||||
// The length of the string written (not including the terminated nul byte),
|
||||
// or a negative err code.
|
||||
if (ret_info > 0) {
|
||||
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%s"), xcbuf);
|
||||
}
|
||||
}
|
||||
|
||||
mbedtls_raise_error(ret);
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
|
||||
STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
if (!mp_obj_is_true(binary_form)) {
|
||||
|
@ -417,6 +605,18 @@ STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
|
|||
return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_ssl_cipher(mp_obj_t o_in) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
const char *cipher_suite = mbedtls_ssl_get_ciphersuite(&o->ssl);
|
||||
const char *tls_version = mbedtls_ssl_get_version(&o->ssl);
|
||||
mp_obj_t tuple[2] = {mp_obj_new_str(cipher_suite, strlen(cipher_suite)),
|
||||
mp_obj_new_str(tls_version, strlen(tls_version))};
|
||||
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ssl_cipher_obj, mod_ssl_cipher);
|
||||
|
||||
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
|
@ -454,6 +654,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
|
|||
} else {
|
||||
o->last_error = ret;
|
||||
}
|
||||
ssl_check_async_handshake_failure(o, &ret);
|
||||
*errcode = ret;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
@ -482,6 +683,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
|
|||
} else {
|
||||
o->last_error = ret;
|
||||
}
|
||||
ssl_check_async_handshake_failure(o, &ret);
|
||||
*errcode = ret;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
@ -566,7 +768,10 @@ STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
|
|||
#if MICROPY_UNIX_COVERAGE
|
||||
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
|
||||
#endif
|
||||
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
|
||||
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_cipher), MP_ROM_PTR(&mod_ssl_cipher_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table);
|
||||
|
||||
|
@ -647,6 +852,7 @@ STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_SSLContext), MP_ROM_PTR(&ssl_context_type) },
|
||||
|
||||
// Constants.
|
||||
{ MP_ROM_QSTR(MP_QSTR_MBEDTLS_VERSION), MP_ROM_PTR(&mbedtls_version_obj)},
|
||||
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(MBEDTLS_SSL_IS_CLIENT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(MBEDTLS_SSL_IS_SERVER) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(MBEDTLS_SSL_VERIFY_NONE) },
|
||||
|
|
|
@ -96,7 +96,7 @@ STATIC NORETURN void syntax_error(void) {
|
|||
STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 2, 3, false);
|
||||
mp_obj_uctypes_struct_t *o = mp_obj_malloc(mp_obj_uctypes_struct_t, type);
|
||||
o->addr = (void *)(uintptr_t)mp_obj_int_get_truncated(args[0]);
|
||||
o->addr = (void *)(uintptr_t)mp_obj_get_int_truncated(args[0]);
|
||||
o->desc = args[1];
|
||||
o->flags = LAYOUT_NATIVE;
|
||||
if (n_args == 3) {
|
||||
|
|
|
@ -222,8 +222,13 @@ STATIC mp_obj_t network_cyw43_scan(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
|
||||
// Wait for scan to finish, with a 10s timeout
|
||||
uint32_t start = mp_hal_ticks_ms();
|
||||
while (cyw43_wifi_scan_active(self->cyw) && mp_hal_ticks_ms() - start < 10000) {
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
const uint32_t TIMEOUT = 10000;
|
||||
while (cyw43_wifi_scan_active(self->cyw)) {
|
||||
uint32_t elapsed = mp_hal_ticks_ms() - start;
|
||||
if (elapsed >= TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
mp_event_wait_ms(TIMEOUT - elapsed);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "py/misc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "shared/netutils/netutils.h"
|
||||
#include "shared/runtime/softtimer.h"
|
||||
#include "extmod/modnetwork.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
|
@ -50,6 +51,7 @@
|
|||
typedef struct _nina_obj_t {
|
||||
mp_obj_base_t base;
|
||||
bool active;
|
||||
bool poll_enable;
|
||||
uint32_t itf;
|
||||
mp_uint_t security;
|
||||
char ssid[NINA_MAX_SSID_LEN + 1];
|
||||
|
@ -71,6 +73,7 @@ typedef struct _nina_obj_t {
|
|||
#define SO_ERROR (0x1007)
|
||||
#define SO_TYPE (0x1008)
|
||||
#define SO_NO_CHECK (0x100a)
|
||||
#define NINAW10_POLL_INTERVAL (100)
|
||||
|
||||
#define is_nonblocking_error(errno) ((errno) == MP_EAGAIN || (errno) == MP_EWOULDBLOCK || (errno) == MP_EINPROGRESS)
|
||||
|
||||
|
@ -78,28 +81,56 @@ typedef struct _nina_obj_t {
|
|||
|
||||
static uint16_t bind_port = BIND_PORT_RANGE_MIN;
|
||||
const mp_obj_type_t mod_network_nic_type_nina;
|
||||
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
|
||||
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
|
||||
static mp_sched_node_t mp_wifi_sockpoll_node;
|
||||
static mp_sched_node_t mp_wifi_connpoll_node;
|
||||
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, false, MOD_NETWORK_STA_IF};
|
||||
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, false, MOD_NETWORK_AP_IF};
|
||||
static mp_sched_node_t mp_wifi_poll_node;
|
||||
static soft_timer_entry_t mp_wifi_poll_timer;
|
||||
STATIC void network_ninaw10_deinit(void);
|
||||
|
||||
STATIC bool network_ninaw10_poll_list_is_empty(void) {
|
||||
return MP_STATE_PORT(mp_wifi_poll_list) == NULL ||
|
||||
MP_STATE_PORT(mp_wifi_poll_list)->len == 0;
|
||||
}
|
||||
|
||||
STATIC void network_ninaw10_poll_list_insert(mp_obj_t socket) {
|
||||
if (MP_STATE_PORT(mp_wifi_poll_list) == NULL) {
|
||||
MP_STATE_PORT(mp_wifi_poll_list) = mp_obj_new_list(0, NULL);
|
||||
}
|
||||
mp_obj_list_append(MP_STATE_PORT(mp_wifi_poll_list), socket);
|
||||
}
|
||||
|
||||
STATIC void network_ninaw10_poll_list_remove(mp_obj_t socket) {
|
||||
if (MP_STATE_PORT(mp_wifi_poll_list) == NULL) {
|
||||
return;
|
||||
}
|
||||
mp_obj_list_remove(MP_STATE_PORT(mp_wifi_poll_list), socket);
|
||||
if (MP_STATE_PORT(mp_wifi_poll_list)->len == 0) {
|
||||
MP_STATE_PORT(mp_wifi_poll_list) = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void network_ninaw10_poll_sockets(mp_sched_node_t *node) {
|
||||
(void)node;
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_wifi_sockpoll_list)->len; i++) {
|
||||
mod_network_socket_obj_t *socket = MP_STATE_PORT(mp_wifi_sockpoll_list)->items[i];
|
||||
for (mp_uint_t i = 0; MP_STATE_PORT(mp_wifi_poll_list) && i < MP_STATE_PORT(mp_wifi_poll_list)->len;) {
|
||||
mod_network_socket_obj_t *socket = MP_STATE_PORT(mp_wifi_poll_list)->items[i];
|
||||
uint8_t flags = 0;
|
||||
if (socket->callback == MP_OBJ_NULL || nina_socket_poll(socket->fileno, &flags) < 0) {
|
||||
// remove from poll list on error.
|
||||
// Remove socket from poll list on error.
|
||||
socket->callback = MP_OBJ_NULL;
|
||||
mp_obj_list_remove(MP_STATE_PORT(mp_wifi_sockpoll_list), socket);
|
||||
} else if (flags) {
|
||||
mp_call_function_1(socket->callback, MP_OBJ_FROM_PTR(socket));
|
||||
if (flags & SOCKET_POLL_ERR) {
|
||||
// remove from poll list on error.
|
||||
socket->callback = MP_OBJ_NULL;
|
||||
mp_obj_list_remove(MP_STATE_PORT(mp_wifi_sockpoll_list), socket);
|
||||
}
|
||||
network_ninaw10_poll_list_remove(socket);
|
||||
// Check the same index on the next iteration.
|
||||
continue;
|
||||
}
|
||||
if (flags & SOCKET_POLL_RD) {
|
||||
mp_call_function_1(socket->callback, MP_OBJ_FROM_PTR(socket));
|
||||
}
|
||||
i++;
|
||||
debug_printf("poll_sockets(%d) -> flags %d\n", socket->fileno, flags);
|
||||
}
|
||||
|
||||
if (!network_ninaw10_poll_list_is_empty()) {
|
||||
// Reschedule the sockets polling code.
|
||||
soft_timer_reinsert(&mp_wifi_poll_timer, NINAW10_POLL_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,10 +140,8 @@ STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
|
|||
int status = nina_connection_status();
|
||||
if (status == NINA_STATUS_CONNECTED) {
|
||||
// Connected to AP, nothing else to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (status != NINA_STATUS_NO_SSID_AVAIL) {
|
||||
self->poll_enable = false;
|
||||
} else if (status != NINA_STATUS_NO_SSID_AVAIL) {
|
||||
// If not connected, and no connection in progress, the connection attempt has failed.
|
||||
// Read the ESP failure reason, reconnect and reschedule the connection polling code.
|
||||
int reason = nina_connection_reason();
|
||||
|
@ -121,7 +150,7 @@ STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
|
|||
reason == NINA_ESP_REASON_NOT_AUTHED ||
|
||||
reason == NINA_ESP_REASON_4WAY_HANDSHAKE_TIMEOUT ||
|
||||
reason >= NINA_ESP_REASON_BEACON_TIMEOUT) {
|
||||
debug_printf(&mp_plat_print, "poll_connect() status: %d reason %d\n", status, reason);
|
||||
debug_printf("poll_connect() status: %d reason %d\n", status, reason);
|
||||
if (nina_connect(self->ssid, self->security, self->key, 0) != 0) {
|
||||
mp_raise_msg_varg(&mp_type_OSError,
|
||||
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"),
|
||||
|
@ -129,21 +158,23 @@ STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
|
|||
}
|
||||
} else {
|
||||
// Will not attempt to reconnect if there's another error code set.
|
||||
return;
|
||||
self->poll_enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reschedule the connection polling code.
|
||||
mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
|
||||
// Reinsert the timer to schedule the polling code.
|
||||
soft_timer_reinsert(&mp_wifi_poll_timer, NINAW10_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t network_ninaw10_timer_callback(mp_obj_t none_in) {
|
||||
if (MP_STATE_PORT(mp_wifi_sockpoll_list) != MP_OBJ_NULL && MP_STATE_PORT(mp_wifi_sockpoll_list)->len) {
|
||||
mp_sched_schedule_node(&mp_wifi_sockpoll_node, network_ninaw10_poll_sockets);
|
||||
STATIC void network_ninaw10_timer_callback(soft_timer_entry_t *self) {
|
||||
debug_printf("timer_callback() poll status STA: %d AP: %d SOCKETS: %d\n",
|
||||
network_nina_wl_sta.poll_enable, network_nina_wl_ap.poll_enable, !network_ninaw10_poll_list_is_empty());
|
||||
if (network_nina_wl_sta.poll_enable) {
|
||||
mp_sched_schedule_node(&mp_wifi_poll_node, network_ninaw10_poll_connect);
|
||||
} else if (!network_ninaw10_poll_list_is_empty()) {
|
||||
mp_sched_schedule_node(&mp_wifi_poll_node, network_ninaw10_poll_sockets);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_timer_callback_obj, network_ninaw10_timer_callback);
|
||||
|
||||
STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
@ -162,6 +193,7 @@ STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
|
|||
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
if (n_args == 2) {
|
||||
bool active = mp_obj_is_true(args[1]);
|
||||
network_ninaw10_deinit();
|
||||
if (active) {
|
||||
int error = 0;
|
||||
if ((error = nina_init()) != 0) {
|
||||
|
@ -190,19 +222,9 @@ STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
|
|||
NINA_FW_VER_MIN_MAJOR, NINA_FW_VER_MIN_MINOR, NINA_FW_VER_MIN_PATCH, semver[NINA_FW_VER_MAJOR_OFFS] - 48,
|
||||
semver[NINA_FW_VER_MINOR_OFFS] - 48, semver[NINA_FW_VER_PATCH_OFFS] - 48);
|
||||
}
|
||||
MP_STATE_PORT(mp_wifi_sockpoll_list) = mp_obj_new_list(0, NULL);
|
||||
if (MP_STATE_PORT(mp_wifi_timer) == MP_OBJ_NULL) {
|
||||
// Start sockets poll timer
|
||||
mp_obj_t timer_args[] = {
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_freq), MP_OBJ_NEW_SMALL_INT(10),
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_callback), MP_OBJ_FROM_PTR(&network_ninaw10_timer_callback_obj),
|
||||
};
|
||||
MP_STATE_PORT(mp_wifi_timer) = MP_OBJ_TYPE_GET_SLOT(&machine_timer_type, make_new)((mp_obj_t)&machine_timer_type, 0, 2, timer_args);
|
||||
}
|
||||
soft_timer_static_init(&mp_wifi_poll_timer, SOFT_TIMER_MODE_ONE_SHOT, 0, network_ninaw10_timer_callback);
|
||||
} else {
|
||||
nina_deinit();
|
||||
MP_STATE_PORT(mp_wifi_timer) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(mp_wifi_sockpoll_list) = MP_OBJ_NULL;
|
||||
}
|
||||
self->active = active;
|
||||
return mp_const_none;
|
||||
|
@ -283,7 +305,8 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
|
|||
self->security = security;
|
||||
strncpy(self->key, key, NINA_MAX_WPA_LEN);
|
||||
strncpy(self->ssid, ssid, NINA_MAX_SSID_LEN);
|
||||
mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
|
||||
self->poll_enable = true;
|
||||
soft_timer_reinsert(&mp_wifi_poll_timer, NINAW10_POLL_INTERVAL);
|
||||
} else {
|
||||
mp_uint_t channel = args[ARG_channel].u_int;
|
||||
|
||||
|
@ -428,7 +451,11 @@ STATIC mp_obj_t network_ninaw10_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_
|
|||
nina_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t buf;
|
||||
mp_get_buffer_raise(buf_in, &buf, MP_BUFFER_READ | MP_BUFFER_WRITE);
|
||||
nina_ioctl(mp_obj_get_int(cmd_in), buf.len, buf.buf, self->itf);
|
||||
int ret = nina_ioctl(mp_obj_get_int(cmd_in), buf.len, buf.buf, self->itf);
|
||||
if (ret != 0) {
|
||||
mp_raise_msg_varg(&mp_type_OSError,
|
||||
MP_ERROR_TEXT("ioctl %d failed %d"), mp_obj_get_int(cmd_in), ret);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(network_ninaw10_ioctl_obj, network_ninaw10_ioctl);
|
||||
|
@ -447,7 +474,7 @@ STATIC int network_ninaw10_socket_poll(mod_network_socket_obj_t *socket, uint32_
|
|||
}
|
||||
mp_uint_t start = mp_hal_ticks_ms();
|
||||
for (; !(flags & rwf); mp_hal_delay_ms(5)) {
|
||||
if (nina_socket_poll(socket->fileno, &flags) < 0 || (flags & SOCKET_POLL_ERR)) {
|
||||
if (nina_socket_poll(socket->fileno, &flags) < 0) {
|
||||
nina_socket_errno(_errno);
|
||||
debug_printf("socket_poll(%d) -> errno %d flags %d\n", socket->fileno, *_errno, flags);
|
||||
return -1;
|
||||
|
@ -529,10 +556,8 @@ STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *
|
|||
STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) {
|
||||
debug_printf("socket_close(%d)\n", socket->fileno);
|
||||
if (socket->callback != MP_OBJ_NULL) {
|
||||
mp_sched_lock();
|
||||
socket->callback = MP_OBJ_NULL;
|
||||
mp_obj_list_remove(MP_STATE_PORT(mp_wifi_sockpoll_list), socket);
|
||||
mp_sched_unlock();
|
||||
network_ninaw10_poll_list_remove(socket);
|
||||
}
|
||||
if (socket->fileno >= 0) {
|
||||
nina_socket_close(socket->fileno);
|
||||
|
@ -740,7 +765,8 @@ STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, m
|
|||
mp_sched_lock();
|
||||
socket->callback = (void *)optval;
|
||||
if (socket->callback != MP_OBJ_NULL) {
|
||||
mp_obj_list_append(MP_STATE_PORT(mp_wifi_sockpoll_list), socket);
|
||||
network_ninaw10_poll_list_insert(socket);
|
||||
soft_timer_reinsert(&mp_wifi_poll_timer, NINAW10_POLL_INTERVAL);
|
||||
}
|
||||
mp_sched_unlock();
|
||||
return 0;
|
||||
|
@ -804,6 +830,14 @@ STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uin
|
|||
return ret;
|
||||
}
|
||||
|
||||
STATIC void network_ninaw10_deinit(void) {
|
||||
// On soft-reboot, gc_sweep_all is called and all open sockets are closed
|
||||
// and collected. Make sure that the driver is not keeping any references
|
||||
// to collected sockets in the poll list.
|
||||
soft_timer_remove(&mp_wifi_poll_timer);
|
||||
MP_STATE_PORT(mp_wifi_poll_list) = NULL;
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t nina_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) },
|
||||
|
@ -827,6 +861,7 @@ STATIC MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
|
|||
|
||||
STATIC const mod_network_nic_protocol_t mod_network_nic_protocol_nina = {
|
||||
.gethostbyname = network_ninaw10_gethostbyname,
|
||||
.deinit = network_ninaw10_deinit,
|
||||
.socket = network_ninaw10_socket_socket,
|
||||
.close = network_ninaw10_socket_close,
|
||||
.bind = network_ninaw10_socket_bind,
|
||||
|
@ -852,7 +887,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
|
|||
);
|
||||
|
||||
MP_REGISTER_ROOT_POINTER(struct _machine_spi_obj_t *mp_wifi_spi);
|
||||
MP_REGISTER_ROOT_POINTER(struct _machine_timer_obj_t *mp_wifi_timer);
|
||||
MP_REGISTER_ROOT_POINTER(struct _mp_obj_list_t *mp_wifi_sockpoll_list);
|
||||
MP_REGISTER_ROOT_POINTER(struct _mp_obj_list_t *mp_wifi_poll_list);
|
||||
|
||||
#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
|
||||
|
|