Merge branch 'adafruit:main' into add-raspberry-breadstick
This commit is contained in:
commit
f45046bb11
@ -20,3 +20,9 @@ deques
|
||||
extint
|
||||
shs
|
||||
pass-thru
|
||||
numer
|
||||
arithmetics
|
||||
ftbfs
|
||||
straightaway
|
||||
ftbs
|
||||
ftb
|
||||
|
@ -34,7 +34,7 @@ rm -fr /workspaces/dosfstools-4.2 /workspaces/dosfstools-4.2.tar.gz
|
||||
# prepare source-code tree
|
||||
cd /workspaces/circuitpython/
|
||||
echo -e "[on-create.sh] fetching submodules"
|
||||
make fetch-submodules
|
||||
make fetch-all-submodules
|
||||
echo -e "[on-create.sh] fetching tags"
|
||||
git fetch --tags --recurse-submodules=no --shallow-since="2021-07-01" https://github.com/adafruit/circuitpython HEAD
|
||||
|
||||
|
@ -1,3 +1,24 @@
|
||||
# all: Fix various spelling mistakes found by codespell 2.2.6.
|
||||
cf490a70917a1b2d38ba9b58e763e0837d0f7ca7
|
||||
|
||||
# all: Fix spelling mistakes based on codespell check.
|
||||
b1229efbd1509654dec6053865ab828d769e29db
|
||||
|
||||
# top: Update Python formatting to black "2023 stable style".
|
||||
8b2748269244304854b3462cb8902952b4dcb892
|
||||
|
||||
# all: Reformat remaining C code that doesn't have a space after a comma.
|
||||
5b700b0af90591d6b1a2c087bb8de6b7f1bfdd2d
|
||||
|
||||
# ports: Reformat more C and Python source code.
|
||||
5c32111fa0e31e451b0f1666bdf926be2fdfd82c
|
||||
|
||||
# all: Update Python formatting to latest Black version 22.1.0.
|
||||
ab2923dfa1174dc177f0a90cb00a7e4ff87958d2
|
||||
|
||||
# all: Update Python formatting to latest Black version 21.12b0.
|
||||
3770fab33449a5dadf8eb06edfae0767e75320a6
|
||||
|
||||
# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
|
||||
0f78c36c5aa458a954eed39a46942209107a553e
|
||||
|
||||
|
8
.github/actions/deps/external/action.yml
vendored
8
.github/actions/deps/external/action.yml
vendored
@ -25,7 +25,7 @@ runs:
|
||||
inputs.port != 'espressif'
|
||||
uses: carlosperate/arm-none-eabi-gcc-action@v1
|
||||
with:
|
||||
release: '10-2020-q4'
|
||||
release: '13.2.Rel1'
|
||||
|
||||
# espressif
|
||||
- name: Get espressif toolchain
|
||||
@ -37,11 +37,7 @@ runs:
|
||||
- name: Install IDF tools
|
||||
if: inputs.port == 'espressif'
|
||||
run: |
|
||||
echo "Installing ESP-IDF tools"
|
||||
$IDF_PATH/tools/idf_tools.py --non-interactive install required
|
||||
$IDF_PATH/tools/idf_tools.py --non-interactive install cmake
|
||||
echo "Installing Python environment and packages"
|
||||
$IDF_PATH/tools/idf_tools.py --non-interactive install-python-env
|
||||
$IDF_PATH/install.sh
|
||||
rm -rf $IDF_TOOLS_PATH/dist
|
||||
shell: bash
|
||||
- name: Set environment
|
||||
|
11
.github/actions/mpy_cross/action.yml
vendored
11
.github/actions/mpy_cross/action.yml
vendored
@ -5,6 +5,9 @@ inputs:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
cp-version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@ -16,17 +19,19 @@ runs:
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mpy-cross
|
||||
path: mpy-cross
|
||||
path: mpy-cross/build
|
||||
|
||||
- name: Make mpy-cross executable
|
||||
if: inputs.download == 'true' && steps.download-mpy-cross.outcome == 'success'
|
||||
run: sudo chmod +x mpy-cross/mpy-cross
|
||||
run: sudo chmod +x mpy-cross/build/mpy-cross
|
||||
shell: bash
|
||||
|
||||
- name: Build mpy-cross
|
||||
if: inputs.download == 'false' || steps.download-mpy-cross.outcome == 'failure'
|
||||
run: make -C mpy-cross -j2
|
||||
shell: bash
|
||||
env:
|
||||
CP_VERSION: ${{ inputs.cp-version }}
|
||||
|
||||
- name: Upload mpy-cross
|
||||
if: inputs.download == 'false' || steps.download-mpy-cross.outcome == 'failure'
|
||||
@ -34,4 +39,4 @@ runs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mpy-cross
|
||||
path: mpy-cross/mpy-cross
|
||||
path: mpy-cross/build/mpy-cross
|
||||
|
2
.github/workflows/build-boards.yml
vendored
2
.github/workflows/build-boards.yml
vendored
@ -49,6 +49,8 @@ jobs:
|
||||
- name: Set up mpy-cross
|
||||
if: steps.set-up-submodules.outputs.frozen == 'True'
|
||||
uses: ./.github/actions/mpy_cross
|
||||
with:
|
||||
cp-version: ${{ inputs.cp-version }}
|
||||
|
||||
- name: Versions
|
||||
run: |
|
||||
|
4
.github/workflows/build-mpy-cross.yml
vendored
4
.github/workflows/build-mpy-cross.yml
vendored
@ -64,11 +64,11 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mpy-cross.${{ env.EX }}
|
||||
path: mpy-cross/mpy-cross.${{ env.EX }}
|
||||
path: mpy-cross/build-${{ matrix.mpy-cross }}/mpy-cross.${{ env.EX }}
|
||||
- name: Upload to S3
|
||||
uses: ./.github/actions/upload_aws
|
||||
with:
|
||||
source: mpy-cross/mpy-cross.${{ env.EX }}
|
||||
source: mpy-cross/build-${{ matrix.mpy-cross }}/mpy-cross.${{ env.EX }}
|
||||
destination: mpy-cross/${{ env.OS }}/mpy-cross-${{ env.OS }}-${{ env.CP_VERSION }}.${{ env.EX }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@ -51,6 +51,7 @@ jobs:
|
||||
- name: Set up mpy-cross
|
||||
uses: ./.github/actions/mpy_cross
|
||||
with:
|
||||
cp-version: ${{ steps.set-up-submodules.outputs.version }}
|
||||
download: false
|
||||
- name: Get last commit with checks
|
||||
id: get-last-commit-with-checks
|
||||
@ -127,15 +128,15 @@ jobs:
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mpy-cross-macos-11-x64
|
||||
path: mpy-cross/mpy-cross
|
||||
path: mpy-cross/build/mpy-cross
|
||||
- name: Build mpy-cross (arm64)
|
||||
run: make -C mpy-cross -j2 -f Makefile.m1 V=2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mpy-cross-macos-11-arm64
|
||||
path: mpy-cross/mpy-cross-arm64
|
||||
path: mpy-cross/build-arm64/mpy-cross-arm64
|
||||
- name: Make universal binary
|
||||
run: lipo -create -output mpy-cross-macos-universal mpy-cross/mpy-cross mpy-cross/mpy-cross-arm64
|
||||
run: lipo -create -output mpy-cross-macos-universal mpy-cross/build/mpy-cross mpy-cross/build-arm64/mpy-cross-arm64
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@ -147,8 +148,8 @@ jobs:
|
||||
(github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested'))
|
||||
run: |
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/macos-11/mpy-cross-macos-11-${{ env.CP_VERSION }}-universal --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/macos-11/mpy-cross-macos-11-${{ env.CP_VERSION }}-arm64 --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/macos-11/mpy-cross-macos-11-${{ env.CP_VERSION }}-x64 --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build-arm64/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/macos-11/mpy-cross-macos-11-${{ env.CP_VERSION }}-arm64 --no-progress --region us-east-1
|
||||
[ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/macos-11/mpy-cross-macos-11-${{ env.CP_VERSION }}-x64 --no-progress --region us-east-1
|
||||
env:
|
||||
AWS_PAGER: ''
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
|
1
.github/workflows/custom-board-build.yml
vendored
1
.github/workflows/custom-board-build.yml
vendored
@ -65,6 +65,7 @@ jobs:
|
||||
if: steps.set-up-submodules.outputs.frozen == 'True'
|
||||
uses: ./.github/actions/mpy_cross
|
||||
with:
|
||||
cp-version: ${{ steps.set-up-submodules.outputs.version }}
|
||||
download: false
|
||||
- name: Versions
|
||||
run: |
|
||||
|
15
.github/workflows/run-tests.yml
vendored
15
.github/workflows/run-tests.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
env:
|
||||
CP_VERSION: ${{ inputs.cp-version }}
|
||||
MICROPY_CPYTHON3: python3.8
|
||||
MICROPY_MICROPYTHON: ../ports/unix/micropython-coverage
|
||||
MICROPY_MICROPYTHON: ../ports/unix/build-coverage/micropython
|
||||
TEST_all:
|
||||
TEST_mpy: --via-mpy -d basics float micropython
|
||||
TEST_native: --emit native
|
||||
@ -41,6 +41,8 @@ jobs:
|
||||
uses: ./.github/actions/deps/external
|
||||
- name: Set up mpy-cross
|
||||
uses: ./.github/actions/mpy_cross
|
||||
with:
|
||||
cp-version: ${{ inputs.cp-version }}
|
||||
- name: Build unix port
|
||||
run: make -C ports/unix VARIANT=coverage -j2
|
||||
- name: Run tests
|
||||
@ -55,13 +57,10 @@ jobs:
|
||||
run: |
|
||||
make -C examples/natmod/features1
|
||||
make -C examples/natmod/features2
|
||||
make -C examples/natmod/btree
|
||||
make -C examples/natmod/framebuf
|
||||
make -C examples/natmod/uheapq
|
||||
make -C examples/natmod/urandom
|
||||
make -C examples/natmod/ure
|
||||
make -C examples/natmod/uzlib
|
||||
make -C examples/natmod/heapq
|
||||
make -C examples/natmod/random
|
||||
make -C examples/natmod/re
|
||||
- name: Test native modules
|
||||
if: matrix.test == 'all'
|
||||
run: ./run-natmodtests.py extmod/{btree*,framebuf*,uheapq*,ure*,uzlib*}.py
|
||||
run: ./run-natmodtests.py extmod/{heapq*,re*,zlib*}.py
|
||||
working-directory: tests
|
||||
|
31
.gitmodules
vendored
31
.gitmodules
vendored
@ -143,10 +143,14 @@
|
||||
[submodule "ports/espressif/esp-idf"]
|
||||
path = ports/espressif/esp-idf
|
||||
url = https://github.com/adafruit/esp-idf.git
|
||||
branch = release/v4.4-circuitpython
|
||||
[submodule "ports/espressif/certificates/nina-fw"]
|
||||
path = lib/certificates/nina-fw
|
||||
url = https://github.com/adafruit/nina-fw.git
|
||||
branch = circuitpython-v5.1
|
||||
[submodule "ports/espressif/esp-protocols"]
|
||||
path = ports/espressif/esp-protocols
|
||||
url = https://github.com/espressif/esp-protocols.git
|
||||
[submodule "ports/espressif/esp-camera"]
|
||||
path = ports/espressif/esp-camera
|
||||
url = https://github.com/adafruit/esp32-camera.git
|
||||
branch = circuitpython
|
||||
[submodule "frozen/Adafruit_CircuitPython_ST7789"]
|
||||
path = frozen/Adafruit_CircuitPython_ST7789
|
||||
url = https://github.com/adafruit/Adafruit_CircuitPython_ST7789
|
||||
@ -300,10 +304,6 @@
|
||||
[submodule "frozen/circuitpython_picoed"]
|
||||
path = frozen/circuitpython_picoed
|
||||
url = https://github.com/elecfreaks/circuitpython_picoed.git
|
||||
[submodule "ports/espressif/esp32-camera"]
|
||||
path = ports/espressif/esp32-camera
|
||||
url = https://github.com/adafruit/esp32-camera/
|
||||
branch = circuitpython
|
||||
[submodule "ports/raspberrypi/lib/cyw43-driver"]
|
||||
path = ports/raspberrypi/lib/cyw43-driver
|
||||
url = https://github.com/georgerobotics/cyw43-driver.git
|
||||
@ -340,4 +340,17 @@
|
||||
url = https://github.com/bablokb/circuitpython-pcf85063a
|
||||
[submodule "frozen/Adafruit_CircuitPython_Wave"]
|
||||
path = frozen/Adafruit_CircuitPython_Wave
|
||||
url = http://github.com/adafruit/Adafruit_CircuitPython_Wave.git
|
||||
url = https://github.com/adafruit/Adafruit_CircuitPython_Wave.git
|
||||
[submodule "ports/raspberrypi/lib/Pico-PIO-USB"]
|
||||
path = ports/raspberrypi/lib/Pico-PIO-USB
|
||||
url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git
|
||||
branch = main
|
||||
[submodule "lib/micropython-lib"]
|
||||
path = lib/micropython-lib
|
||||
url = https://github.com/micropython/micropython-lib.git
|
||||
[submodule "lib/certificates"]
|
||||
path = lib/certificates
|
||||
url = https://github.com/adafruit/certificates
|
||||
[submodule "lib/tlsf"]
|
||||
path = lib/tlsf
|
||||
url = https://github.com/espressif/tlsf.git
|
||||
|
@ -19,7 +19,10 @@ repos:
|
||||
exclude: |
|
||||
(?x)^(
|
||||
locale/|
|
||||
lib/
|
||||
lib/|
|
||||
tests/unicode/data/utf-8_invalid.txt|
|
||||
tests/extmod/data/qr.pgm|
|
||||
tests/basics/bytearray_byte_operations.py
|
||||
)
|
||||
- repo: local
|
||||
hooks:
|
||||
|
@ -48,7 +48,7 @@ To compile (or recompile) mpy-cross:
|
||||
|
||||
make -C mpy-cross
|
||||
|
||||
# Building
|
||||
## Building
|
||||
|
||||
There a number of ports of CircuitPython! To build for your board, change to the appropriate ports directory and build.
|
||||
|
||||
@ -64,7 +64,7 @@ If you aren't sure what boards exist, have a peek in the boards subdirectory of
|
||||
If you have a fast computer with many cores, consider adding `-j` to your build flags, such as `-j17` on
|
||||
a 6-core 12-thread machine.
|
||||
|
||||
# Testing
|
||||
## Testing
|
||||
|
||||
If you are working on changes to the core language, you might find it useful to run the test suite.
|
||||
The test suite in the top level `tests` directory. It needs the unix port to run.
|
||||
@ -84,7 +84,7 @@ A successful run will say something like
|
||||
676 tests passed
|
||||
30 tests skipped: buffered_writer builtin_help builtin_range_binop class_delattr_setattr cmd_parsetree extra_coverage framebuf1 framebuf16 framebuf2 framebuf4 framebuf8 framebuf_subclass mpy_invalid namedtuple_asdict non_compliant resource_stream schedule sys_getsizeof urandom_extra ure_groups ure_span ure_sub ure_sub_unmatched vfs_basic vfs_fat_fileio1 vfs_fat_fileio2 vfs_fat_more vfs_fat_oldproto vfs_fat_ramdisk vfs_userfs
|
||||
|
||||
# Debugging
|
||||
## Debugging
|
||||
|
||||
The easiest way to debug CircuitPython on hardware is with a JLink device, JLinkGDBServer, and an appropriate GDB.
|
||||
Instructions can be found at https://learn.adafruit.com/debugging-the-samd21-with-gdb
|
||||
@ -99,7 +99,7 @@ Example:
|
||||
If your port/build includes `arm-none-eabi-gdb-py`, consider using it instead, as it can be used for better register
|
||||
debugging with https://github.com/bnahill/PyCortexMDebug
|
||||
|
||||
# Code Quality Checks
|
||||
## Code Quality Checks
|
||||
|
||||
We apply code quality checks using pre-commit. Install pre-commit once per system with
|
||||
|
||||
|
@ -38,9 +38,9 @@ For SAMD21 debugging workflow tips check out [this learn guide](https://learn.ad
|
||||
Scott Shawcroft ([@tannewt](https://github.com/tannewt)) is the lead developer of CircuitPython
|
||||
and is sponsored by [Adafruit Industries LLC](https://adafruit.com). Scott is usually available
|
||||
during US West Coast working hours. Dan Halbert ([@dhalbert](https://github.com/dhalbert)) and
|
||||
Kattni Rembor ([@kattni](https://github.com/kattni)) are also sponsored by [Adafruit Industries
|
||||
LLC](https://adafruit.com) and are usually available during US East Coast daytime hours including
|
||||
some weekends.
|
||||
Jeff Epler ([@jepler](https://github.com/jepler)) are also sponsored by [Adafruit Industries
|
||||
LLC](https://adafruit.com) and are usually available during US daytime hours including some
|
||||
weekends.
|
||||
|
||||
They are all reachable on [Discord](https://adafru.it/discord), GitHub issues and the [Adafruit
|
||||
support forum](https://forums.adafruit.com/viewforum.php?f=60).
|
||||
|
8
LICENSE
8
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2022 Damien P. George and others
|
||||
Copyright (c) 2013-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
|
||||
@ -9,8 +9,8 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
7
Makefile
7
Makefile
@ -226,8 +226,9 @@ pseudoxml:
|
||||
.PHONY: all-source
|
||||
all-source:
|
||||
|
||||
TRANSLATE_COMMAND=find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -x locale/synthetic.pot -f- -L C -s --add-location=file --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d'
|
||||
locale/circuitpython.pot: all-source
|
||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' > $@
|
||||
$(TRANSLATE_COMMAND) > $@
|
||||
|
||||
# Historically, `make translate` updated the .pot file and ran msgmerge.
|
||||
# However, this was a frequent source of merge conflicts. Weblate can perform
|
||||
@ -252,7 +253,7 @@ merge-translate:
|
||||
|
||||
.PHONY: check-translate
|
||||
check-translate:
|
||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o circuitpython.pot.tmp -p locale
|
||||
$(TRANSLATE_COMMAND) > locale/circuitpython.pot.tmp
|
||||
$(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status
|
||||
|
||||
.PHONY: stubs
|
||||
@ -327,7 +328,7 @@ clean-stm:
|
||||
|
||||
.PHONY: fetch-all-submodules
|
||||
fetch-all-submodules:
|
||||
tools/fetch-submodules.sh
|
||||
$(PYTHON) tools/ci_fetch_deps.py all
|
||||
|
||||
.PHONY: remove-all-submodules
|
||||
remove-all-submodules:
|
||||
|
@ -56,10 +56,6 @@ Specifically useful documentation when starting out:
|
||||
- `CircuitPython Essentials <https://learn.adafruit.com/circuitpython-essentials>`__
|
||||
- `Example Code <https://github.com/adafruit/Adafruit_Learning_System_Guides/tree/master/CircuitPython_Essentials>`__
|
||||
|
||||
Code Search
|
||||
------------
|
||||
GitHub doesn't currently support code search on forks. Therefore, CircuitPython doesn't have code search through GitHub because it is a fork of MicroPython. Luckily, `SourceGraph <https://sourcegraph.com/github.com/adafruit/circuitpython>`_ has free code search for public repos like CircuitPython. So, visit `sourcegraph.com/github.com/adafruit/circuitpython <https://sourcegraph.com/github.com/adafruit/circuitpython>`_ to search the CircuitPython codebase online.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
@ -133,6 +129,8 @@ Behavior
|
||||
``code.py`` **in the REPL anymore, as the REPL is a fresh vm.** CircuitPython's goal for this
|
||||
change includes reducing confusion about pins and memory being used.
|
||||
- After the main code is finished the REPL can be entered by pressing any key.
|
||||
- If the file ``repl.py`` exists, it is executed before the REPL Prompt is shown
|
||||
- In safe mode this functionality is disabled, to ensure the REPL Prompt can always be reached
|
||||
- Autoreload state will be maintained across reload.
|
||||
|
||||
- Adds a safe mode that does not run user code after a hard crash or brown out. This makes it
|
||||
@ -235,7 +233,7 @@ litex alpha
|
||||
mimxrt10xx alpha
|
||||
nrf stable
|
||||
raspberrypi stable
|
||||
efr32 alpha
|
||||
silabs (efr32) alpha
|
||||
stm ``F4`` stable | ``others`` beta
|
||||
unix alpha
|
||||
================ ============================================================
|
||||
|
57
conf.py
57
conf.py
@ -30,6 +30,7 @@ from collections import defaultdict
|
||||
from sphinx.transforms import SphinxTransform
|
||||
from docutils import nodes
|
||||
from sphinx import addnodes
|
||||
from sphinx.ext import intersphinx
|
||||
|
||||
tools_describe = str(pathlib.Path(__file__).parent / "tools/describe")
|
||||
|
||||
@ -201,7 +202,8 @@ exclude_patterns = ["**/build*",
|
||||
"ports/cxd56/spresense-exported-sdk",
|
||||
"ports/espressif/certificates",
|
||||
"ports/espressif/esp-idf",
|
||||
"ports/espressif/esp32-camera",
|
||||
"ports/espressif/esp-camera",
|
||||
"ports/espressif/esp-protocols",
|
||||
"ports/espressif/.idf_tools",
|
||||
"ports/espressif/peripherals",
|
||||
"ports/litex/hw",
|
||||
@ -216,12 +218,12 @@ exclude_patterns = ["**/build*",
|
||||
"ports/nrf/usb",
|
||||
"ports/raspberrypi/sdk",
|
||||
"ports/raspberrypi/lib",
|
||||
"ports/silabs",
|
||||
"ports/silabs/gecko_sdk",
|
||||
"ports/silabs/tools",
|
||||
"ports/stm/st_driver",
|
||||
"ports/stm/packages",
|
||||
"ports/stm/peripherals",
|
||||
"ports/stm/ref",
|
||||
"ports/unix",
|
||||
"py",
|
||||
"shared/*",
|
||||
"shared-bindings/util.*",
|
||||
@ -265,19 +267,9 @@ rst_epilog = """
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# on_rtd is whether we are on readthedocs.org
|
||||
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(), '.']
|
||||
except:
|
||||
html_theme = 'default'
|
||||
html_theme_path = ['.']
|
||||
else:
|
||||
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
|
||||
@ -370,15 +362,23 @@ latex_elements = {
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
# Include 3 levels of headers in PDF ToC
|
||||
'preamble': '\setcounter{tocdepth}{2}',
|
||||
'preamble': r'''
|
||||
\setcounter{tocdepth}{2}
|
||||
\hbadness=99999
|
||||
\hfuzz=20pt
|
||||
\usepackage{pdflscape}
|
||||
''',
|
||||
}
|
||||
|
||||
# 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, 'CircuitPython.tex', 'CircuitPython Documentation',
|
||||
("docs/pdf", 'CircuitPython.tex', 'CircuitPython Documentation',
|
||||
'CircuitPython Contributors', 'manual'),
|
||||
# Uncomment this if you want to build a PDF of the board -> module support matrix.
|
||||
# ("shared-bindings/support_matrix", 'SupportMatrix.tex', 'Board Support Matrix',
|
||||
# 'CircuitPython Contributors', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@ -440,8 +440,10 @@ texinfo_documents = [
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {"cpython": ('https://docs.python.org/3/', None),
|
||||
"register": ('https://circuitpython.readthedocs.io/projects/register/en/latest/', None)}
|
||||
intersphinx_mapping = {"python": ('https://docs.python.org/3/', None),
|
||||
"register": ('https://circuitpython.readthedocs.io/projects/register/en/latest/', None),
|
||||
"mcp2515": ('https://circuitpython.readthedocs.io/projects/mcp2515/en/latest/', None),
|
||||
"typing": ('https://circuitpython.readthedocs.io/projects/adafruit-circuitpython-typing/en/latest/', None)}
|
||||
|
||||
# Adapted from sphinxcontrib-redirects
|
||||
from sphinx.builders import html as builders
|
||||
@ -483,6 +485,26 @@ def generate_redirects(app):
|
||||
with open(redirected_filename, 'w') as f:
|
||||
f.write(TEMPLATE % urllib.parse.quote(to_path, '#/'))
|
||||
|
||||
def adafruit_typing_workaround(app, env, node, contnode):
|
||||
# Sphinx marks a requesting node that uses circuitpython-typing
|
||||
# as looking for a "class" definition, but unfortunately
|
||||
# Sphinx doesn't recognize TypeAlias based types usefully from
|
||||
# the typing library.
|
||||
# (see: https://github.com/sphinx-doc/sphinx/issues/8934)
|
||||
# Instead, it categorizes these types as "data".
|
||||
# (see: python -m sphinx.ext.intersphinx \
|
||||
# https://docs.circuitpython.org/projects/adafruit-circuitpython-typing/en/latest/objects.inv)
|
||||
# This workaround traps missing references, checks if
|
||||
# they are likely to be in the circuitpython_typing package,
|
||||
# and changes the requesting type from "class" to "data" if
|
||||
# needed, and re-tries the reference resolver.
|
||||
ref = node.get("reftarget", None)
|
||||
if ref and ref.startswith("circuitpython_typing."):
|
||||
dtype = node.get("reftype", None)
|
||||
if dtype != "data":
|
||||
node.attributes.update({"reftype": "data"})
|
||||
return intersphinx.missing_reference(app, env, node, contnode)
|
||||
|
||||
|
||||
class CoreModuleTransform(SphinxTransform):
|
||||
default_priority = 870
|
||||
@ -519,4 +541,5 @@ def setup(app):
|
||||
app.add_js_file("filter.js")
|
||||
app.add_config_value('redirects_file', 'redirects', 'env')
|
||||
app.connect('builder-inited', generate_redirects)
|
||||
app.connect('missing-reference', adafruit_typing_workaround)
|
||||
app.add_transform(CoreModuleTransform)
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 427cc923976229bcb981ca6f218ebe8efd636df6
|
||||
Subproject commit d17b999f46fd148ac192ad692b8a4639f81add38
|
@ -82,28 +82,23 @@ STATIC void add_generic_services(bleio_adapter_obj_t *adapter) {
|
||||
|
||||
// Generic Access Service setup.
|
||||
|
||||
bleio_uuid_obj_t *generic_access_service_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
generic_access_service_uuid->base.type = &bleio_uuid_type;
|
||||
bleio_uuid_obj_t *generic_access_service_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
common_hal_bleio_uuid_construct(generic_access_service_uuid, 0x1800, NULL);
|
||||
|
||||
bleio_uuid_obj_t *device_name_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
device_name_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
bleio_uuid_obj_t *device_name_characteristic_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
common_hal_bleio_uuid_construct(device_name_characteristic_uuid, 0x2A00, NULL);
|
||||
|
||||
bleio_uuid_obj_t *appearance_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
appearance_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
bleio_uuid_obj_t *appearance_characteristic_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
common_hal_bleio_uuid_construct(appearance_characteristic_uuid, 0x2A01, NULL);
|
||||
|
||||
// Not implemented:
|
||||
// Peripheral Preferred Connection Parameters
|
||||
// Central Address Resolution
|
||||
|
||||
bleio_service_obj_t *generic_access_service = m_new_obj(bleio_service_obj_t);
|
||||
generic_access_service->base.type = &bleio_service_type;
|
||||
bleio_service_obj_t *generic_access_service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type);
|
||||
common_hal_bleio_service_construct(generic_access_service, generic_access_service_uuid, false);
|
||||
|
||||
adapter->device_name_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->device_name_characteristic->base.type = &bleio_characteristic_type;
|
||||
adapter->device_name_characteristic = mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type);
|
||||
|
||||
char generic_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 'n', 'n', 'n', 'n' };
|
||||
mp_buffer_info_t generic_name_bufinfo = {
|
||||
@ -132,8 +127,7 @@ STATIC void add_generic_services(bleio_adapter_obj_t *adapter) {
|
||||
.len = sizeof(zero_16),
|
||||
};
|
||||
|
||||
adapter->appearance_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->appearance_characteristic->base.type = &bleio_characteristic_type;
|
||||
adapter->appearance_characteristic = mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type);
|
||||
|
||||
common_hal_bleio_characteristic_construct(
|
||||
adapter->appearance_characteristic,
|
||||
@ -151,20 +145,16 @@ STATIC void add_generic_services(bleio_adapter_obj_t *adapter) {
|
||||
|
||||
// Generic Attribute Service setup.
|
||||
|
||||
bleio_uuid_obj_t *generic_attribute_service_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
generic_attribute_service_uuid->base.type = &bleio_uuid_type;
|
||||
bleio_uuid_obj_t *generic_attribute_service_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
common_hal_bleio_uuid_construct(generic_attribute_service_uuid, 0x1801, NULL);
|
||||
|
||||
bleio_uuid_obj_t *service_changed_characteristic_uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
service_changed_characteristic_uuid->base.type = &bleio_uuid_type;
|
||||
bleio_uuid_obj_t *service_changed_characteristic_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
common_hal_bleio_uuid_construct(service_changed_characteristic_uuid, 0x2A05, NULL);
|
||||
|
||||
bleio_service_obj_t *generic_attribute_service = m_new_obj(bleio_service_obj_t);
|
||||
generic_attribute_service->base.type = &bleio_service_type;
|
||||
bleio_service_obj_t *generic_attribute_service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type);
|
||||
common_hal_bleio_service_construct(generic_attribute_service, generic_attribute_service_uuid, false);
|
||||
|
||||
adapter->service_changed_characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
adapter->service_changed_characteristic->base.type = &bleio_characteristic_type;
|
||||
adapter->service_changed_characteristic = mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type);
|
||||
|
||||
uint32_t zero_32 = 0;
|
||||
mp_buffer_info_t zero_32_value = {
|
||||
@ -190,7 +180,7 @@ STATIC void add_generic_services(bleio_adapter_obj_t *adapter) {
|
||||
|
||||
STATIC void check_enabled(bleio_adapter_obj_t *adapter) {
|
||||
if (!common_hal_bleio_adapter_get_enabled(adapter)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Adapter not enabled"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Adapter not enabled"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,18 +297,18 @@ STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) {
|
||||
// Get version information.
|
||||
if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version,
|
||||
&self->manufacturer, &self->lmp_subversion) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read HCI version"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not read HCI version"));
|
||||
}
|
||||
// Get supported features.
|
||||
if (hci_le_read_local_supported_features(self->features) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read BLE features"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not read BLE features"));
|
||||
}
|
||||
|
||||
// Enabled desired events.
|
||||
// Most importantly, includes:
|
||||
// BT_EVT_MASK_LE_META_EVENT BT_EVT_BIT(61)
|
||||
if (hci_set_event_mask(0x3FFFFFFFFFFFFFFF) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not set event mask"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not set event mask"));
|
||||
}
|
||||
// The default events for LE are:
|
||||
// BT_EVT_MASK_LE_CONN_COMPLETE, BT_EVT_MASK_LE_ADVERTISING_REPORT,
|
||||
@ -339,7 +329,7 @@ STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) {
|
||||
uint16_t acl_max_num;
|
||||
uint16_t sco_max_num;
|
||||
if (hci_read_buffer_size(&acl_max_len, &sco_max_len, &acl_max_num, &sco_max_num) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not read BLE buffer info"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not read BLE buffer info"));
|
||||
}
|
||||
self->max_acl_buffer_len = acl_max_len;
|
||||
self->max_acl_num_buffers = acl_max_num;
|
||||
@ -349,7 +339,7 @@ STATIC void bleio_adapter_hci_init(bleio_adapter_obj_t *self) {
|
||||
if (BT_FEAT_LE_EXT_ADV(self->features)) {
|
||||
uint16_t max_adv_data_len;
|
||||
if (hci_le_read_maximum_advertising_data_length(&max_adv_data_len) != HCI_OK) {
|
||||
mp_raise_bleio_BluetoothError(translate("Could not get max advertising length"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not get max advertising length"));
|
||||
}
|
||||
self->max_adv_data_len = max_adv_data_len;
|
||||
} else {
|
||||
@ -416,8 +406,7 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s
|
||||
bt_addr_t addr;
|
||||
hci_check_error(hci_read_bd_addr(&addr));
|
||||
|
||||
bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t);
|
||||
address->base.type = &bleio_address_type;
|
||||
bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type);
|
||||
|
||||
common_hal_bleio_address_construct(address, addr.val, BT_ADDR_LE_PUBLIC);
|
||||
return address;
|
||||
@ -483,14 +472,14 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t
|
||||
|
||||
if (self->scan_results != NULL) {
|
||||
if (!shared_module_bleio_scanresults_get_done(self->scan_results)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Scan already in progress. Stop with stop_scan."));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Scan already in progress. Stop with stop_scan."));
|
||||
}
|
||||
self->scan_results = NULL;
|
||||
}
|
||||
self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi);
|
||||
|
||||
// size_t max_packet_size = extended ? BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED : BLE_GAP_SCAN_BUFFER_MAX;
|
||||
// uint8_t *raw_data = m_malloc(sizeof(ble_data_t) + max_packet_size, false);
|
||||
// uint8_t *raw_data = m_malloc(sizeof(ble_data_t) + max_packet_size);
|
||||
// ble_data_t * sd_data = (ble_data_t *) raw_data;
|
||||
// self->scan_results->common_hal_data = sd_data;
|
||||
// sd_data->len = max_packet_size;
|
||||
@ -612,7 +601,7 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre
|
||||
|
||||
// uint16_t conn_handle = event_info.conn_handle;
|
||||
// if (conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
// mp_raise_bleio_BluetoothError(translate("Failed to connect: timeout"));
|
||||
// mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: timeout"));
|
||||
// }
|
||||
|
||||
// // Negotiate for better PHY, larger MTU and data lengths since we are the central. These are
|
||||
@ -633,14 +622,14 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre
|
||||
// }
|
||||
// }
|
||||
|
||||
mp_raise_bleio_BluetoothError(translate("Failed to connect: internal error"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: internal error"));
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void check_data_fit(size_t data_len, bool connectable) {
|
||||
if (data_len > MAX_ADVERTISEMENT_SIZE) {
|
||||
mp_raise_ValueError(translate("Data too large for advertisement packet"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Data too large for advertisement packet"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,7 +686,7 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
|
||||
|
||||
if (extended) {
|
||||
if (!BT_FEAT_LE_EXT_ADV(self->features)) {
|
||||
mp_raise_bleio_BluetoothError(translate("Data length needs extended advertising, but this adapter does not support it"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Data length needs extended advertising, but this adapter does not support it"));
|
||||
}
|
||||
|
||||
uint16_t props = 0;
|
||||
@ -812,7 +801,7 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
|
||||
check_data_fit(scan_response_data_bufinfo->len, connectable);
|
||||
|
||||
if (advertising_data_bufinfo->len > MAX_ADVERTISEMENT_SIZE && scan_response_data_bufinfo->len > 0) {
|
||||
mp_raise_bleio_BluetoothError(translate("Extended advertisements with scan response not supported."));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Extended advertisements with scan response not supported."));
|
||||
}
|
||||
|
||||
// Anonymous mode requires a timeout so that we don't continue to broadcast
|
||||
@ -822,13 +811,13 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
|
||||
timeout = MAX_ANONYMOUS_ADV_TIMEOUT_SECS;
|
||||
} else {
|
||||
if (timeout > MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS) {
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout is too long: Maximum timeout length is %d seconds"),
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Timeout is too long: Maximum timeout length is %d seconds"),
|
||||
MAX_LIMITED_DISCOVERABLE_ADV_TIMEOUT_SECS);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx_power != 0) {
|
||||
mp_raise_NotImplementedError(translate("Only tx_power=0 supported"));
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("Only tx_power=0 supported"));
|
||||
}
|
||||
|
||||
const uint32_t result = _common_hal_bleio_adapter_start_advertising(
|
||||
@ -840,7 +829,7 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self,
|
||||
tx_power, directed_to);
|
||||
|
||||
if (result) {
|
||||
mp_raise_bleio_BluetoothError(translate("Already advertising"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Already advertising"));
|
||||
}
|
||||
self->circuitpython_advertising = false;
|
||||
}
|
||||
|
@ -45,5 +45,5 @@ bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute) {
|
||||
bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute);
|
||||
return service->uuid;
|
||||
}
|
||||
mp_raise_RuntimeError(translate("Invalid BLE attribute"));
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid BLE attribute"));
|
||||
}
|
||||
|
@ -108,10 +108,10 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel
|
||||
|
||||
void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length != required fixed length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Value length != required fixed length"));
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length > max_length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Value length > max_length"));
|
||||
}
|
||||
|
||||
// Do GATT operations only if this characteristic has been added to a registered service.
|
||||
@ -125,7 +125,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self,
|
||||
} else if (self->props & CHAR_PROP_WRITE_NO_RESPONSE) {
|
||||
// att_write_cmd(conn_handle, self->handle, bufinfo->buff, bufinfo->len);
|
||||
} else {
|
||||
mp_raise_bleio_BluetoothError(translate("Characteristic not writable"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Characteristic not writable"));
|
||||
}
|
||||
} else {
|
||||
// Always write the value locally even if no connections are active.
|
||||
@ -168,7 +168,7 @@ bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties
|
||||
void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) {
|
||||
if (self->handle != common_hal_bleio_adapter_obj.last_added_characteristic_handle) {
|
||||
mp_raise_bleio_BluetoothError(
|
||||
translate("Descriptor can only be added to most recently added characteristic"));
|
||||
MP_ERROR_TEXT("Descriptor can only be added to most recently added characteristic"));
|
||||
}
|
||||
|
||||
descriptor->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(descriptor));
|
||||
@ -181,11 +181,11 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *
|
||||
|
||||
void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) {
|
||||
if (self->cccd == NULL) {
|
||||
mp_raise_bleio_BluetoothError(translate("No CCCD for this Characteristic"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("No CCCD for this Characteristic"));
|
||||
}
|
||||
|
||||
if (!common_hal_bleio_service_get_is_remote(self->service)) {
|
||||
mp_raise_bleio_RoleError(translate("Can't set CCCD on local Characteristic"));
|
||||
mp_raise_bleio_RoleError(MP_ERROR_TEXT("Can't set CCCD on local Characteristic"));
|
||||
}
|
||||
|
||||
const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
|
||||
@ -199,7 +199,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self,
|
||||
(void)cccd_value;
|
||||
// uint8_t rsp[sizeof(bt_att_error_rsp)];
|
||||
// if (att_write_req(conn_handle, self->cccd->handle, &cccd_value, sizeof(cccd_value)) == 0) {
|
||||
// mp_raise_bleio_BluetoothError(translate("Could not write CCCD"));
|
||||
// mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Could not write CCCD"));
|
||||
// }
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,7 @@ void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffe
|
||||
self->characteristic = characteristic;
|
||||
self->timeout_ms = timeout * 1000;
|
||||
// This is a macro.
|
||||
// true means long-lived, so it won't be moved.
|
||||
ringbuf_alloc(&self->ringbuf, buffer_size, true);
|
||||
ringbuf_alloc(&self->ringbuf, buffer_size);
|
||||
|
||||
bleio_characteristic_set_observer(characteristic, self);
|
||||
}
|
||||
|
@ -453,8 +453,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern
|
||||
// for (size_t i = 0; i < response->count; ++i) {
|
||||
// ble_gattc_service_t *gattc_service = &response->services[i];
|
||||
|
||||
// bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
|
||||
// service->base.type = &bleio_service_type;
|
||||
// bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type);
|
||||
|
||||
// // Initialize several fields at once.
|
||||
// bleio_service_from_connection(service, bleio_connection_new_from_internal(connection));
|
||||
@ -466,8 +465,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern
|
||||
|
||||
// if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known service UUID.
|
||||
// bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// bleio_uuid_obj_t *uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid);
|
||||
// service->uuid = uuid;
|
||||
// } else {
|
||||
@ -491,15 +489,14 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern
|
||||
// for (size_t i = 0; i < response->count; ++i) {
|
||||
// ble_gattc_char_t *gattc_char = &response->chars[i];
|
||||
|
||||
// bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
|
||||
// characteristic->base.type = &bleio_characteristic_type;
|
||||
// bleio_characteristic_obj_t *characteristic =
|
||||
// mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type);
|
||||
|
||||
// bleio_uuid_obj_t *uuid = NULL;
|
||||
|
||||
// if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known characteristic UUID.
|
||||
// uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid);
|
||||
// } else {
|
||||
// // The discovery response contained a 128-bit UUID that has not yet been registered with the
|
||||
@ -557,15 +554,13 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern
|
||||
// break;
|
||||
// }
|
||||
|
||||
// bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t);
|
||||
// descriptor->base.type = &bleio_descriptor_type;
|
||||
// bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type);
|
||||
|
||||
// bleio_uuid_obj_t *uuid = NULL;
|
||||
|
||||
// if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
|
||||
// // Known descriptor UUID.
|
||||
// uuid = m_new_obj(bleio_uuid_obj_t);
|
||||
// uuid->base.type = &bleio_uuid_type;
|
||||
// uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type);
|
||||
// bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid);
|
||||
// } else {
|
||||
// // The discovery response contained a 128-bit UUID that has not yet been registered with the
|
||||
@ -645,7 +640,7 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern
|
||||
// mp_obj_t uuid_obj;
|
||||
// while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
// if (!mp_obj_is_type(uuid_obj, &bleio_uuid_type)) {
|
||||
// mp_raise_TypeError(translate("non-UUID found in service_uuids_whitelist"));
|
||||
// mp_raise_TypeError(MP_ERROR_TEXT("non-UUID found in service_uuids_whitelist"));
|
||||
// }
|
||||
// bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj);
|
||||
|
||||
@ -750,8 +745,7 @@ mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *interna
|
||||
if (internal->connection_obj != mp_const_none) {
|
||||
return internal->connection_obj;
|
||||
}
|
||||
bleio_connection_obj_t *connection = m_new_obj(bleio_connection_obj_t);
|
||||
connection->base.type = &bleio_connection_type;
|
||||
bleio_connection_obj_t *connection = mp_obj_malloc(bleio_connection_obj_t, &bleio_connection_type);
|
||||
connection->connection = internal;
|
||||
internal->connection_obj = connection;
|
||||
|
||||
|
@ -43,7 +43,7 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c
|
||||
|
||||
const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX;
|
||||
if (max_length < 0 || max_length > max_length_max) {
|
||||
mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"),
|
||||
mp_raise_ValueError_varg(MP_ERROR_TEXT("max_length must be 0-%d when fixed_length is %s"),
|
||||
max_length_max, fixed_length ? "True" : "False");
|
||||
}
|
||||
self->max_length = max_length;
|
||||
@ -85,10 +85,10 @@ size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8
|
||||
|
||||
void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) {
|
||||
if (self->fixed_length && bufinfo->len != self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length != required fixed length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Value length != required fixed length"));
|
||||
}
|
||||
if (bufinfo->len > self->max_length) {
|
||||
mp_raise_ValueError(translate("Value length > max_length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Value length > max_length"));
|
||||
}
|
||||
|
||||
self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len);
|
||||
|
@ -101,8 +101,8 @@ void common_hal_bleio_packet_buffer_construct(
|
||||
}
|
||||
|
||||
if (incoming) {
|
||||
if (!ringbuf_alloc(&self->ringbuf, buffer_size * (sizeof(uint16_t) + max_packet_size), false)) {
|
||||
mp_raise_ValueError(translate("Buffer too large and unable to allocate"));
|
||||
if (!ringbuf_alloc(&self->ringbuf, buffer_size * (sizeof(uint16_t) + max_packet_size))) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Buffer too large and unable to allocate"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,8 +110,8 @@ void common_hal_bleio_packet_buffer_construct(
|
||||
self->packet_queued = false;
|
||||
self->pending_index = 0;
|
||||
self->pending_size = 0;
|
||||
self->outgoing[0] = m_malloc(max_packet_size, false);
|
||||
self->outgoing[1] = m_malloc(max_packet_size, false);
|
||||
self->outgoing[0] = m_malloc(max_packet_size);
|
||||
self->outgoing[1] = m_malloc(max_packet_size);
|
||||
} else {
|
||||
self->outgoing[0] = NULL;
|
||||
self->outgoing[1] = NULL;
|
||||
@ -151,7 +151,7 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self
|
||||
mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self,
|
||||
const uint8_t *data, size_t len, uint8_t *header, size_t header_len) {
|
||||
if (self->outgoing[0] == NULL) {
|
||||
mp_raise_bleio_BluetoothError(translate("Writes not supported on Characteristic"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Writes not supported on Characteristic"));
|
||||
}
|
||||
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
return -1;
|
||||
@ -160,7 +160,7 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self,
|
||||
|
||||
if (len + header_len > outgoing_packet_length) {
|
||||
// Supplied data will not fit in a single BLE packet.
|
||||
mp_raise_ValueError(translate("Total data to write is larger than outgoing_packet_length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Total data to write is larger than outgoing_packet_length"));
|
||||
}
|
||||
|
||||
if (len + self->pending_size > outgoing_packet_length) {
|
||||
|
@ -53,7 +53,7 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu
|
||||
void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) {
|
||||
if (_common_hal_bleio_service_construct(self, uuid, is_secondary,
|
||||
mp_obj_new_list(0, NULL)) != 0) {
|
||||
mp_raise_RuntimeError(translate("Failed to add service"));
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to add service"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
|
||||
|
||||
if (self->handle != common_hal_bleio_adapter_obj.last_added_service_handle) {
|
||||
mp_raise_bleio_BluetoothError(
|
||||
translate("Characteristic can only be added to most recently added service"));
|
||||
MP_ERROR_TEXT("Characteristic can only be added to most recently added service"));
|
||||
}
|
||||
characteristic->decl_handle = bleio_adapter_add_attribute(
|
||||
&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(characteristic));
|
||||
@ -101,8 +101,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
|
||||
|
||||
if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) {
|
||||
// We need a CCCD if this characteristic is doing notify or indicate.
|
||||
bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t);
|
||||
cccd->base.type = &bleio_descriptor_type;
|
||||
bleio_descriptor_obj_t *cccd = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type);
|
||||
|
||||
uint16_t zero = 0;
|
||||
mp_buffer_info_t zero_cccd_value = {
|
||||
|
@ -50,10 +50,10 @@ bool vm_used_ble;
|
||||
|
||||
// switch (sec_status) {
|
||||
// case BLE_GAP_SEC_STATUS_UNSPECIFIED:
|
||||
// mp_raise_bleio_SecurityError(translate("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored."));
|
||||
// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored."));
|
||||
// return;
|
||||
// default:
|
||||
// mp_raise_bleio_SecurityError(translate("Unknown security error: 0x%04x"), sec_status);
|
||||
// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_status);
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -96,14 +96,14 @@ bleio_adapter_obj_t common_hal_bleio_adapter_obj = {
|
||||
|
||||
bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) {
|
||||
if (common_hal_bleio_adapter_obj.allocated) {
|
||||
mp_raise_RuntimeError(translate("Too many Adapters"));
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Too many Adapters"));
|
||||
}
|
||||
return &common_hal_bleio_adapter_obj;
|
||||
}
|
||||
|
||||
void common_hal_bleio_check_connected(uint16_t conn_handle) {
|
||||
if (conn_handle == BLE_CONN_HANDLE_INVALID) {
|
||||
mp_raise_ConnectionError(translate("Not connected"));
|
||||
mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "shared-bindings/_bleio/Service.h"
|
||||
#include "shared-bindings/_bleio/UUID.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
STATIC uint16_t max_mtu = BT_ATT_DEFAULT_LE_MTU; // 23
|
||||
STATIC unsigned long timeout = 5000;
|
||||
@ -1723,57 +1722,57 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) {
|
||||
|
||||
// FIX Do we need all of these?
|
||||
static void check_att_err(uint8_t err) {
|
||||
const compressed_string_t *msg = NULL;
|
||||
mp_rom_error_text_t msg = NULL;
|
||||
switch (err) {
|
||||
case 0:
|
||||
return;
|
||||
case BT_ATT_ERR_INVALID_HANDLE:
|
||||
msg = translate("Invalid handle");
|
||||
msg = MP_ERROR_TEXT("Invalid handle");
|
||||
break;
|
||||
case BT_ATT_ERR_READ_NOT_PERMITTED:
|
||||
msg = translate("Read not permitted");
|
||||
msg = MP_ERROR_TEXT("Read not permitted");
|
||||
break;
|
||||
case BT_ATT_ERR_WRITE_NOT_PERMITTED:
|
||||
msg = translate("Write not permitted");
|
||||
msg = MP_ERROR_TEXT("Write not permitted");
|
||||
break;
|
||||
case BT_ATT_ERR_INVALID_PDU:
|
||||
msg = translate("Invalid PDU");
|
||||
msg = MP_ERROR_TEXT("Invalid PDU");
|
||||
break;
|
||||
case BT_ATT_ERR_NOT_SUPPORTED:
|
||||
msg = translate("Not supported");
|
||||
msg = MP_ERROR_TEXT("Not supported");
|
||||
break;
|
||||
case BT_ATT_ERR_INVALID_OFFSET:
|
||||
msg = translate("Invalid offset");
|
||||
msg = MP_ERROR_TEXT("Invalid offset");
|
||||
break;
|
||||
case BT_ATT_ERR_PREPARE_QUEUE_FULL:
|
||||
msg = translate("Prepare queue full");
|
||||
msg = MP_ERROR_TEXT("Prepare queue full");
|
||||
break;
|
||||
case BT_ATT_ERR_ATTRIBUTE_NOT_FOUND:
|
||||
msg = translate("Attribute not found");
|
||||
msg = MP_ERROR_TEXT("Attribute not found");
|
||||
break;
|
||||
case BT_ATT_ERR_ATTRIBUTE_NOT_LONG:
|
||||
msg = translate("Attribute not long");
|
||||
msg = MP_ERROR_TEXT("Attribute not long");
|
||||
break;
|
||||
case BT_ATT_ERR_ENCRYPTION_KEY_SIZE:
|
||||
msg = translate("Encryption key size");
|
||||
msg = MP_ERROR_TEXT("Encryption key size");
|
||||
break;
|
||||
case BT_ATT_ERR_INVALID_ATTRIBUTE_LEN:
|
||||
msg = translate("Invalid attribute length");
|
||||
msg = MP_ERROR_TEXT("Invalid attribute length");
|
||||
break;
|
||||
case BT_ATT_ERR_UNLIKELY:
|
||||
msg = translate("Unlikely");
|
||||
msg = MP_ERROR_TEXT("Unlikely");
|
||||
break;
|
||||
case BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE:
|
||||
msg = translate("Unsupported group type");
|
||||
msg = MP_ERROR_TEXT("Unsupported group type");
|
||||
break;
|
||||
case BT_ATT_ERR_INSUFFICIENT_RESOURCES:
|
||||
msg = translate("Insufficient resources");
|
||||
msg = MP_ERROR_TEXT("Insufficient resources");
|
||||
break;
|
||||
case BT_ATT_ERR_DB_OUT_OF_SYNC:
|
||||
msg = translate("DB out of sync");
|
||||
msg = MP_ERROR_TEXT("DB out of sync");
|
||||
break;
|
||||
case BT_ATT_ERR_VALUE_NOT_ALLOWED:
|
||||
msg = translate("Value not allowed");
|
||||
msg = MP_ERROR_TEXT("Value not allowed");
|
||||
break;
|
||||
}
|
||||
if (msg) {
|
||||
@ -1782,15 +1781,15 @@ static void check_att_err(uint8_t err) {
|
||||
|
||||
switch (err) {
|
||||
case BT_ATT_ERR_AUTHENTICATION:
|
||||
msg = translate("Insufficient authentication");
|
||||
msg = MP_ERROR_TEXT("Insufficient authentication");
|
||||
break;
|
||||
case BT_ATT_ERR_INSUFFICIENT_ENCRYPTION:
|
||||
msg = translate("Insufficient encryption");
|
||||
msg = MP_ERROR_TEXT("Insufficient encryption");
|
||||
break;
|
||||
}
|
||||
if (msg) {
|
||||
mp_raise_bleio_SecurityError(msg);
|
||||
}
|
||||
|
||||
mp_raise_bleio_BluetoothError(translate("Unknown ATT error: 0x%02x"), err);
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Unknown ATT error: 0x%02x"), err);
|
||||
}
|
||||
|
@ -770,35 +770,35 @@ void hci_check_error(hci_result_t result) {
|
||||
return;
|
||||
|
||||
case HCI_RESPONSE_TIMEOUT:
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout waiting for HCI response"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Timeout waiting for HCI response"));
|
||||
return;
|
||||
|
||||
case HCI_WRITE_TIMEOUT:
|
||||
mp_raise_bleio_BluetoothError(translate("Timeout waiting to write HCI request"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Timeout waiting to write HCI request"));
|
||||
return;
|
||||
|
||||
case HCI_READ_ERROR:
|
||||
mp_raise_bleio_BluetoothError(translate("Error reading from HCI adapter"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Error reading from HCI adapter"));
|
||||
return;
|
||||
|
||||
case HCI_WRITE_ERROR:
|
||||
mp_raise_bleio_BluetoothError(translate("Error writing to HCI adapter"));
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Error writing to HCI adapter"));
|
||||
return;
|
||||
|
||||
case HCI_PACKET_SIZE_ERROR:
|
||||
mp_raise_RuntimeError(translate("HCI packet size mismatch"));
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("HCI packet size mismatch"));
|
||||
return;
|
||||
|
||||
case HCI_ATT_ERROR:
|
||||
mp_raise_RuntimeError(translate("Error in ATT protocol code"));
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("Error in ATT protocol code"));
|
||||
return;
|
||||
|
||||
default:
|
||||
// Should be an HCI status error, > 0.
|
||||
if (result > 0) {
|
||||
mp_raise_bleio_BluetoothError(translate("HCI status error: %02x"), result);
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("HCI status error: %02x"), result);
|
||||
} else {
|
||||
mp_raise_bleio_BluetoothError(translate("Unknown hci_result_t: %d"), result);
|
||||
mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Unknown hci_result_t: %d"), result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -60,18 +60,21 @@ CIRCUITPY_BLE_NAME
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
Default BLE name the board advertises as, including for the BLE workflow.
|
||||
|
||||
CIRCUITPY_HEAP_START_SIZE
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the initial size of the python heap, allocated from the outer heap. Must be a multiple of 4.
|
||||
The default is currently 8192.
|
||||
The python heap will grow by doubling and redoubling this initial size until it cannot fit in the outer heap.
|
||||
Larger values will reserve more RAM for python use and prevent the supervisor and SDK
|
||||
from large allocations of their own.
|
||||
Smaller values will likely grow sooner than large start sizes.
|
||||
|
||||
CIRCUITPY_PYSTACK_SIZE
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the size of the python stack. Must be a multiple of 4. The default value is currently 1536.
|
||||
Increasing the stack reduces the size of the heap available to python code.
|
||||
Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoid it.
|
||||
|
||||
CIRCUITPY_RESERVED_PSRAM
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
On boards with Espressif microcontrollers with PSRAM (also called SPIRAM), permanently reserve a portion of PSRAM for use by esp-idf.
|
||||
This storage is removed from the CircuitPython "heap" and is available for allocation by esp-idf routines in the core instead.
|
||||
Generally, only set this to a non-zero value when it is required by a specific core module.
|
||||
|
||||
CIRCUITPY_WEB_API_PASSWORD
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Password required to make modifications to the board from the Web Workflow.
|
||||
|
@ -19,6 +19,7 @@ Full Table of Contents
|
||||
:caption: API and Usage
|
||||
|
||||
../shared-bindings/index.rst
|
||||
library/index.rst
|
||||
supported_ports.rst
|
||||
troubleshooting.rst
|
||||
libraries.rst
|
||||
@ -32,13 +33,11 @@ Full Table of Contents
|
||||
design_guide
|
||||
porting
|
||||
common_hal
|
||||
reference/glossary.rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: MicroPython specific
|
||||
|
||||
library/index.rst
|
||||
reference/glossary.rst
|
||||
:caption: Python stand
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -1,10 +1,10 @@
|
||||
:mod:`array` -- arrays of numeric data
|
||||
=======================================
|
||||
======================================
|
||||
|
||||
.. module:: array
|
||||
:synopsis: efficient arrays of numeric data
|
||||
|
||||
|see_cpython_module| :mod:`cpython:array`.
|
||||
|see_cpython_module| :mod:`python:array`.
|
||||
|
||||
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
|
||||
``L``, ``q``, ``Q``, ``f``, ``d`` (the latter 2 depending on the
|
||||
@ -27,3 +27,55 @@ Classes
|
||||
|
||||
Append new elements as contained in `iterable` to the end of
|
||||
array, growing it.
|
||||
|
||||
.. method:: __getitem__(index)
|
||||
|
||||
Indexed read of the array, called as ``a[index]`` (where ``a`` is an ``array``).
|
||||
Returns a value if *index* is an ``int`` and an ``array`` if *index* is a slice.
|
||||
Negative indices count from the end and ``IndexError`` is thrown if the index is
|
||||
out of range.
|
||||
|
||||
**Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(index)`` fails) and
|
||||
is not present in ``__dict__``, however ``a[index]`` does work.
|
||||
|
||||
.. method:: __setitem__(index, value)
|
||||
|
||||
Indexed write into the array, called as ``a[index] = value`` (where ``a`` is an ``array``).
|
||||
``value`` is a single value if *index* is an ``int`` and an ``array`` if *index* is a slice.
|
||||
Negative indices count from the end and ``IndexError`` is thrown if the index is out of range.
|
||||
|
||||
**Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and
|
||||
is not present in ``__dict__``, however ``a[index] = value`` does work.
|
||||
|
||||
.. method:: __len__()
|
||||
|
||||
Returns the number of items in the array, called as ``len(a)`` (where ``a`` is an ``array``).
|
||||
|
||||
**Note:** ``__len__`` cannot be called directly (``a.__len__()`` fails) and the
|
||||
method is not present in ``__dict__``, however ``len(a)`` does work.
|
||||
|
||||
.. method:: __add__(other)
|
||||
|
||||
Return a new ``array`` that is the concatenation of the array with *other*, called as
|
||||
``a + other`` (where ``a`` and *other* are both ``arrays``).
|
||||
|
||||
**Note:** ``__add__`` cannot be called directly (``a.__add__(other)`` fails) and
|
||||
is not present in ``__dict__``, however ``a + other`` does work.
|
||||
|
||||
.. method:: __iadd__(other)
|
||||
|
||||
Concatenates the array with *other* in-place, called as ``a += other`` (where ``a`` and *other*
|
||||
are both ``arrays``). Equivalent to ``extend(other)``.
|
||||
|
||||
**Note:** ``__iadd__`` cannot be called directly (``a.__iadd__(other)`` fails) and
|
||||
is not present in ``__dict__``, however ``a += other`` does work.
|
||||
|
||||
.. method:: __repr__()
|
||||
|
||||
Returns the string representation of the array, called as ``str(a)`` or ``repr(a)```
|
||||
(where ``a`` is an ``array``). Returns the string ``"array(<type>, [<elements>])"``,
|
||||
where ``<type>`` is the type code letter for the array and ``<elements>`` is a comma
|
||||
separated list of the elements of the array.
|
||||
|
||||
**Note:** ``__repr__`` cannot be called directly (``a.__repr__()`` fails) and
|
||||
is not present in ``__dict__``, however ``str(a)`` and ``repr(a)`` both work.
|
||||
|
@ -1,10 +1,10 @@
|
||||
:mod:`binascii` -- binary/ASCII conversions
|
||||
============================================
|
||||
===========================================
|
||||
|
||||
.. module:: binascii
|
||||
:synopsis: binary/ASCII conversions
|
||||
|
||||
|see_cpython_module| :mod:`cpython:binascii`.
|
||||
|see_cpython_module| :mod:`python:binascii`.
|
||||
|
||||
This module implements conversions between binary data and various
|
||||
encodings of it in ASCII form (in both directions).
|
||||
@ -31,11 +31,11 @@ Functions
|
||||
Conforms to `RFC 2045 s.6.8 <https://tools.ietf.org/html/rfc2045#section-6.8>`_.
|
||||
Returns a bytes object.
|
||||
|
||||
.. function:: b2a_base64(data)
|
||||
.. function:: b2a_base64(data, *, newline=True)
|
||||
|
||||
Encode binary data in base64 format, as in `RFC 3548
|
||||
<https://tools.ietf.org/html/rfc3548.html>`_. Returns the encoded data
|
||||
followed by a newline character, as a bytes object.
|
||||
followed by a newline character if ``newline`` is true, as a bytes object.
|
||||
|
||||
.. function:: crc32(data, value=0, /)
|
||||
|
||||
|
@ -1,161 +0,0 @@
|
||||
:mod:`btree` -- simple BTree database
|
||||
=====================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
|
||||
.. module:: btree
|
||||
:synopsis: simple BTree database
|
||||
|
||||
The ``btree`` module implements a simple key-value database using external
|
||||
storage (disk files, or in general case, a random-access ``stream``). Keys are
|
||||
stored sorted in the database, and besides efficient retrieval by a key
|
||||
value, a database also supports efficient ordered range scans (retrieval
|
||||
of values with the keys in a given range). On the application interface
|
||||
side, BTree database work as close a possible to a way standard `dict`
|
||||
type works, one notable difference is that both keys and values must
|
||||
be `bytes` objects (so, if you want to store objects of other types, you
|
||||
need to serialize them to `bytes` first).
|
||||
|
||||
The module is based on the well-known BerkelyDB library, version 1.xx.
|
||||
|
||||
Example::
|
||||
|
||||
import btree
|
||||
|
||||
# First, we need to open a stream which holds a database
|
||||
# This is usually a file, but can be in-memory database
|
||||
# using io.BytesIO, a raw flash partition, etc.
|
||||
# Oftentimes, you want to create a database file if it doesn't
|
||||
# exist and open if it exists. Idiom below takes care of this.
|
||||
# DO NOT open database with "a+b" access mode.
|
||||
try:
|
||||
f = open("mydb", "r+b")
|
||||
except OSError:
|
||||
f = open("mydb", "w+b")
|
||||
|
||||
# Now open a database itself
|
||||
db = btree.open(f)
|
||||
|
||||
# The keys you add will be sorted internally in the database
|
||||
db[b"3"] = b"three"
|
||||
db[b"1"] = b"one"
|
||||
db[b"2"] = b"two"
|
||||
|
||||
# Assume that any changes are cached in memory unless
|
||||
# explicitly flushed (or database closed). Flush database
|
||||
# at the end of each "transaction".
|
||||
db.flush()
|
||||
|
||||
# Prints b'two'
|
||||
print(db[b"2"])
|
||||
|
||||
# Iterate over sorted keys in the database, starting from b"2"
|
||||
# until the end of the database, returning only values.
|
||||
# Mind that arguments passed to values() method are *key* values.
|
||||
# Prints:
|
||||
# b'two'
|
||||
# b'three'
|
||||
for word in db.values(b"2"):
|
||||
print(word)
|
||||
|
||||
del db[b"2"]
|
||||
|
||||
# No longer true, prints False
|
||||
print(b"2" in db)
|
||||
|
||||
# Prints:
|
||||
# b"1"
|
||||
# b"3"
|
||||
for key in db:
|
||||
print(key)
|
||||
|
||||
db.close()
|
||||
|
||||
# Don't forget to close the underlying stream!
|
||||
f.close()
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: open(stream, *, flags=0, pagesize=0, cachesize=0, minkeypage=0)
|
||||
|
||||
Open a database from a random-access ``stream`` (like an open file). All
|
||||
other parameters are optional and keyword-only, and allow to tweak advanced
|
||||
parameters of the database operation (most users will not need them):
|
||||
|
||||
* *flags* - Currently unused.
|
||||
* *pagesize* - Page size used for the nodes in BTree. Acceptable range
|
||||
is 512-65536. If 0, a port-specific default will be used, optimized for
|
||||
port's memory usage and/or performance.
|
||||
* *cachesize* - Suggested memory cache size in bytes. For a
|
||||
board with enough memory using larger values may improve performance.
|
||||
Cache policy is as follows: entire cache is not allocated at once;
|
||||
instead, accessing a new page in database will allocate a memory buffer
|
||||
for it, until value specified by *cachesize* is reached. Then, these
|
||||
buffers will be managed using LRU (least recently used) policy. More
|
||||
buffers may still be allocated if needed (e.g., if a database contains
|
||||
big keys and/or values). Allocated cache buffers aren't reclaimed.
|
||||
* *minkeypage* - Minimum number of keys to store per page. Default value
|
||||
of 0 equivalent to 2.
|
||||
|
||||
Returns a BTree object, which implements a dictionary protocol (set
|
||||
of methods), and some additional methods described below.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: btree.close()
|
||||
|
||||
Close the database. It's mandatory to close the database at the end of
|
||||
processing, as some unwritten data may be still in the cache. Note that
|
||||
this does not close underlying stream with which the database was opened,
|
||||
it should be closed separately (which is also mandatory to make sure that
|
||||
data flushed from buffer to the underlying storage).
|
||||
|
||||
.. method:: btree.flush()
|
||||
|
||||
Flush any data in cache to the underlying stream.
|
||||
|
||||
.. method:: btree.__getitem__(key)
|
||||
btree.get(key, default=None, /)
|
||||
btree.__setitem__(key, val)
|
||||
btree.__delitem__(key)
|
||||
btree.__contains__(key)
|
||||
|
||||
Standard dictionary methods.
|
||||
|
||||
.. method:: btree.__iter__()
|
||||
|
||||
A BTree object can be iterated over directly (similar to a dictionary)
|
||||
to get access to all keys in order.
|
||||
|
||||
.. method:: btree.keys([start_key, [end_key, [flags]]])
|
||||
btree.values([start_key, [end_key, [flags]]])
|
||||
btree.items([start_key, [end_key, [flags]]])
|
||||
|
||||
These methods are similar to standard dictionary methods, but also can
|
||||
take optional parameters to iterate over a key sub-range, instead of
|
||||
the entire database. Note that for all 3 methods, *start_key* and
|
||||
*end_key* arguments represent key values. For example, `values()`
|
||||
method will iterate over values corresponding to they key range
|
||||
given. None values for *start_key* means "from the first key", no
|
||||
*end_key* or its value of None means "until the end of database".
|
||||
By default, range is inclusive of *start_key* and exclusive of
|
||||
*end_key*, you can include *end_key* in iteration by passing *flags*
|
||||
of `btree.INCL`. You can iterate in descending key direction
|
||||
by passing *flags* of `btree.DESC`. The flags values can be ORed
|
||||
together.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: INCL
|
||||
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be inclusive of the end key.
|
||||
|
||||
.. data:: DESC
|
||||
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be in descending direction of keys.
|
@ -33,7 +33,7 @@ Functions and types
|
||||
|
||||
.. class:: bytes()
|
||||
|
||||
|see_cpython| `bytes`.
|
||||
|see_cpython| `python:bytes`.
|
||||
|
||||
.. function:: callable()
|
||||
|
||||
@ -68,7 +68,7 @@ Functions and types
|
||||
|
||||
.. class:: frozenset()
|
||||
|
||||
`frozenset()` is not enabled on non-Express CircuitPython boards.
|
||||
`frozenset()` is not enabled on the smallest CircuitPython boards for space reasons.
|
||||
|
||||
.. function:: getattr()
|
||||
|
||||
@ -88,12 +88,12 @@ Functions and types
|
||||
|
||||
.. classmethod:: from_bytes(bytes, byteorder)
|
||||
|
||||
In CircuitPython, ``byteorder`` parameter must be positional (this is
|
||||
In CircuitPython, the ``byteorder`` parameter must be positional (this is
|
||||
compatible with CPython).
|
||||
|
||||
.. method:: to_bytes(size, byteorder)
|
||||
|
||||
In CircuitPython, ``byteorder`` parameter must be positional (this is
|
||||
In CircuitPython, the ``byteorder`` parameter must be positional (this is
|
||||
compatible with CPython).
|
||||
|
||||
.. function:: isinstance()
|
||||
@ -138,7 +138,7 @@ Functions and types
|
||||
|
||||
.. function:: reversed()
|
||||
|
||||
`reversed()` is not enabled on non-Express CircuitPython boards.
|
||||
`reversed()` is not enabled on the smallest CircuitPython boards for space reasons.
|
||||
|
||||
.. function:: round()
|
||||
|
||||
@ -224,10 +224,14 @@ Exceptions
|
||||
|
||||
.. exception:: SystemExit
|
||||
|
||||
|see_cpython| `python:SystemExit`.
|
||||
|
||||
.. exception:: TimeoutError
|
||||
|
||||
.. exception:: TypeError
|
||||
|
||||
|see_cpython| `python:TypeError`.
|
||||
|
||||
.. exception:: UnicodeError
|
||||
|
||||
.. exception:: ValueError
|
||||
|
@ -1,12 +1,12 @@
|
||||
:mod:`collections` -- collection and container types
|
||||
=====================================================
|
||||
====================================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
**Limitations:** Not implemented on the smallest CircuitPython boards for space reasons.
|
||||
|
||||
.. module:: collections
|
||||
:synopsis: collection and container types
|
||||
|
||||
|see_cpython_module| :mod:`cpython:collections`.
|
||||
|see_cpython_module| :mod:`python:collections`.
|
||||
|
||||
This module implements advanced collection and container types to
|
||||
hold/accumulate various objects.
|
||||
@ -14,7 +14,7 @@ hold/accumulate various objects.
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. function:: deque(iterable, maxlen[, flags])
|
||||
.. class:: deque(iterable, maxlen[, flags])
|
||||
|
||||
Deques (double-ended queues) are a list-like container that support O(1)
|
||||
appends and pops from either side of the deque. New deques are created
|
||||
@ -59,7 +59,7 @@ Classes
|
||||
print(t1.name)
|
||||
assert t2.name == t2[1]
|
||||
|
||||
.. function:: OrderedDict(...)
|
||||
.. class:: OrderedDict(...)
|
||||
|
||||
``dict`` type subclass which remembers and preserves the order of keys
|
||||
added. When ordered dict is iterated over, keys/items are returned in
|
||||
|
@ -4,10 +4,10 @@
|
||||
.. module:: errno
|
||||
:synopsis: system error codes
|
||||
|
||||
|see_cpython_module| :mod:`cpython:errno`.
|
||||
|see_cpython_module| :mod:`python:errno`.
|
||||
|
||||
This module provides access to symbolic error codes for `OSError` exception.
|
||||
A particular inventory of codes depends on :term:`MicroPython port`.
|
||||
The codes available may vary per CircuitPython build.
|
||||
|
||||
Constants
|
||||
---------
|
||||
@ -15,14 +15,13 @@ Constants
|
||||
.. data:: EEXIST, EAGAIN, etc.
|
||||
|
||||
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
||||
"E". As mentioned above, inventory of the codes depends on
|
||||
:term:`MicroPython port`. Errors are usually accessible as ``exc.args[0]``
|
||||
"E". Errors are usually accessible as ``exc.errno``
|
||||
where ``exc`` is an instance of `OSError`. Usage example::
|
||||
|
||||
try:
|
||||
os.mkdir("my_dir")
|
||||
except OSError as exc:
|
||||
if exc.args[0] == errno.EEXIST:
|
||||
if exc.errno == errno.EEXIST:
|
||||
print("Directory already exists")
|
||||
|
||||
.. data:: errorcode
|
||||
|
@ -1,170 +0,0 @@
|
||||
:mod:`framebuf` --- frame buffer manipulation
|
||||
=============================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
|
||||
.. module:: framebuf
|
||||
:synopsis: Frame buffer manipulation
|
||||
|
||||
This module provides a general frame buffer which can be used to create
|
||||
bitmap images, which can then be sent to a display.
|
||||
|
||||
class FrameBuffer
|
||||
-----------------
|
||||
|
||||
The FrameBuffer class provides a pixel buffer which can be drawn upon with
|
||||
pixels, lines, rectangles, text and even other FrameBuffer's. It is useful
|
||||
when generating output for displays.
|
||||
|
||||
For example::
|
||||
|
||||
import framebuf
|
||||
|
||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||
fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565)
|
||||
|
||||
fbuf.fill(0)
|
||||
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
||||
fbuf.hline(0, 9, 96, 0xffff)
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width, /)
|
||||
|
||||
Construct a FrameBuffer object. The parameters are:
|
||||
|
||||
- *buffer* is an object with a buffer protocol which must be large
|
||||
enough to contain every pixel defined by the width, height and
|
||||
format of the FrameBuffer.
|
||||
- *width* is the width of the FrameBuffer in pixels
|
||||
- *height* is the height of the FrameBuffer in pixels
|
||||
- *format* specifies the type of pixel used in the FrameBuffer;
|
||||
permissible values are listed under Constants below. These set the
|
||||
number of bits used to encode a color value and the layout of these
|
||||
bits in *buffer*.
|
||||
Where a color value c is passed to a method, c is a small integer
|
||||
with an encoding that is dependent on the format of the FrameBuffer.
|
||||
- *stride* is the number of pixels between each horizontal line
|
||||
of pixels in the FrameBuffer. This defaults to *width* but may
|
||||
need adjustments when implementing a FrameBuffer within another
|
||||
larger FrameBuffer or screen. The *buffer* size must accommodate
|
||||
an increased step size.
|
||||
|
||||
One must specify valid *buffer*, *width*, *height*, *format* and
|
||||
optionally *stride*. Invalid *buffer* size or dimensions may lead to
|
||||
unexpected errors.
|
||||
|
||||
Drawing primitive shapes
|
||||
------------------------
|
||||
|
||||
The following methods draw shapes onto the FrameBuffer.
|
||||
|
||||
.. method:: FrameBuffer.fill(c)
|
||||
|
||||
Fill the entire FrameBuffer with the specified color.
|
||||
|
||||
.. method:: FrameBuffer.pixel(x, y[, c])
|
||||
|
||||
If *c* is not given, get the color value of the specified pixel.
|
||||
If *c* is given, set the specified pixel to the given color.
|
||||
|
||||
.. method:: FrameBuffer.hline(x, y, w, c)
|
||||
.. method:: FrameBuffer.vline(x, y, h, c)
|
||||
.. method:: FrameBuffer.line(x1, y1, x2, y2, c)
|
||||
|
||||
Draw a line from a set of coordinates using the given color and
|
||||
a thickness of 1 pixel. The `line` method draws the line up to
|
||||
a second set of coordinates whereas the `hline` and `vline`
|
||||
methods draw horizontal and vertical lines respectively up to
|
||||
a given length.
|
||||
|
||||
.. method:: FrameBuffer.rect(x, y, w, h, c)
|
||||
.. method:: FrameBuffer.fill_rect(x, y, w, h, c)
|
||||
|
||||
Draw a rectangle at the given location, size and color. The `rect`
|
||||
method draws only a 1 pixel outline whereas the `fill_rect` method
|
||||
draws both the outline and interior.
|
||||
|
||||
Drawing text
|
||||
------------
|
||||
|
||||
.. method:: FrameBuffer.text(s, x, y[, c])
|
||||
|
||||
Write text to the FrameBuffer using the the coordinates as the upper-left
|
||||
corner of the text. The color of the text can be defined by the optional
|
||||
argument but is otherwise a default value of 1. All characters have
|
||||
dimensions of 8x8 pixels and there is currently no way to change the font.
|
||||
|
||||
|
||||
Other methods
|
||||
-------------
|
||||
|
||||
.. method:: FrameBuffer.scroll(xstep, ystep)
|
||||
|
||||
Shift the contents of the FrameBuffer by the given vector. This may
|
||||
leave a footprint of the previous colors in the FrameBuffer.
|
||||
|
||||
.. method:: FrameBuffer.blit(fbuf, x, y, key=-1, palette=None)
|
||||
|
||||
Draw another FrameBuffer on top of the current one at the given coordinates.
|
||||
If *key* is specified then it should be a color integer and the
|
||||
corresponding color will be considered transparent: all pixels with that
|
||||
color value will not be drawn.
|
||||
|
||||
The *palette* argument enables blitting between FrameBuffers with differing
|
||||
formats. Typical usage is to render a monochrome or grayscale glyph/icon to
|
||||
a color display. The *palette* is a FrameBuffer instance whose format is
|
||||
that of the current FrameBuffer. The *palette* height is one pixel and its
|
||||
pixel width is the number of colors in the source FrameBuffer. The *palette*
|
||||
for an N-bit source needs 2**N pixels; the *palette* for a monochrome source
|
||||
would have 2 pixels representing background and foreground colors. The
|
||||
application assigns a color to each pixel in the *palette*. The color of the
|
||||
current pixel will be that of that *palette* pixel whose x position is the
|
||||
color of the corresponding source pixel.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: framebuf.MONO_VLSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are vertically mapped with
|
||||
bit 0 being nearest the top of the screen. Consequently each byte occupies
|
||||
8 vertical pixels. Subsequent bytes appear at successive horizontal
|
||||
locations until the rightmost edge is reached. Further bytes are rendered
|
||||
at locations starting at the leftmost edge, 8 pixels lower.
|
||||
|
||||
.. data:: framebuf.MONO_HLSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
||||
.. data:: framebuf.MONO_HMSB
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
||||
.. data:: framebuf.RGB565
|
||||
|
||||
Red Green Blue (16-bit, 5+6+5) color format
|
||||
|
||||
.. data:: framebuf.GS2_HMSB
|
||||
|
||||
Grayscale (2-bit) color format
|
||||
|
||||
.. data:: framebuf.GS4_HMSB
|
||||
|
||||
Grayscale (4-bit) color format
|
||||
|
||||
.. data:: framebuf.GS8
|
||||
|
||||
Grayscale (8-bit) color format
|
@ -1,12 +1,10 @@
|
||||
:mod:`gc` -- control the garbage collector
|
||||
==========================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
|
||||
.. module:: gc
|
||||
:synopsis: control the garbage collector
|
||||
|
||||
|see_cpython_module| :mod:`cpython:gc`.
|
||||
|see_cpython_module| :mod:`python:gc`.
|
||||
|
||||
Functions
|
||||
---------
|
||||
@ -26,7 +24,7 @@ Functions
|
||||
|
||||
.. function:: mem_alloc()
|
||||
|
||||
Return the number of bytes of heap RAM that are allocated.
|
||||
Return the number of bytes of heap RAM that are allocated by Python code.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
@ -35,8 +33,8 @@ Functions
|
||||
|
||||
.. function:: mem_free()
|
||||
|
||||
Return the number of bytes of available heap RAM, or -1 if this amount
|
||||
is not known.
|
||||
Return the number of bytes of heap RAM that is available for Python
|
||||
code to allocate, or -1 if this amount is not known.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
@ -63,6 +61,6 @@ Functions
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
This function is a a MicroPython extension. CPython has a similar
|
||||
This function is a MicroPython extension. CPython has a similar
|
||||
function - ``set_threshold()``, but due to different GC
|
||||
implementations, its signature and semantics are different.
|
||||
|
@ -6,7 +6,7 @@
|
||||
.. module:: heapq
|
||||
:synopsis: heap queue algorithm
|
||||
|
||||
|see_cpython_module| :mod:`cpython:heapq`.
|
||||
|see_cpython_module| :mod:`python:heapq`.
|
||||
|
||||
This module implements the
|
||||
`min heap queue algorithm <https://en.wikipedia.org/wiki/Heap_%28data_structure%29>`_.
|
||||
|
@ -1,25 +1,23 @@
|
||||
.. _micropython_lib:
|
||||
|
||||
MicroPython libraries
|
||||
=====================
|
||||
Standard Libraries
|
||||
==================
|
||||
|
||||
Python standard libraries and micro-libraries
|
||||
---------------------------------------------
|
||||
Python standard libraries
|
||||
-------------------------
|
||||
|
||||
The libraries below are inherited from MicroPython.
|
||||
They are similar to the standard Python libraries with the same name.
|
||||
They implement a subset of or a variant of the corresponding
|
||||
standard Python library.
|
||||
The libraries below implement a subset of the corresponding
|
||||
standard Python (CPython) library. They are implemented in C, not Python.
|
||||
|
||||
CircuitPython's long-term goal is that code written in CircuitPython
|
||||
using Python standard libraries will be runnable on CPython without changes.
|
||||
|
||||
These libraries are not enabled on CircuitPython builds with
|
||||
limited flash memory, usually on non-Express builds:
|
||||
limited flash memory:
|
||||
``binascii``, ``errno``, ``json``, ``re``.
|
||||
|
||||
These libraries are not currently enabled in any CircuitPython build, but may be in the future:
|
||||
``ctypes``
|
||||
``ctypes``, ``platform``
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
@ -33,16 +31,17 @@ These libraries are not currently enabled in any CircuitPython build, but may be
|
||||
gc.rst
|
||||
io.rst
|
||||
json.rst
|
||||
platform.rst
|
||||
re.rst
|
||||
sys.rst
|
||||
ctypes.rst
|
||||
select.rst
|
||||
|
||||
Omitted functions in the ``string`` library
|
||||
-------------------------------------------
|
||||
Omitted ``string`` functions
|
||||
----------------------------
|
||||
|
||||
A few string operations are not enabled on small builds
|
||||
(usually non-Express), due to limited flash memory:
|
||||
due to limited flash memory:
|
||||
``string.center()``, ``string.partition()``, ``string.splitlines()``,
|
||||
``string.reversed()``.
|
||||
|
||||
@ -50,13 +49,10 @@ A few string operations are not enabled on small builds
|
||||
CircuitPython/MicroPython-specific libraries
|
||||
--------------------------------------------
|
||||
|
||||
Functionality specific to the CircuitPython/MicroPython implementation is available in
|
||||
the following libraries. These libraries may change significantly or be removed in future
|
||||
versions of CircuitPython.
|
||||
Functionality specific to the CircuitPython/MicroPython implementations is available in
|
||||
the following libraries.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
btree.rst
|
||||
framebuf.rst
|
||||
micropython.rst
|
||||
|
@ -1,10 +1,10 @@
|
||||
:mod:`io` -- input/output streams
|
||||
==================================
|
||||
=================================
|
||||
|
||||
.. module:: io
|
||||
:synopsis: input/output streams
|
||||
|
||||
|see_cpython_module| :mod:`cpython:io`.
|
||||
|see_cpython_module| :mod:`python:io`.
|
||||
|
||||
This module contains additional types of ``stream`` (file-like) objects
|
||||
and helper functions.
|
||||
@ -112,3 +112,20 @@ Classes
|
||||
.. method:: getvalue()
|
||||
|
||||
Get the current contents of the underlying buffer which holds data.
|
||||
|
||||
.. class:: StringIO(alloc_size)
|
||||
:noindex:
|
||||
.. class:: BytesIO(alloc_size)
|
||||
:noindex:
|
||||
|
||||
Create an empty `StringIO`/`BytesIO` object, preallocated to hold up
|
||||
to *alloc_size* number of bytes. That means that writing that amount
|
||||
of bytes won't lead to reallocation of the buffer, and thus won't hit
|
||||
out-of-memory situation or lead to memory fragmentation. These constructors
|
||||
are a MicroPython extension and are recommended for usage only in special
|
||||
cases and in system-level libraries, not for end-user applications.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
These constructors are a MicroPython extension.
|
||||
|
@ -1,10 +1,10 @@
|
||||
:mod:`json` -- JSON encoding and decoding
|
||||
==========================================
|
||||
=========================================
|
||||
|
||||
.. module:: json
|
||||
:synopsis: JSON encoding and decoding
|
||||
|
||||
|see_cpython_module| :mod:`cpython:json`.
|
||||
|see_cpython_module| :mod:`python:json`.
|
||||
|
||||
This modules allows to convert between Python objects and the JSON
|
||||
data format.
|
||||
@ -12,14 +12,20 @@ data format.
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: dump(obj, stream)
|
||||
.. function:: dump(obj, stream, separators=None)
|
||||
|
||||
Serialise ``obj`` to a JSON string, writing it to the given *stream*.
|
||||
|
||||
.. function:: dumps(obj)
|
||||
If specified, separators should be an ``(item_separator, key_separator)``
|
||||
tuple. The default is ``(', ', ': ')``. To get the most compact JSON
|
||||
representation, you should specify ``(',', ':')`` to eliminate whitespace.
|
||||
|
||||
.. function:: dumps(obj, separators=None)
|
||||
|
||||
Return ``obj`` represented as a JSON string.
|
||||
|
||||
The arguments have the same meaning as in `dump`.
|
||||
|
||||
.. function:: load(stream)
|
||||
|
||||
Parse the given ``stream``, interpreting it as a JSON string and
|
||||
|
@ -1,7 +1,5 @@
|
||||
:mod:`micropython` -- access and control MicroPython internals
|
||||
==============================================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
:mod:`micropython` -- MicroPython extensions and internals
|
||||
==========================================================
|
||||
|
||||
.. module:: micropython
|
||||
:synopsis: access and control MicroPython internals
|
||||
@ -11,7 +9,7 @@ Functions
|
||||
|
||||
.. function:: const(expr)
|
||||
|
||||
Used to declare that the expression is a constant so that the compile can
|
||||
Used to declare that the expression is a constant so that the compiler can
|
||||
optimise it. The use of this function should be as follows::
|
||||
|
||||
from micropython import const
|
||||
@ -28,111 +26,3 @@ Functions
|
||||
provided as part of the :mod:`micropython` module mainly so that scripts can be
|
||||
written which run under both CPython and MicroPython, by following the above
|
||||
pattern.
|
||||
|
||||
.. function:: opt_level([level])
|
||||
|
||||
If *level* is given then this function sets the optimisation level for subsequent
|
||||
compilation of scripts, and returns ``None``. Otherwise it returns the current
|
||||
optimisation level.
|
||||
|
||||
The optimisation level controls the following compilation features:
|
||||
|
||||
- Assertions: at level 0 assertion statements are enabled and compiled into the
|
||||
bytecode; at levels 1 and higher assertions are not compiled.
|
||||
- Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``;
|
||||
at levels 1 and higher it expands to ``False``.
|
||||
- Source-code line numbers: at levels 0, 1 and 2 source-code line number are
|
||||
stored along with the bytecode so that exceptions can report the line number
|
||||
they occurred at; at levels 3 and higher line numbers are not stored.
|
||||
|
||||
The default optimisation level is usually level 0.
|
||||
|
||||
.. function:: mem_info([verbose])
|
||||
|
||||
Print information about currently used memory. If the *verbose* argument
|
||||
is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the amount of stack and heap used. In verbose mode it prints out
|
||||
the entire heap indicating which blocks are used and which are free.
|
||||
|
||||
.. function:: qstr_info([verbose])
|
||||
|
||||
Print information about currently interned strings. If the *verbose*
|
||||
argument is given then extra information is printed.
|
||||
|
||||
The information that is printed is implementation dependent, but currently
|
||||
includes the number of interned strings and the amount of RAM they use. In
|
||||
verbose mode it prints out the names of all RAM-interned strings.
|
||||
|
||||
.. function:: stack_use()
|
||||
|
||||
Return an integer representing the current amount of stack that is being
|
||||
used. The absolute value of this is not particularly useful, rather it
|
||||
should be used to compute differences in stack usage at different points.
|
||||
|
||||
.. function:: heap_lock()
|
||||
.. function:: heap_unlock()
|
||||
.. function:: heap_locked()
|
||||
|
||||
Lock or unlock the heap. When locked no memory allocation can occur and a
|
||||
``MemoryError`` will be raised if any heap allocation is attempted.
|
||||
`heap_locked()` returns a true value if the heap is currently locked.
|
||||
|
||||
These functions can be nested, ie `heap_lock()` can be called multiple times
|
||||
in a row and the lock-depth will increase, and then `heap_unlock()` must be
|
||||
called the same number of times to make the heap available again.
|
||||
|
||||
Both `heap_unlock()` and `heap_locked()` return the current lock depth
|
||||
(after unlocking for the former) as a non-negative integer, with 0 meaning
|
||||
the heap is not locked.
|
||||
|
||||
If the REPL becomes active with the heap locked then it will be forcefully
|
||||
unlocked.
|
||||
|
||||
Note: `heap_locked()` is not enabled on most ports by default,
|
||||
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
|
||||
|
||||
.. function:: kbd_intr(chr)
|
||||
|
||||
Set the character that will raise a `KeyboardInterrupt` exception. By
|
||||
default this is set to 3 during script execution, corresponding to Ctrl-C.
|
||||
Passing -1 to this function will disable capture of Ctrl-C, and passing 3
|
||||
will restore it.
|
||||
|
||||
This function can be used to prevent the capturing of Ctrl-C on the
|
||||
incoming stream of characters that is usually used for the REPL, in case
|
||||
that stream is used for other purposes.
|
||||
|
||||
.. function:: schedule(func, arg)
|
||||
|
||||
Schedule the function *func* to be executed "very soon". The function
|
||||
is passed the value *arg* as its single argument. "Very soon" means that
|
||||
the MicroPython runtime will do its best to execute the function at the
|
||||
earliest possible time, given that it is also trying to be efficient, and
|
||||
that the following conditions hold:
|
||||
|
||||
- A scheduled function will never preempt another scheduled function.
|
||||
- Scheduled functions are always executed "between opcodes" which means
|
||||
that all fundamental Python operations (such as appending to a list)
|
||||
are guaranteed to be atomic.
|
||||
- A given port may define "critical regions" within which scheduled
|
||||
functions will never be executed. Functions may be scheduled within
|
||||
a critical region but they will not be executed until that region
|
||||
is exited. An example of a critical region is a preempting interrupt
|
||||
handler (an IRQ).
|
||||
|
||||
A use for this function is to schedule a callback from a preempting IRQ.
|
||||
Such an IRQ puts restrictions on the code that runs in the IRQ (for example
|
||||
the heap may be locked) and scheduling a function to call later will lift
|
||||
those restrictions.
|
||||
|
||||
Note: If `schedule()` is called from a preempting IRQ, when memory
|
||||
allocation is not allowed and the callback to be passed to `schedule()` is
|
||||
a bound method, passing this directly will fail. This is because creating a
|
||||
reference to a bound method causes memory allocation. A solution is to
|
||||
create a reference to the method in the class constructor and to pass that
|
||||
reference to `schedule()`.
|
||||
|
||||
There is a finite queue to hold the scheduled functions and `schedule()`
|
||||
will raise a `RuntimeError` if the queue is full.
|
||||
|
38
docs/library/platform.rst
Normal file
38
docs/library/platform.rst
Normal file
@ -0,0 +1,38 @@
|
||||
:mod:`platform` -- access to underlying platform’s identifying data
|
||||
===================================================================
|
||||
|
||||
.. module:: platform
|
||||
:synopsis: access to underlying platform’s identifying data
|
||||
|
||||
|see_cpython_module| :mod:`python:platform`.
|
||||
|
||||
This module tries to retrieve as much platform-identifying data as possible. It
|
||||
makes this information available via function APIs.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: platform()
|
||||
|
||||
Returns a string identifying the underlying platform. This string is composed
|
||||
of several substrings in the following order, delimited by dashes (``-``):
|
||||
|
||||
- the name of the platform system (e.g. Unix, Windows or MicroPython)
|
||||
- the MicroPython version
|
||||
- the architecture of the platform
|
||||
- the version of the underlying platform
|
||||
- the concatenation of the name of the libc that MicroPython is linked to
|
||||
and its corresponding version.
|
||||
|
||||
For example, this could be
|
||||
``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``.
|
||||
|
||||
.. function:: python_compiler()
|
||||
|
||||
Returns a string identifying the compiler used for compiling MicroPython.
|
||||
|
||||
.. function:: libc_ver()
|
||||
|
||||
Returns a tuple of strings *(lib, version)*, where *lib* is the name of the
|
||||
libc that MicroPython is linked to, and *version* the corresponding version
|
||||
of this libc.
|
@ -1,10 +1,10 @@
|
||||
:mod:`re` -- simple regular expressions
|
||||
========================================
|
||||
=======================================
|
||||
|
||||
.. module:: re
|
||||
:synopsis: regular expressions
|
||||
|
||||
|see_cpython_module| :mod:`cpython:re`.
|
||||
|see_cpython_module| :mod:`python:re`.
|
||||
|
||||
This module implements regular expression operations. Regular expression
|
||||
syntax supported is a subset of CPython ``re`` module (and actually is
|
||||
|
@ -1,8 +1,6 @@
|
||||
:mod:`select` -- wait for events on a set of streams
|
||||
====================================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
|
||||
.. module:: select
|
||||
:synopsis: wait for events on a set of streams
|
||||
|
||||
@ -86,7 +84,7 @@ Methods
|
||||
.. method:: poll.ipoll(timeout=-1, flags=0, /)
|
||||
|
||||
Like :meth:`poll.poll`, but instead returns an iterator which yields a
|
||||
``callee-owned tuples``. This function provides efficient, allocation-free
|
||||
"callee-owned tuple". This function provides an efficient, allocation-free
|
||||
way to poll on streams.
|
||||
|
||||
If *flags* is 1, one-shot behaviour for events is employed: streams for
|
||||
|
@ -1,12 +1,10 @@
|
||||
:mod:`sys` -- system specific functions
|
||||
========================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
=======================================
|
||||
|
||||
.. module:: sys
|
||||
:synopsis: system specific functions
|
||||
|
||||
|see_cpython_module| :mod:`cpython:sys`.
|
||||
|see_cpython_module| :mod:`python:sys`.
|
||||
|
||||
Functions
|
||||
---------
|
||||
@ -35,6 +33,8 @@ Constants
|
||||
|
||||
* *name* - string "circuitpython"
|
||||
* *version* - tuple (major, minor, micro), e.g. (1, 7, 0)
|
||||
* *_machine* - string describing the underlying machine
|
||||
* *_mpy* - supported mpy file-format version (optional attribute)
|
||||
|
||||
This object is the recommended way to distinguish CircuitPython from other
|
||||
Python implementations (note that it still may not exist in the very
|
||||
@ -97,6 +97,12 @@ Constants
|
||||
If you need to check whether your program runs on CircuitPython (vs other
|
||||
Python implementation), use `sys.implementation` instead.
|
||||
|
||||
.. data:: ps1
|
||||
ps2
|
||||
|
||||
Mutable attributes holding strings, which are used for the REPL prompt. The defaults
|
||||
give the standard Python prompt of ``>>>`` and ``...``.
|
||||
|
||||
.. data:: stderr
|
||||
|
||||
Standard error ``stream``.
|
||||
@ -109,6 +115,14 @@ Constants
|
||||
|
||||
Standard output ``stream``.
|
||||
|
||||
.. data:: tracebacklimit
|
||||
|
||||
A mutable attribute holding an integer value which is the maximum number of traceback
|
||||
entries to store in an exception. Set to 0 to disable adding tracebacks. Defaults
|
||||
to 1000.
|
||||
|
||||
Note: this is not available on all ports.
|
||||
|
||||
.. data:: version
|
||||
|
||||
Python language version that this implementation conforms to, as a string.
|
||||
|
60
docs/pdf.rst
Normal file
60
docs/pdf.rst
Normal file
@ -0,0 +1,60 @@
|
||||
:orphan:
|
||||
|
||||
Adafruit CircuitPython API Reference
|
||||
====================================
|
||||
|
||||
Welcome to the API reference documentation for Adafruit CircuitPython.
|
||||
This contains low-level API reference docs which may link out to separate
|
||||
*"getting started"* guides. `Adafruit <https://adafruit.com>`_ has many
|
||||
excellent tutorials available through the
|
||||
`Adafruit Learning System <https://learn.adafruit.com/>`_.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
../README.rst
|
||||
libraries.rst
|
||||
workflows
|
||||
environment.rst
|
||||
troubleshooting.rst
|
||||
../CONTRIBUTING
|
||||
../BUILDING
|
||||
../WEBUSB_README
|
||||
supported_ports.rst
|
||||
|
||||
Design and porting reference
|
||||
----------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
design_guide
|
||||
porting
|
||||
common_hal
|
||||
|
||||
API Reference
|
||||
----------------------
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
:maxdepth: 3
|
||||
|
||||
library/index.rst
|
||||
../shared-bindings/*/index
|
||||
../shared-bindings/help
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
reference/glossary.rst
|
||||
../CODE_OF_CONDUCT
|
||||
../docs/LICENSE
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
@ -1,3 +1,4 @@
|
||||
index.rst README.html
|
||||
shared-bindings//__init__.rst shared-bindings//
|
||||
shared-bindings/_bleio/Adapter.rst shared-bindings/_bleio/#_bleio.Adapter
|
||||
shared-bindings/_bleio/Address.rst shared-bindings/_bleio/#_bleio.Address
|
||||
@ -83,8 +84,10 @@ shared-bindings/frequencyio/__init__.rst shared-bindings/frequencyio/
|
||||
shared-bindings/gnss/__init__.rst shared-bindings/gnss/
|
||||
shared-bindings/i2cperipheral/__init__.rst shared-bindings/i2cperipheral/
|
||||
shared-bindings/i2csecondary/__init__.rst shared-bindings/i2csecondary/
|
||||
shared-bindings/i2cslave/I2CSlave.rst shared-bindings/i2cperipheral/#i2cperipheral.I2CPeripheral
|
||||
shared-bindings/i2cslave/I2CSlaveRequest.rst shared-bindings/i2cperipheral/#i2cperipheral.I2CPeripheralRequest
|
||||
shared-bindings/i2cslave/I2CSlave.rst shared-bindings/i2cperipheral/#i2ctarget.Target
|
||||
shared-bindings/i2cslave/I2CSlaveRequest.rst shared-bindings/i2cperipheral/#i2ctarget.I2CTargetRequest
|
||||
shared-bindings/i2cperipheral/I2CPeripheral.rst shared-bindings/i2ctarget/#i2ctarget.I2CTarget
|
||||
shared-bindings/i2cperipheral/I2CPeripheralRequest.rst shared-bindings/i2ctarget/#i2ctarget.I2CTargetRequest
|
||||
shared-bindings/math/__init__.rst shared-bindings/math/
|
||||
shared-bindings/microcontroller/Pin.rst shared-bindings/microcontroller/#microcontroller.Pin
|
||||
shared-bindings/microcontroller/Processor.rst shared-bindings/microcontroller/#microcontroller.Processor
|
||||
|
@ -32,7 +32,7 @@ Glossary
|
||||
|
||||
callee-owned tuple
|
||||
This is a MicroPython-specific construct where, for efficiency
|
||||
reasons, some built-in functions or methods may re-use the same
|
||||
reasons, some built-in functions or methods may reuse the same
|
||||
underlying tuple object to return data. This avoids having to allocate
|
||||
a new tuple for every call, and reduces heap fragmentation. Programs
|
||||
should not hold references to callee-owned tuples and instead only
|
||||
@ -52,7 +52,7 @@ Glossary
|
||||
cross-compiler
|
||||
Also known as ``mpy-cross``. This tool runs on your PC and converts a
|
||||
:term:`.py file` containing MicroPython code into a :term:`.mpy file`
|
||||
containing MicroPython bytecode. This means it loads faster (the board
|
||||
containing MicroPython :term:`bytecode`. This means it loads faster (the board
|
||||
doesn't have to compile the code), and uses less space on flash (the
|
||||
bytecode is more space efficient).
|
||||
|
||||
@ -112,6 +112,24 @@ Glossary
|
||||
require much less power. MicroPython is designed to be small and
|
||||
optimized enough to run on an average modern microcontroller.
|
||||
|
||||
micropython-lib
|
||||
MicroPython is (usually) distributed as a single executable/binary
|
||||
file with just few builtin modules. There is no extensive standard
|
||||
library comparable with :term:`CPython`'s. Instead, there is a related,
|
||||
but separate project `micropython-lib
|
||||
<https://github.com/micropython/micropython-lib>`_ which provides
|
||||
implementations for many modules from CPython's standard library.
|
||||
|
||||
Some of the modules are implemented in pure Python, and are able to
|
||||
be used on all ports. However, the majority of these modules use
|
||||
:term:`FFI` to access operating system functionality, and as such can
|
||||
only be used on the :term:`MicroPython Unix port` (with limited support
|
||||
for Windows).
|
||||
|
||||
Unlike the :term:`CPython` stdlib, micropython-lib modules are
|
||||
intended to be installed individually - either using manual copying or
|
||||
using :term:`mip`.
|
||||
|
||||
MicroPython port
|
||||
MicroPython supports different :term:`boards <board>`, RTOSes, and
|
||||
OSes, and can be relatively easily adapted to new systems. MicroPython
|
||||
@ -133,16 +151,26 @@ Glossary
|
||||
machine-independent features. It can also function in a similar way to
|
||||
:term:`CPython`'s ``python`` executable.
|
||||
|
||||
mip
|
||||
A package installer for MicroPython (mip - "mip installs packages"). It
|
||||
installs MicroPython packages either from :term:`micropython-lib`,
|
||||
GitHub, or arbitrary URLs. mip can be used on-device on
|
||||
network-capable boards, and internally by tools such
|
||||
as :term:`mpremote`.
|
||||
|
||||
mpremote
|
||||
A tool for interacting with a MicroPython device.
|
||||
|
||||
.mpy file
|
||||
The output of the :term:`cross-compiler`. A compiled form of a
|
||||
:term:`.py file` that contains MicroPython bytecode instead of Python
|
||||
source code.
|
||||
:term:`.py file` that contains MicroPython :term:`bytecode` instead of
|
||||
Python source code.
|
||||
|
||||
native
|
||||
Usually refers to "native code", i.e. machine code for the target
|
||||
microcontroller (such as ARM Thumb, Xtensa, x86/x64). The ``@native``
|
||||
decorator can be applied to a MicroPython function to generate native
|
||||
code instead of bytecode for that function, which will likely be
|
||||
code instead of :term:`bytecode` for that function, which will likely be
|
||||
faster but use more RAM.
|
||||
|
||||
port
|
||||
@ -159,7 +187,7 @@ Glossary
|
||||
typically accessible on a host PC via USB.
|
||||
|
||||
stream
|
||||
Also known as a "file-like object". An Python object which provides
|
||||
Also known as a "file-like object". A Python object which provides
|
||||
sequential read-write access to the underlying data. A stream object
|
||||
implements a corresponding interface, which consists of methods like
|
||||
``read()``, ``write()``, ``readinto()``, ``seek()``, ``flush()``,
|
||||
@ -173,3 +201,12 @@ Glossary
|
||||
peripheral that sends data over a pair of pins (TX & RX). Many boards
|
||||
include a way to make at least one of the UARTs available to a host PC
|
||||
as a serial port over USB.
|
||||
|
||||
upip
|
||||
A now-obsolete package manager for MicroPython, inspired
|
||||
by :term:`CPython`'s pip, but much smaller and with reduced
|
||||
functionality. See its replacement, :term:`mip`.
|
||||
|
||||
webrepl
|
||||
A way of connecting to the REPL (and transferring files) on a device
|
||||
over the internet from a browser. See https://micropython.org/webrepl
|
||||
|
@ -1,6 +1,13 @@
|
||||
# Derived from code on Eric Holscher's blog, found at:
|
||||
# https://www.ericholscher.com/blog/2016/jul/25/integrating-jinja-rst-sphinx/
|
||||
|
||||
import re
|
||||
|
||||
def render_with_jinja(docname, source):
|
||||
if re.search('^\s*.. jinja$', source[0], re.M):
|
||||
return True
|
||||
return False
|
||||
|
||||
def rstjinja(app, docname, source):
|
||||
"""
|
||||
Render our pages as a jinja template for fancy templating goodness.
|
||||
@ -9,12 +16,12 @@ def rstjinja(app, docname, source):
|
||||
if app.builder.format not in ("html", "latex"):
|
||||
return
|
||||
|
||||
# we only want our one jinja template to run through this func
|
||||
if "shared-bindings/support_matrix" not in docname:
|
||||
# we only want specific files to run through this func
|
||||
if not render_with_jinja(docname, source):
|
||||
return
|
||||
|
||||
src = rendered = source[0]
|
||||
print(docname)
|
||||
print(f"rendering {docname} as jinja templates")
|
||||
|
||||
if app.builder.format == "html":
|
||||
rendered = app.builder.templates.render_string(
|
||||
|
@ -63,34 +63,29 @@ ALIASES_BRAND_NAMES = {
|
||||
}
|
||||
|
||||
ADDITIONAL_MODULES = {
|
||||
"_asyncio": "MICROPY_PY_UASYNCIO",
|
||||
"_asyncio": "MICROPY_PY_ASYNCIO",
|
||||
"adafruit_bus_device": "CIRCUITPY_BUSDEVICE",
|
||||
"adafruit_pixelbuf": "CIRCUITPY_PIXELBUF",
|
||||
"array": "CIRCUITPY_ARRAY",
|
||||
# always available, so depend on something that's always 1.
|
||||
"builtins": "CIRCUITPY",
|
||||
"builtins.pow3": "CIRCUITPY_BUILTINS_POW3",
|
||||
"busio.SPI": "CIRCUITPY_BUSIO_SPI",
|
||||
"busio.UART": "CIRCUITPY_BUSIO_UART",
|
||||
"collections": "CIRCUITPY_COLLECTIONS",
|
||||
"fontio": "CIRCUITPY_DISPLAYIO",
|
||||
"io": "CIRCUITPY_IO",
|
||||
"select": "MICROPY_PY_USELECT_SELECT",
|
||||
"terminalio": "CIRCUITPY_DISPLAYIO",
|
||||
"keypad.KeyMatrix": "CIRCUITPY_KEYPAD_KEYMATRIX",
|
||||
"keypad.Keys": "CIRCUITPY_KEYPAD_KEYS",
|
||||
"keypad.ShiftRegisterKeys": "CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS",
|
||||
"os.getenv": "CIRCUITPY_OS_GETENV",
|
||||
"select": "MICROPY_PY_SELECT_SELECT",
|
||||
"sys": "CIRCUITPY_SYS",
|
||||
"terminalio": "CIRCUITPY_DISPLAYIO",
|
||||
"usb": "CIRCUITPY_USB_HOST",
|
||||
}
|
||||
|
||||
MODULES_NOT_IN_BINDINGS = [
|
||||
"_asyncio",
|
||||
"array",
|
||||
"binascii",
|
||||
"builtins",
|
||||
"collections",
|
||||
"errno",
|
||||
"json",
|
||||
"re",
|
||||
"select",
|
||||
"sys",
|
||||
"ulab",
|
||||
]
|
||||
MODULES_NOT_IN_BINDINGS = [ "binascii", "errno", "json", "re", "ulab" ]
|
||||
|
||||
FROZEN_EXCLUDES = ["examples", "docs", "tests", "utils", "conf.py", "setup.py"]
|
||||
"""Files and dirs at the root of a frozen directory that should be ignored.
|
||||
@ -117,7 +112,7 @@ def get_bindings():
|
||||
bindings_modules = []
|
||||
for d in get_circuitpython_root_dir().glob("ports/*/bindings"):
|
||||
bindings_modules.extend(module.name for module in d.iterdir() if d.is_dir())
|
||||
return shared_bindings_modules + bindings_modules + MODULES_NOT_IN_BINDINGS
|
||||
return shared_bindings_modules + bindings_modules + MODULES_NOT_IN_BINDINGS + list(ADDITIONAL_MODULES.keys())
|
||||
|
||||
|
||||
def get_board_mapping():
|
||||
@ -148,50 +143,21 @@ def get_board_mapping():
|
||||
return boards
|
||||
|
||||
|
||||
def read_mpconfig():
|
||||
"""Open 'circuitpy_mpconfig.mk' and return the contents."""
|
||||
configs = []
|
||||
cpy_mpcfg = get_circuitpython_root_dir() / "py" / "circuitpy_mpconfig.mk"
|
||||
with open(cpy_mpcfg) as mpconfig:
|
||||
configs = mpconfig.read()
|
||||
|
||||
return configs
|
||||
|
||||
|
||||
def build_module_map():
|
||||
"""Establish the base of the JSON file, based on the contents from
|
||||
`configs`. Base will contain module names, if they're part of
|
||||
the `FULL_BUILD`, or their default value (0, 1, or a list of
|
||||
modules that determine default [see audiocore, audiomixer, etc.]).
|
||||
|
||||
`configs`. Base contains the module name and the controlling C macro name.
|
||||
"""
|
||||
base = dict()
|
||||
modules = get_bindings()
|
||||
configs = read_mpconfig()
|
||||
full_build = False
|
||||
for module in modules:
|
||||
full_name = module
|
||||
if module in ADDITIONAL_MODULES:
|
||||
search_identifier = ADDITIONAL_MODULES[module]
|
||||
else:
|
||||
search_identifier = "CIRCUITPY_" + module.lstrip("_").upper()
|
||||
re_pattern = f"{re.escape(search_identifier)}\s*\??=\s*(.+)"
|
||||
find_config = re.findall(re_pattern, configs)
|
||||
if not find_config:
|
||||
continue
|
||||
find_config = ", ".join([x.strip("$()") for x in find_config])
|
||||
|
||||
full_build = int("CIRCUITPY_FULL_BUILD" in find_config)
|
||||
if not full_build:
|
||||
default_val = find_config
|
||||
else:
|
||||
default_val = "None"
|
||||
|
||||
base[module] = {
|
||||
"name": full_name,
|
||||
"full_build": str(full_build),
|
||||
"default_value": default_val,
|
||||
"excluded": {},
|
||||
"key": search_identifier,
|
||||
}
|
||||
|
||||
@ -199,15 +165,16 @@ def build_module_map():
|
||||
|
||||
|
||||
def get_settings_from_makefile(port_dir, board_name):
|
||||
"""Invoke make in a mode which prints the database, then parse it for
|
||||
settings.
|
||||
"""Invoke make to print the value of critical build settings
|
||||
|
||||
This means that the effect of all Makefile directives is taken
|
||||
into account, without having to re-encode the logic that sets them
|
||||
in this script, something that has proved error-prone
|
||||
|
||||
This list must explicitly include any setting queried by tools/ci_set_matrix.py.
|
||||
"""
|
||||
contents = subprocess.run(
|
||||
["make", "-C", port_dir, f"BOARD={board_name}", "-qp", "print-CC"],
|
||||
["make", "-C", port_dir, "-f", "Makefile", f"BOARD={board_name}", "print-CFLAGS", "print-CIRCUITPY_BUILD_EXTENSIONS", "print-FROZEN_MPY_DIRS", "print-SRC_PATTERNS", "print-SRC_SUPERVISOR"],
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
stdout=subprocess.PIPE,
|
||||
@ -223,9 +190,10 @@ def get_settings_from_makefile(port_dir, board_name):
|
||||
|
||||
settings = {}
|
||||
for line in contents.stdout.split("\n"):
|
||||
# Handle both = and := definitions.
|
||||
m = re.match(r"^([A-Z][A-Z0-9_]*) :?= (.*)$", line)
|
||||
if m:
|
||||
if line.startswith('CFLAGS ='):
|
||||
for m in re.findall(r'-D([A-Z][A-Z0-9_]*)=(\d+)', line):
|
||||
settings[m[0]] = m[1]
|
||||
elif m := re.match(r"^([A-Z][A-Z0-9_]*) = (.*)$", line):
|
||||
settings[m.group(1)] = m.group(2)
|
||||
|
||||
return settings
|
||||
@ -247,12 +215,12 @@ def get_repository_url(directory):
|
||||
with open(readme, "r") as fp:
|
||||
for line in fp.readlines():
|
||||
if m := re.match(
|
||||
"\s+:target:\s+(http\S+(docs.circuitpython|readthedocs)\S+)\s*",
|
||||
r"\s+:target:\s+(http\S+(docs.circuitpython|readthedocs)\S+)\s*",
|
||||
line,
|
||||
):
|
||||
path = m.group(1)
|
||||
break
|
||||
if m := re.search("<(http[^>]+)>", line):
|
||||
if m := re.search(r"<(http[^>]+)>", line):
|
||||
path = m.group(1)
|
||||
break
|
||||
if path is None:
|
||||
@ -268,6 +236,10 @@ def get_repository_url(directory):
|
||||
repository_urls[directory] = path
|
||||
return path
|
||||
|
||||
def remove_prefix(s, prefix):
|
||||
if not s.startswith(prefix):
|
||||
raise ValueError(f"{s=} does not start with {prefix=}")
|
||||
return s.removeprefix(prefix)
|
||||
|
||||
def frozen_modules_from_dirs(frozen_mpy_dirs, withurl):
|
||||
"""
|
||||
@ -280,7 +252,8 @@ def frozen_modules_from_dirs(frozen_mpy_dirs, withurl):
|
||||
"""
|
||||
frozen_modules = []
|
||||
for frozen_path in filter(lambda x: x, frozen_mpy_dirs.split(" ")):
|
||||
source_dir = get_circuitpython_root_dir() / frozen_path[7:]
|
||||
frozen_path = remove_prefix(frozen_path, '../../')
|
||||
source_dir = get_circuitpython_root_dir() / frozen_path
|
||||
url_repository = get_repository_url(source_dir)
|
||||
for sub in source_dir.glob("*"):
|
||||
if sub.name in FROZEN_EXCLUDES:
|
||||
|
5
docs/static/custom.css
vendored
Normal file
5
docs/static/custom.css
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/* Workaround to force Sphinx to render tables to 100% and wordwrap */
|
||||
/* See https://stackoverflow.com/questions/69359978/grid-table-does-not-word-wrap for more details */
|
||||
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||
white-space: inherit;
|
||||
}
|
@ -12,10 +12,13 @@ is limited.
|
||||
:maxdepth: 2
|
||||
|
||||
../ports/atmel-samd/README
|
||||
../ports/broadcom/README
|
||||
../ports/cxd56/README
|
||||
../ports/espressif/README
|
||||
../ports/litex/README
|
||||
../ports/mimxrt10xx/README
|
||||
../ports/nrf/README
|
||||
../ports/raspberrypi/README
|
||||
../ports/silabs/README
|
||||
../ports/stm/README
|
||||
../ports/unix/README
|
||||
|
@ -68,12 +68,14 @@ conflicts with user created NUS services.
|
||||
Read-only characteristic that returns the UTF-8 encoded version string.
|
||||
|
||||
## Web
|
||||
If the keys `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD` are set in `settings.toml`,
|
||||
CircuitPython will automatically connect to the given Wi-Fi network on boot and upon reload.
|
||||
|
||||
The web workflow is depends on adding Wi-Fi credentials into the `settings.toml` file. The keys are
|
||||
`CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD`. Once these are defined, CircuitPython will
|
||||
automatically connect to the network and start the webserver used for the workflow. The webserver
|
||||
is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS. The name
|
||||
of the board as advertised to the network can be overridden by `CIRCUITPY_WEB_INSTANCE_NAME`.
|
||||
If `CIRCUITPY_WEB_API_PASSWORD` is also set, the web workflow will also start.
|
||||
The web workflow will only be enabled if the Wi-Fi connection succeeds upon boot.
|
||||
|
||||
The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS.
|
||||
The name of the board as advertised to the network can be overridden by `CIRCUITPY_WEB_INSTANCE_NAME`.
|
||||
|
||||
Here is an example `/settings.toml`:
|
||||
|
||||
@ -82,7 +84,7 @@ Here is an example `/settings.toml`:
|
||||
CIRCUITPY_WIFI_SSID="scottswifi"
|
||||
CIRCUITPY_WIFI_PASSWORD="secretpassword"
|
||||
|
||||
# To enable modifying files from the web. Change this too!
|
||||
# To enable the the webserver. Change this too!
|
||||
# Leave the User field blank in the browser.
|
||||
CIRCUITPY_WEB_API_PASSWORD="passw0rd"
|
||||
|
||||
@ -94,6 +96,10 @@ MDNS is used to resolve [`circuitpython.local`](http://circuitpython.local) to a
|
||||
hostname of the form `cpy-XXXXXX.local`. The `XXXXXX` is based on network MAC address. The device
|
||||
also provides the MDNS service with service type `_circuitpython` and protocol `_tcp`.
|
||||
|
||||
Since port 80 (or the port assigned to `CIRCUITPY_WEB_API_PORT`) is used for web workflow, the `mdns`
|
||||
[module](https://docs.circuitpython.org/en/latest/shared-bindings/mdns/index.html#mdns.Server.advertise_service)
|
||||
can't advertise an additional service on that port.
|
||||
|
||||
### HTTP
|
||||
The web server is HTTP 1.1 and may use chunked responses so that it doesn't need to precompute
|
||||
content length.
|
||||
|
74
examples/natmod/README.md
Normal file
74
examples/natmod/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
# Dynamic Native Modules
|
||||
|
||||
Dynamic Native Modules are .mpy files that contain native machine code from a
|
||||
language other than Python. For more info see [the documentation]
|
||||
(https://docs.micropython.org/en/latest/develop/natmod.html).
|
||||
|
||||
This should not be confused with [User C Modules]
|
||||
(https://docs.micropython.org/en/latest/develop/cmodules.html) which are a
|
||||
mechanism to add additional out-of-tree modules into the firmware build.
|
||||
|
||||
## Examples
|
||||
|
||||
This directory contains several examples of writing dynamic native modules, in
|
||||
two main categories:
|
||||
|
||||
1. Feature examples.
|
||||
|
||||
* `features0` - A module containing a single "factorial" function which
|
||||
demonstrates working with integers.
|
||||
|
||||
* `features1` - A module that demonstrates some common tasks:
|
||||
- defining simple functions exposed to Python
|
||||
- defining local, helper C functions
|
||||
- defining constant integers and strings exposed to Python
|
||||
- getting and creating integer objects
|
||||
- creating Python lists
|
||||
- raising exceptions
|
||||
- allocating memory
|
||||
- BSS and constant data (rodata)
|
||||
- relocated pointers in rodata
|
||||
|
||||
* `features2` - This is a hybrid module containing both Python and C code,
|
||||
and additionally the C code is spread over multiple files. It also
|
||||
demonstrates using floating point (only when the target supports
|
||||
hardware floating point).
|
||||
|
||||
* `features3` - A module that shows how to use types, constant objects,
|
||||
and creating dictionary instances.
|
||||
|
||||
* `features4` - A module that demonstrates how to define a class.
|
||||
|
||||
2. Dynamic version of existing built-ins.
|
||||
|
||||
This provides a way to add missing functionality to firmware that doesn't
|
||||
include certain built-in modules. See the `heapq`, `random`, `re`,
|
||||
`deflate`, `btree`, and `framebuf` directories.
|
||||
|
||||
So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF`
|
||||
disabled (e.g. to save flash space), then it would not include the
|
||||
`framebuf` module. The `framebuf` native module provides a way to add the
|
||||
`framebuf` module dynamically.
|
||||
|
||||
The way these work is they define a dynamic native module which
|
||||
`#include`'s the original module and then does the necessary
|
||||
initialisation of the module's globals dict.
|
||||
|
||||
## Build instructions
|
||||
|
||||
To compile an example, you need to have the same toolchain available as
|
||||
required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M
|
||||
target. See the port instructions for details.
|
||||
|
||||
You also need to have the `pyelftools` Python package available, either via
|
||||
your system package manager or installed from PyPI in a virtual environment
|
||||
with `pip`.
|
||||
|
||||
Each example provides a Makefile. You should specify the `ARCH` argument to
|
||||
make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin):
|
||||
|
||||
```
|
||||
$ cd features0
|
||||
$ make ARCH=armv7m
|
||||
$ mpremote cp features0.mpy :
|
||||
```
|
@ -1,37 +0,0 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in btree so it can coexist)
|
||||
MOD = btree_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = btree_c.c btree_py.py
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
|
||||
BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error="(void)" -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA)
|
||||
CFLAGS += -I$(BTREE_DIR)/PORT/include
|
||||
CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
|
||||
|
||||
SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
|
||||
btree/bt_close.c \
|
||||
btree/bt_conv.c \
|
||||
btree/bt_delete.c \
|
||||
btree/bt_get.c \
|
||||
btree/bt_open.c \
|
||||
btree/bt_overflow.c \
|
||||
btree/bt_page.c \
|
||||
btree/bt_put.c \
|
||||
btree/bt_search.c \
|
||||
btree/bt_seq.c \
|
||||
btree/bt_split.c \
|
||||
btree/bt_utils.c \
|
||||
mpool/mpool.c \
|
||||
)
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
# btree needs gnu99 defined
|
||||
CFLAGS += -std=gnu99
|
@ -1,148 +0,0 @@
|
||||
#define MICROPY_PY_BTREE (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(__linux__)
|
||||
void *memcpy(void *dst, const void *src, size_t n) {
|
||||
return mp_fun_table.memmove_(dst, src, n);
|
||||
}
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
return mp_fun_table.memset_(s, c, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
return mp_fun_table.memmove_(dest, src, n);
|
||||
}
|
||||
|
||||
void *malloc(size_t n) {
|
||||
void *ptr = m_malloc(n, false);
|
||||
return ptr;
|
||||
}
|
||||
void *realloc(void *ptr, size_t n) {
|
||||
mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__);
|
||||
return NULL;
|
||||
}
|
||||
void *calloc(size_t n, size_t m) {
|
||||
void *ptr = m_malloc(n * m, false);
|
||||
// memory already cleared by conservative GC
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
m_free(ptr);
|
||||
}
|
||||
|
||||
void abort_(void) {
|
||||
nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError)));
|
||||
}
|
||||
|
||||
int native_errno;
|
||||
#if defined(__linux__)
|
||||
int *__errno_location (void)
|
||||
#else
|
||||
int *__errno (void)
|
||||
#endif
|
||||
{
|
||||
return &native_errno;
|
||||
}
|
||||
|
||||
ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) {
|
||||
mp_obj_base_t* o = stream;
|
||||
const mp_stream_p_t *stream_p = o->type->ext[0].protocol;
|
||||
mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
return -1;
|
||||
} else {
|
||||
return out_sz;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) {
|
||||
mp_obj_base_t* o = stream;
|
||||
const mp_stream_p_t *stream_p = o->type->ext[0].protocol;
|
||||
mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
return -1;
|
||||
} else {
|
||||
return out_sz;
|
||||
}
|
||||
}
|
||||
|
||||
off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) {
|
||||
const mp_obj_base_t* o = stream;
|
||||
const mp_stream_p_t *stream_p = o->type->ext[0].protocol;
|
||||
struct mp_stream_seek_t seek_s;
|
||||
seek_s.offset = offset;
|
||||
seek_s.whence = whence;
|
||||
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
return seek_s.offset;
|
||||
}
|
||||
|
||||
int mp_stream_posix_fsync(void *stream) {
|
||||
mp_obj_base_t* o = stream;
|
||||
const mp_stream_p_t *stream_p = o->type->ext[0].protocol;
|
||||
mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
mp_obj_full_type_t btree_type;
|
||||
|
||||
#include "extmod/modbtree.c"
|
||||
|
||||
mp_map_elem_t btree_locals_dict_table[8];
|
||||
STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
|
||||
|
||||
STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) {
|
||||
// Make sure we got a stream object
|
||||
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
|
||||
|
||||
BTREEINFO openinfo = {0};
|
||||
openinfo.flags = mp_obj_get_int(args[1]);
|
||||
openinfo.cachesize = mp_obj_get_int(args[2]);
|
||||
openinfo.psize = mp_obj_get_int(args[3]);
|
||||
openinfo.minkeypage = mp_obj_get_int(args[4]);
|
||||
DB *db = __bt_open(MP_OBJ_TO_PTR(args[0]), &btree_stream_fvtable, &openinfo, 0);
|
||||
if (db == NULL) {
|
||||
mp_raise_OSError(native_errno);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(btree_new(db, args[0]));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
btree_type.base.type = (void*)&mp_fun_table.type_type;
|
||||
btree_type.flags = MP_TYPE_FLAG_EXTENDED;
|
||||
btree_type.name = MP_QSTR_btree;
|
||||
btree_type.print = btree_print;
|
||||
btree_type.ext[0].getiter = btree_getiter;
|
||||
btree_type.ext[0].iternext = btree_iternext;
|
||||
btree_type.ext[0].binary_op = btree_binary_op;
|
||||
btree_type.ext[0].subscr = btree_subscr;
|
||||
btree_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) };
|
||||
btree_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) };
|
||||
btree_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) };
|
||||
btree_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) };
|
||||
btree_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) };
|
||||
btree_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) };
|
||||
btree_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) };
|
||||
btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) };
|
||||
btree_type.locals_dict = (void*)&btree_locals_dict;
|
||||
|
||||
mp_store_global(MP_QSTR__open, MP_OBJ_FROM_PTR(&btree_open_obj));
|
||||
mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL));
|
||||
mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
# Implemented in Python to support keyword arguments
|
||||
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
|
||||
return _open(stream, flags, cachesize, pagesize, minkeypage)
|
@ -2,10 +2,10 @@
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in uzlib so it can coexist)
|
||||
MOD = uzlib_$(ARCH)
|
||||
MOD = deflate_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = uzlib.c
|
||||
SRC = deflate.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
70
examples/natmod/deflate/deflate.c
Normal file
70
examples/natmod/deflate/deflate.c
Normal file
@ -0,0 +1,70 @@
|
||||
#define MICROPY_PY_DEFLATE (1)
|
||||
#define MICROPY_PY_DEFLATE_COMPRESS (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#if !defined(__linux__)
|
||||
void *memcpy(void *dst, const void *src, size_t n) {
|
||||
return mp_fun_table.memmove_(dst, src, n);
|
||||
}
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
return mp_fun_table.memset_(s, c, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_full_type_t deflateio_type;
|
||||
|
||||
#include "extmod/moddeflate.c"
|
||||
|
||||
// Re-implemented from py/stream.c, not yet available in dynruntime.h.
|
||||
mp_obj_t mp_stream_close(mp_obj_t stream) {
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(stream);
|
||||
int error;
|
||||
mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
if (res == MP_STREAM_ERROR) {
|
||||
mp_raise_OSError(error);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close);
|
||||
|
||||
// Re-implemented from py/stream.c, not yet available in dynruntime.h.
|
||||
STATIC mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
return mp_stream_close(args[0]);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj, 4, 4, mp_stream___exit__);
|
||||
|
||||
// Re-implemented from obj.c, not yet available in dynruntime.h.
|
||||
mp_obj_t mp_identity(mp_obj_t self) {
|
||||
return self;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
|
||||
|
||||
mp_map_elem_t deflateio_locals_dict_table[7];
|
||||
STATIC MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
deflateio_type.base.type = mp_fun_table.type_type;
|
||||
deflateio_type.name = MP_QSTR_DeflateIO;
|
||||
MP_OBJ_TYPE_SET_SLOT(&deflateio_type, make_new, &deflateio_make_new, 0);
|
||||
MP_OBJ_TYPE_SET_SLOT(&deflateio_type, protocol, &deflateio_stream_p, 1);
|
||||
deflateio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) };
|
||||
deflateio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) };
|
||||
deflateio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) };
|
||||
deflateio_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_OBJ_FROM_PTR(&mp_stream_write_obj) };
|
||||
deflateio_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&mp_stream_close_obj) };
|
||||
deflateio_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___enter__), MP_OBJ_FROM_PTR(&mp_identity_obj) };
|
||||
deflateio_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___exit__), MP_OBJ_FROM_PTR(&mp_stream___exit___obj) };
|
||||
MP_OBJ_TYPE_SET_SLOT(&deflateio_type, locals_dict, (void*)&deflateio_locals_dict, 2);
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_deflate));
|
||||
mp_store_global(MP_QSTR_DeflateIO, MP_OBJ_FROM_PTR(&deflateio_type));
|
||||
mp_store_global(MP_QSTR_RAW, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_RAW));
|
||||
mp_store_global(MP_QSTR_ZLIB, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_ZLIB));
|
||||
mp_store_global(MP_QSTR_GZIP, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_GZIP));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -88,7 +88,7 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
||||
// This must be first, it sets up the globals dict and other things
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
// Messages can be printed as usually
|
||||
// Messages can be printed as usual
|
||||
mp_printf(&mp_plat_print, "initialising module self=%p\n", self);
|
||||
|
||||
// Make the functions available in the module's namespace
|
||||
|
@ -1,5 +1,7 @@
|
||||
# This Python code will be merged with the C code in main.c
|
||||
|
||||
# ruff: noqa: F821 - this file is evaluated with C-defined names in scope
|
||||
|
||||
import array
|
||||
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in framebuf so it can coexist)
|
||||
MOD = framebuf_$(ARCH)
|
||||
# Name of module
|
||||
MOD = features3
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = framebuf.c
|
||||
SRC = features3.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
# Include to get the rules for compiling and linking the module
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
60
examples/natmod/features3/features3.c
Normal file
60
examples/natmod/features3/features3.c
Normal file
@ -0,0 +1,60 @@
|
||||
/* This example demonstrates the following features in a native module:
|
||||
- using types
|
||||
- using constant objects
|
||||
- creating dictionaries
|
||||
*/
|
||||
|
||||
// Include the header file to get access to the MicroPython API.
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// A function that returns a tuple of object types.
|
||||
STATIC mp_obj_t get_types(void) {
|
||||
return mp_obj_new_tuple(9, ((mp_obj_t []) {
|
||||
MP_OBJ_FROM_PTR(&mp_type_type),
|
||||
MP_OBJ_FROM_PTR(&mp_type_NoneType),
|
||||
MP_OBJ_FROM_PTR(&mp_type_bool),
|
||||
MP_OBJ_FROM_PTR(&mp_type_int),
|
||||
MP_OBJ_FROM_PTR(&mp_type_str),
|
||||
MP_OBJ_FROM_PTR(&mp_type_bytes),
|
||||
MP_OBJ_FROM_PTR(&mp_type_tuple),
|
||||
MP_OBJ_FROM_PTR(&mp_type_list),
|
||||
MP_OBJ_FROM_PTR(&mp_type_dict),
|
||||
}));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types);
|
||||
|
||||
// A function that returns a tuple of constant objects.
|
||||
STATIC mp_obj_t get_const_objects(void) {
|
||||
return mp_obj_new_tuple(5, ((mp_obj_t []) {
|
||||
mp_const_none,
|
||||
mp_const_false,
|
||||
mp_const_true,
|
||||
mp_const_empty_bytes,
|
||||
mp_const_empty_tuple,
|
||||
}));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects);
|
||||
|
||||
// A function that creates a dictionary from the given arguments.
|
||||
STATIC mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t dict = mp_obj_new_dict(n_args / 2);
|
||||
for (; n_args >= 2; n_args -= 2, args += 2) {
|
||||
mp_obj_dict_store(dict, args[0], args[1]);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict);
|
||||
|
||||
// This is the entry point and is called when the module is imported.
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
// This must be first, it sets up the globals dict and other things.
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
// Make the functions available in the module's namespace.
|
||||
mp_store_global(MP_QSTR_make_dict, MP_OBJ_FROM_PTR(&make_dict_obj));
|
||||
mp_store_global(MP_QSTR_get_types, MP_OBJ_FROM_PTR(&get_types_obj));
|
||||
mp_store_global(MP_QSTR_get_const_objects, MP_OBJ_FROM_PTR(&get_const_objects_obj));
|
||||
|
||||
// This must be last, it restores the globals dict.
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
14
examples/natmod/features4/Makefile
Normal file
14
examples/natmod/features4/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module
|
||||
MOD = features4
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = features4.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
# Include to get the rules for compiling and linking the module
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
73
examples/natmod/features4/features4.c
Normal file
73
examples/natmod/features4/features4.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
This example extends on features0 but demonstrates how to define a class.
|
||||
|
||||
The Factorial class constructor takes an integer, and then the calculate
|
||||
method can be called to get the factorial.
|
||||
|
||||
>>> import features4
|
||||
>>> f = features4.Factorial(4)
|
||||
>>> f.calculate()
|
||||
24
|
||||
*/
|
||||
|
||||
// Include the header file to get access to the MicroPython API
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// This is type(Factorial)
|
||||
mp_obj_full_type_t mp_type_factorial;
|
||||
|
||||
// This is the internal state of a Factorial instance.
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_int_t n;
|
||||
} mp_obj_factorial_t;
|
||||
|
||||
// Essentially Factorial.__new__ (but also kind of __init__).
|
||||
// Takes a single argument (the number to find the factorial of)
|
||||
STATIC mp_obj_t factorial_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, 1, 1, false);
|
||||
|
||||
mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type);
|
||||
o->n = mp_obj_get_int(args_in[0]);
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_int_t factorial_helper(mp_int_t x) {
|
||||
if (x == 0) {
|
||||
return 1;
|
||||
}
|
||||
return x * factorial_helper(x - 1);
|
||||
}
|
||||
|
||||
// Implements Factorial.calculate()
|
||||
STATIC mp_obj_t factorial_calculate(mp_obj_t self_in) {
|
||||
mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(factorial_helper(self->n));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate);
|
||||
|
||||
// Locals dict for the Factorial type (will have a single method, calculate,
|
||||
// added in mpy_init).
|
||||
mp_map_elem_t factorial_locals_dict_table[1];
|
||||
STATIC MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table);
|
||||
|
||||
// This is the entry point and is called when the module is imported
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
// This must be first, it sets up the globals dict and other things
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
// Initialise the type.
|
||||
mp_type_factorial.base.type = (void*)&mp_type_type;
|
||||
mp_type_factorial.flags = MP_TYPE_FLAG_NONE;
|
||||
mp_type_factorial.name = MP_QSTR_Factorial;
|
||||
MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0);
|
||||
factorial_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) };
|
||||
MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void*)&factorial_locals_dict, 1);
|
||||
|
||||
// Make the Factorial type available on the module.
|
||||
mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial));
|
||||
|
||||
// This must be last, it restores the globals dict
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#if !defined(__linux__)
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
return mp_fun_table.memset_(s, c, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_full_type_t mp_type_framebuf;
|
||||
|
||||
#include "extmod/modframebuf.c"
|
||||
|
||||
mp_map_elem_t framebuf_locals_dict_table[10];
|
||||
STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
mp_type_framebuf.base.type = (void*)&mp_type_type;
|
||||
mp_type_framebuf.flags = MP_TYPE_FLAG_EXTENDED;
|
||||
mp_type_framebuf.name = MP_QSTR_FrameBuffer;
|
||||
mp_type_framebuf.make_new = framebuf_make_new;
|
||||
mp_type_framebuf.ext[0].buffer_p.get_buffer = framebuf_get_buffer;
|
||||
framebuf_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill), MP_OBJ_FROM_PTR(&framebuf_fill_obj) };
|
||||
framebuf_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill_rect), MP_OBJ_FROM_PTR(&framebuf_fill_rect_obj) };
|
||||
framebuf_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_pixel), MP_OBJ_FROM_PTR(&framebuf_pixel_obj) };
|
||||
framebuf_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_hline), MP_OBJ_FROM_PTR(&framebuf_hline_obj) };
|
||||
framebuf_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_vline), MP_OBJ_FROM_PTR(&framebuf_vline_obj) };
|
||||
framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) };
|
||||
framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) };
|
||||
framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) };
|
||||
framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) };
|
||||
framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) };
|
||||
mp_type_framebuf.locals_dict = (void*)&framebuf_locals_dict;
|
||||
|
||||
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));
|
||||
mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB));
|
||||
mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB));
|
||||
mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8));
|
||||
mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB));
|
||||
mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in urandom so it can coexist)
|
||||
MOD = urandom_$(ARCH)
|
||||
# Name of module (different to built-in heapq so it can coexist)
|
||||
MOD = heapq_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = urandom.c
|
||||
SRC = heapq.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
16
examples/natmod/heapq/heapq.c
Normal file
16
examples/natmod/heapq/heapq.c
Normal file
@ -0,0 +1,16 @@
|
||||
#define MICROPY_PY_HEAPQ (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#include "extmod/modheapq.c"
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_heapq));
|
||||
mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_heapq_heappush_obj));
|
||||
mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_heapq_heappop_obj));
|
||||
mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_heapq_heapify_obj));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in uheapq so it can coexist)
|
||||
MOD = uheapq_$(ARCH)
|
||||
# Name of module (different to built-in random so it can coexist)
|
||||
MOD = random_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = uheapq.c
|
||||
SRC = random.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
33
examples/natmod/random/random.c
Normal file
33
examples/natmod/random/random.c
Normal file
@ -0,0 +1,33 @@
|
||||
#define MICROPY_PY_RANDOM (1)
|
||||
#define MICROPY_PY_RANDOM_EXTRA_FUNCS (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// Dynamic native modules don't support a data section so these must go in the BSS
|
||||
uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
|
||||
uint8_t yasmarang_dat;
|
||||
|
||||
#include "extmod/modrandom.c"
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
yasmarang_pad = 0xeda4baba;
|
||||
yasmarang_n = 69;
|
||||
yasmarang_d = 233;
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_random));
|
||||
mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_random_getrandbits_obj));
|
||||
mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_random_seed_obj));
|
||||
#if MICROPY_PY_RANDOM_EXTRA_FUNCS
|
||||
mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_random_randrange_obj));
|
||||
mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_random_randint_obj));
|
||||
mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_random_choice_obj));
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_random_random_obj));
|
||||
mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_random_uniform_obj));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module (different to built-in ure so it can coexist)
|
||||
MOD = ure_$(ARCH)
|
||||
# Name of module (different to built-in re so it can coexist)
|
||||
MOD = re_$(ARCH)
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = ure.c
|
||||
SRC = re.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
@ -1,8 +1,8 @@
|
||||
#define MICROPY_STACK_CHECK (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#define MICROPY_PY_URE_MATCH_GROUPS (1)
|
||||
#define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
|
||||
#define MICROPY_PY_URE_SUB (0) // requires vstr interface
|
||||
#define MICROPY_PY_RE (1)
|
||||
#define MICROPY_PY_RE_MATCH_GROUPS (1)
|
||||
#define MICROPY_PY_RE_MATCH_SPAN_START_END (1)
|
||||
#define MICROPY_PY_RE_SUB (0) // requires vstr interface
|
||||
|
||||
#include <alloca.h>
|
||||
#include "py/dynruntime.h"
|
||||
@ -32,10 +32,10 @@ void *memmove(void *dest, const void *src, size_t n) {
|
||||
return mp_fun_table.memmove_(dest, src, n);
|
||||
}
|
||||
|
||||
mp_obj_type_t match_type;
|
||||
mp_obj_type_t re_type;
|
||||
mp_obj_full_type_t match_type;
|
||||
mp_obj_full_type_t re_type;
|
||||
|
||||
#include "extmod/modure.c"
|
||||
#include "extmod/modre.c"
|
||||
|
||||
mp_map_elem_t match_locals_dict_table[5];
|
||||
STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
|
||||
@ -54,21 +54,21 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
|
||||
|
||||
match_type.base.type = (void*)&mp_fun_table.type_type;
|
||||
match_type.name = MP_QSTR_match;
|
||||
match_type.print = match_print;
|
||||
MP_OBJ_TYPE_SET_SLOT(&match_type, print, match_print, 0);
|
||||
match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) };
|
||||
match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) };
|
||||
match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) };
|
||||
match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) };
|
||||
match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) };
|
||||
match_type.locals_dict = (void*)&match_locals_dict;
|
||||
MP_OBJ_TYPE_SET_SLOT(&match_type, locals_dict, (void*)&match_locals_dict, 1);
|
||||
|
||||
re_type.base.type = (void*)&mp_fun_table.type_type;
|
||||
re_type.name = MP_QSTR_ure;
|
||||
re_type.print = re_print;
|
||||
re_type.name = MP_QSTR_re;
|
||||
MP_OBJ_TYPE_SET_SLOT(&re_type, print, re_print, 0);
|
||||
re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) };
|
||||
re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) };
|
||||
re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) };
|
||||
re_type.locals_dict = (void*)&re_locals_dict;
|
||||
MP_OBJ_TYPE_SET_SLOT(&re_type, locals_dict, (void*)&re_locals_dict, 1);
|
||||
|
||||
mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj));
|
||||
mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj));
|
@ -1,16 +0,0 @@
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#include "extmod/moduheapq.c"
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uheapq));
|
||||
mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_uheapq_heappush_obj));
|
||||
mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_uheapq_heappop_obj));
|
||||
mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_uheapq_heapify_obj));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#define MICROPY_PY_URANDOM (1)
|
||||
#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// Dynamic native modules don't support a data section so these must go in the BSS
|
||||
uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
|
||||
uint8_t yasmarang_dat;
|
||||
|
||||
#include "extmod/modurandom.c"
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
yasmarang_pad = 0xeda4baba;
|
||||
yasmarang_n = 69;
|
||||
yasmarang_d = 233;
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_urandom));
|
||||
mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_urandom_getrandbits_obj));
|
||||
mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_urandom_seed_obj));
|
||||
#if MICROPY_PY_URANDOM_EXTRA_FUNCS
|
||||
mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_urandom_randrange_obj));
|
||||
mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_urandom_randint_obj));
|
||||
mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_urandom_choice_obj));
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_urandom_random_obj));
|
||||
mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_urandom_uniform_obj));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#define MICROPY_PY_UZLIB (1)
|
||||
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#if !defined(__linux__)
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
return mp_fun_table.memset_(s, c, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_full_type_t decompio_type;
|
||||
mp_stream_p_t decompio_stream_p;
|
||||
|
||||
#include "extmod/moduzlib.c"
|
||||
|
||||
mp_map_elem_t decompio_locals_dict_table[3];
|
||||
STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
|
||||
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
decompio_stream_p.name = MP_QSTR_protocol_stream;
|
||||
decompio_stream_p.read = decompio_read;
|
||||
|
||||
decompio_type.base.type = mp_fun_table.type_type;
|
||||
decompio_type.flags = MP_TYPE_FLAG_EXTENDED;
|
||||
decompio_type.name = MP_QSTR_DecompIO;
|
||||
decompio_type.make_new = decompio_make_new;
|
||||
decompio_type.ext[0].protocol = &decompio_stream_p;
|
||||
decompio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) };
|
||||
decompio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) };
|
||||
decompio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) };
|
||||
decompio_type.locals_dict = (void*)&decompio_locals_dict;
|
||||
|
||||
mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uzlib));
|
||||
mp_store_global(MP_QSTR_decompress, MP_OBJ_FROM_PTR(&mod_uzlib_decompress_obj));
|
||||
mp_store_global(MP_QSTR_DecompIO, MP_OBJ_FROM_PTR(&decompio_type));
|
||||
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
|
||||
// Used to get the time in the Timer class example.
|
||||
#include "py/mphal.h"
|
||||
|
||||
// This is the function which will be called from Python as cexample.add_ints(a, b).
|
||||
STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
|
||||
// Extract the ints from the micropython input objects.
|
||||
@ -13,7 +16,59 @@ STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
|
||||
// Define a Python reference to the function above.
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
|
||||
|
||||
// Define all properties of the module.
|
||||
// This structure represents Timer instance objects.
|
||||
typedef struct _example_Timer_obj_t {
|
||||
// All objects start with the base.
|
||||
mp_obj_base_t base;
|
||||
// Everything below can be thought of as instance attributes, but they
|
||||
// cannot be accessed by MicroPython code directly. In this example we
|
||||
// store the time at which the object was created.
|
||||
mp_uint_t start_time;
|
||||
} example_Timer_obj_t;
|
||||
|
||||
// This is the Timer.time() method. After creating a Timer object, this
|
||||
// can be called to get the time elapsed since creating the Timer.
|
||||
STATIC mp_obj_t example_Timer_time(mp_obj_t self_in) {
|
||||
// The first argument is self. It is cast to the *example_Timer_obj_t
|
||||
// type so we can read its attributes.
|
||||
example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
// Get the elapsed time and return it as a MicroPython integer.
|
||||
mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time;
|
||||
return mp_obj_new_int_from_uint(elapsed);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_Timer_time_obj, example_Timer_time);
|
||||
|
||||
// This represents Timer.__new__ and Timer.__init__, which is called when
|
||||
// the user instantiates a Timer object.
|
||||
STATIC mp_obj_t example_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// Allocates the new object and sets the type.
|
||||
example_Timer_obj_t *self = mp_obj_malloc(example_Timer_obj_t, type);
|
||||
|
||||
// Initializes the time for this Timer instance.
|
||||
self->start_time = mp_hal_ticks_ms();
|
||||
|
||||
// The make_new function always returns self.
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
// This collects all methods and other static class attributes of the Timer.
|
||||
// The table structure is similar to the module table, as detailed below.
|
||||
STATIC const mp_rom_map_elem_t example_Timer_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&example_Timer_time_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(example_Timer_locals_dict, example_Timer_locals_dict_table);
|
||||
|
||||
// This defines the type(Timer) object.
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
example_type_Timer,
|
||||
MP_QSTR_Timer,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, example_Timer_make_new,
|
||||
locals_dict, &example_Timer_locals_dict
|
||||
);
|
||||
|
||||
// Define all attributes of the module.
|
||||
// Table entries are key/value pairs of the attribute name (a string)
|
||||
// and the MicroPython object reference.
|
||||
// All identifiers and strings are written as MP_QSTR_xxx and will be
|
||||
@ -21,6 +76,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
|
||||
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&example_type_Timer) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
|
||||
|
||||
@ -31,7 +87,4 @@ const mp_obj_module_t example_user_cmodule = {
|
||||
};
|
||||
|
||||
// Register the module to make it available in Python.
|
||||
// Note: the "1" in the third argument means this module is always enabled.
|
||||
// This "1" can be optionally replaced with a macro like MODULE_CEXAMPLE_ENABLED
|
||||
// which can then be used to conditionally enable this module.
|
||||
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, 1);
|
||||
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule);
|
||||
|
@ -1,9 +1,8 @@
|
||||
EXAMPLE_MOD_DIR := $(USERMOD_DIR)
|
||||
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
|
||||
|
||||
# Add all C files to SRC_USERMOD.
|
||||
SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
|
||||
SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c
|
||||
|
||||
# We can add our module folder to include paths if needed
|
||||
# This is not actually needed in this example.
|
||||
CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
|
||||
CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
|
||||
CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR)
|
||||
|
@ -4,7 +4,7 @@
|
||||
// See example.cpp for the definition.
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
|
||||
|
||||
// Define all properties of the module.
|
||||
// Define all attributes of the module.
|
||||
// Table entries are key/value pairs of the attribute name (a string)
|
||||
// and the MicroPython object reference.
|
||||
// All identifiers and strings are written as MP_QSTR_xxx and will be
|
||||
@ -22,7 +22,4 @@ const mp_obj_module_t cppexample_user_cmodule = {
|
||||
};
|
||||
|
||||
// Register the module to make it available in Python.
|
||||
// Note: the "1" in the third argument means this module is always enabled.
|
||||
// This "1" can be optionally replaced with a macro like MODULE_CPPEXAMPLE_ENABLED
|
||||
// which can then be used to conditionally enable this module.
|
||||
MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule, 1);
|
||||
MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule);
|
||||
|
@ -6,7 +6,7 @@ SRC_USERMOD_CXX += $(CPPEXAMPLE_MOD_DIR)/example.cpp
|
||||
|
||||
# Add our module directory to the include path.
|
||||
CFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
|
||||
CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR)
|
||||
CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR) -std=c++11
|
||||
|
||||
# We use C++ features so have to link against the standard library.
|
||||
LDFLAGS_USERMOD += -lstdc++
|
||||
|
1
examples/usercmodule/subpackage/README.md
Normal file
1
examples/usercmodule/subpackage/README.md
Normal file
@ -0,0 +1 @@
|
||||
This is an example of a user C module that includes subpackages.
|
19
examples/usercmodule/subpackage/micropython.cmake
Normal file
19
examples/usercmodule/subpackage/micropython.cmake
Normal file
@ -0,0 +1,19 @@
|
||||
# Create an INTERFACE library for our C module.
|
||||
add_library(usermod_subpackage_example INTERFACE)
|
||||
|
||||
# Add our source files to the lib
|
||||
target_sources(usermod_subpackage_example INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
|
||||
)
|
||||
|
||||
# Add the current directory as an include directory.
|
||||
target_include_directories(usermod_subpackage_example INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(usermod_subpackage_example INTERFACE
|
||||
MICROPY_MODULE_BUILTIN_SUBPACKAGES=1
|
||||
)
|
||||
|
||||
# Link our INTERFACE library to the usermod target.
|
||||
target_link_libraries(usermod INTERFACE usermod_subpackage_example)
|
10
examples/usercmodule/subpackage/micropython.mk
Normal file
10
examples/usercmodule/subpackage/micropython.mk
Normal file
@ -0,0 +1,10 @@
|
||||
SUBPACKAGE_EXAMPLE_MOD_DIR := $(USERMOD_DIR)
|
||||
|
||||
# Add all C files to SRC_USERMOD.
|
||||
SRC_USERMOD += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/modexamplepackage.c
|
||||
|
||||
# We can add our module folder to include paths if needed
|
||||
# This is not actually needed in this example.
|
||||
CFLAGS_USERMOD += -I$(SUBPACKAGE_EXAMPLE_MOD_DIR) -DMICROPY_MODULE_BUILTIN_SUBPACKAGES=1
|
||||
|
||||
QSTR_DEFS += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/qstrdefsexamplepackage.h
|
84
examples/usercmodule/subpackage/modexamplepackage.c
Normal file
84
examples/usercmodule/subpackage/modexamplepackage.c
Normal file
@ -0,0 +1,84 @@
|
||||
// Include MicroPython API.
|
||||
#include "py/runtime.h"
|
||||
|
||||
// Define example_package.foo.bar.f()
|
||||
STATIC mp_obj_t example_package_foo_bar_f(void) {
|
||||
mp_printf(&mp_plat_print, "example_package.foo.bar.f\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_bar_f_obj, example_package_foo_bar_f);
|
||||
|
||||
// Define all attributes of the second-level sub-package (example_package.foo.bar).
|
||||
STATIC const mp_rom_map_elem_t example_package_foo_bar_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo_dot_bar) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_bar_f_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(example_package_foo_bar_globals, example_package_foo_bar_globals_table);
|
||||
|
||||
// Define example_package.foo.bar module object.
|
||||
const mp_obj_module_t example_package_foo_bar_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&example_package_foo_bar_globals,
|
||||
};
|
||||
|
||||
// Define example_package.foo.f()
|
||||
STATIC mp_obj_t example_package_foo_f(void) {
|
||||
mp_printf(&mp_plat_print, "example_package.foo.f\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_f_obj, example_package_foo_f);
|
||||
|
||||
// Define all attributes of the first-level sub-package (example_package.foo).
|
||||
STATIC const mp_rom_map_elem_t example_package_foo_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&example_package_foo_bar_user_cmodule) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_f_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(example_package_foo_globals, example_package_foo_globals_table);
|
||||
|
||||
// Define example_package.foo module object.
|
||||
const mp_obj_module_t example_package_foo_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&example_package_foo_globals,
|
||||
};
|
||||
|
||||
// Define example_package.f()
|
||||
STATIC mp_obj_t example_package_f(void) {
|
||||
mp_printf(&mp_plat_print, "example_package.f\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_f_obj, example_package_f);
|
||||
|
||||
STATIC mp_obj_t example_package___init__(void) {
|
||||
if (!MP_STATE_VM(example_package_initialised)) {
|
||||
// __init__ for builtins is called each time the module is imported,
|
||||
// so ensure that initialisation only happens once.
|
||||
MP_STATE_VM(example_package_initialised) = true;
|
||||
mp_printf(&mp_plat_print, "example_package.__init__\n");
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package___init___obj, example_package___init__);
|
||||
|
||||
// The "initialised" state is stored on mp_state so that it is cleared on soft
|
||||
// reset.
|
||||
MP_REGISTER_ROOT_POINTER(int example_package_initialised);
|
||||
|
||||
// Define all attributes of the top-level package (example_package).
|
||||
STATIC const mp_rom_map_elem_t example_package_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&example_package___init___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_foo), MP_ROM_PTR(&example_package_foo_user_cmodule) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_f_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(example_package_globals, example_package_globals_table);
|
||||
|
||||
// Define module object.
|
||||
const mp_obj_module_t example_package_user_cmodule = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&example_package_globals,
|
||||
};
|
||||
|
||||
// Register the module to make it available in Python.
|
||||
// Note: subpackages should not be registered with MP_REGISTER_MODULE.
|
||||
MP_REGISTER_MODULE(MP_QSTR_example_package, example_package_user_cmodule);
|
2
examples/usercmodule/subpackage/qstrdefsexamplepackage.h
Normal file
2
examples/usercmodule/subpackage/qstrdefsexamplepackage.h
Normal file
@ -0,0 +1,2 @@
|
||||
Q(example_package.foo)
|
||||
Q(example_package.foo.bar)
|
@ -26,7 +26,11 @@
|
||||
#ifndef AXTLS_OS_PORT_H
|
||||
#define AXTLS_OS_PORT_H
|
||||
|
||||
#ifndef __ets__
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include "py/stream.h"
|
||||
#include "lib/crypto-algorithms/sha256.h"
|
||||
|
||||
|
@ -1,98 +0,0 @@
|
||||
# CMake fragment for MicroPython extmod component
|
||||
|
||||
set(MICROPY_EXTMOD_DIR "${MICROPY_DIR}/extmod")
|
||||
set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs")
|
||||
|
||||
set(MICROPY_SOURCE_EXTMOD
|
||||
${MICROPY_DIR}/shared/libc/abort_.c
|
||||
${MICROPY_DIR}/shared/libc/printf.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_bitstream.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2c.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}/modbluetooth.c
|
||||
${MICROPY_EXTMOD_DIR}/modbtree.c
|
||||
${MICROPY_EXTMOD_DIR}/modframebuf.c
|
||||
${MICROPY_EXTMOD_DIR}/modnetwork.c
|
||||
${MICROPY_EXTMOD_DIR}/modonewire.c
|
||||
${MICROPY_EXTMOD_DIR}/moduasyncio.c
|
||||
${MICROPY_EXTMOD_DIR}/modubinascii.c
|
||||
${MICROPY_EXTMOD_DIR}/moducryptolib.c
|
||||
${MICROPY_EXTMOD_DIR}/moductypes.c
|
||||
${MICROPY_EXTMOD_DIR}/moduhashlib.c
|
||||
${MICROPY_EXTMOD_DIR}/moduheapq.c
|
||||
${MICROPY_EXTMOD_DIR}/modujson.c
|
||||
${MICROPY_EXTMOD_DIR}/moduplatform.c
|
||||
${MICROPY_EXTMOD_DIR}/modurandom.c
|
||||
${MICROPY_EXTMOD_DIR}/modure.c
|
||||
${MICROPY_EXTMOD_DIR}/moduselect.c
|
||||
${MICROPY_EXTMOD_DIR}/modusocket.c
|
||||
${MICROPY_EXTMOD_DIR}/modussl_axtls.c
|
||||
${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
|
||||
${MICROPY_EXTMOD_DIR}/modutimeq.c
|
||||
${MICROPY_EXTMOD_DIR}/moduwebsocket.c
|
||||
${MICROPY_EXTMOD_DIR}/moduzlib.c
|
||||
${MICROPY_EXTMOD_DIR}/modwebrepl.c
|
||||
${MICROPY_EXTMOD_DIR}/uos_dupterm.c
|
||||
${MICROPY_EXTMOD_DIR}/utime_mphal.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_blockdev.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_fat.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_fat_diskio.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_fat_file.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_lfs.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_posix.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_posix_file.c
|
||||
${MICROPY_EXTMOD_DIR}/vfs_reader.c
|
||||
${MICROPY_EXTMOD_DIR}/virtpin.c
|
||||
${MICROPY_EXTMOD_DIR}/nimble/modbluetooth_nimble.c
|
||||
)
|
||||
|
||||
# Library for btree module and associated code
|
||||
|
||||
set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx")
|
||||
|
||||
if(EXISTS "${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c")
|
||||
add_library(micropy_extmod_btree OBJECT
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c
|
||||
${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c
|
||||
)
|
||||
|
||||
target_include_directories(micropy_extmod_btree PRIVATE
|
||||
${MICROPY_LIB_BERKELEY_DIR}/PORT/include
|
||||
)
|
||||
|
||||
target_compile_definitions(micropy_extmod_btree PRIVATE
|
||||
__DBINTERFACE_PRIVATE=1
|
||||
mpool_error=printf
|
||||
abort=abort_
|
||||
"virt_fd_t=void*"
|
||||
)
|
||||
|
||||
# The include directories and compile definitions below are needed to build
|
||||
# modbtree.c and should be added to the main MicroPython target.
|
||||
|
||||
list(APPEND MICROPY_INC_CORE
|
||||
"${MICROPY_LIB_BERKELEY_DIR}/PORT/include"
|
||||
)
|
||||
|
||||
list(APPEND MICROPY_DEF_CORE
|
||||
__DBINTERFACE_PRIVATE=1
|
||||
"virt_fd_t=void*"
|
||||
)
|
||||
endif()
|
215
extmod/extmod.mk
215
extmod/extmod.mk
@ -1,4 +1,41 @@
|
||||
# This makefile fragment provides rules to build 3rd-party components for extmod modules
|
||||
# This makefile fragment adds the source code files for the core extmod modules
|
||||
# and provides rules to build 3rd-party components for extmod modules.
|
||||
|
||||
# CIRCUITPY-CHANGE: many extmod modules removed
|
||||
SRC_EXTMOD_C += \
|
||||
extmod/modasyncio.c \
|
||||
extmod/modbinascii.c \
|
||||
extmod/modhashlib.c \
|
||||
extmod/modheapq.c \
|
||||
extmod/modjson.c \
|
||||
extmod/modos.c \
|
||||
extmod/modplatform.c\
|
||||
extmod/modrandom.c \
|
||||
extmod/modre.c \
|
||||
extmod/modselect.c \
|
||||
extmod/moductypes.c \
|
||||
extmod/modzlib.c \
|
||||
extmod/vfs.c \
|
||||
extmod/vfs_blockdev.c \
|
||||
extmod/vfs_fat.c \
|
||||
extmod/vfs_fat_diskio.c \
|
||||
extmod/vfs_fat_file.c \
|
||||
extmod/vfs_lfs.c \
|
||||
extmod/vfs_posix.c \
|
||||
extmod/vfs_posix_file.c \
|
||||
extmod/vfs_reader.c \
|
||||
extmod/virtpin.c \
|
||||
shared/libc/abort_.c \
|
||||
shared/libc/printf.c \
|
||||
|
||||
SRC_THIRDPARTY_C += \
|
||||
|
||||
PY_O += $(addprefix $(BUILD)/, $(SRC_EXTMOD_C:.c=.o))
|
||||
PY_O += $(addprefix $(BUILD)/, $(SRC_THIRDPARTY_C:.c=.o))
|
||||
SRC_QSTR += $(SRC_EXTMOD_C)
|
||||
|
||||
CFLAGS += $(CFLAGS_EXTMOD) $(CFLAGS_THIRDPARTY)
|
||||
LDFLAGS += $(LDFLAGS_EXTMOD) $(LDFLAGS_THIRDPARTY)
|
||||
|
||||
################################################################################
|
||||
# VFS FAT FS
|
||||
@ -6,11 +43,11 @@
|
||||
OOFATFS_DIR = lib/oofatfs
|
||||
|
||||
# this sets the config file for FatFs
|
||||
CFLAGS_MOD += -DFFCONF_H=\"$(OOFATFS_DIR)/ffconf.h\"
|
||||
CFLAGS_THIRDPARTY += -DFFCONF_H=\"$(OOFATFS_DIR)/ffconf.h\"
|
||||
|
||||
ifeq ($(MICROPY_VFS_FAT),1)
|
||||
CFLAGS_MOD += -DMICROPY_VFS_FAT=1
|
||||
SRC_MOD += $(addprefix $(OOFATFS_DIR)/,\
|
||||
CFLAGS_EXTMOD += -DMICROPY_VFS_FAT=1
|
||||
SRC_THIRDPARTY_C += $(addprefix $(OOFATFS_DIR)/,\
|
||||
ff.c \
|
||||
ffunicode.c \
|
||||
)
|
||||
@ -22,25 +59,21 @@ endif
|
||||
LITTLEFS_DIR = lib/littlefs
|
||||
|
||||
ifeq ($(MICROPY_VFS_LFS1),1)
|
||||
CFLAGS_MOD += -DMICROPY_VFS_LFS1=1
|
||||
CFLAGS_MOD += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT
|
||||
SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\
|
||||
CFLAGS_EXTMOD += -DMICROPY_VFS_LFS1=1
|
||||
CFLAGS_THIRDPARTY += -DLFS1_NO_MALLOC -DLFS1_NO_DEBUG -DLFS1_NO_WARN -DLFS1_NO_ERROR -DLFS1_NO_ASSERT
|
||||
SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\
|
||||
lfs1.c \
|
||||
lfs1_util.c \
|
||||
)
|
||||
else
|
||||
CFLAGS_MOD += -DMICROPY_VFS_LFS1=0
|
||||
endif
|
||||
|
||||
ifeq ($(MICROPY_VFS_LFS2),1)
|
||||
CFLAGS_MOD += -DMICROPY_VFS_LFS2=1
|
||||
CFLAGS_MOD += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT
|
||||
SRC_MOD += $(addprefix $(LITTLEFS_DIR)/,\
|
||||
CFLAGS_EXTMOD += -DMICROPY_VFS_LFS2=1
|
||||
CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT
|
||||
SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\
|
||||
lfs2.c \
|
||||
lfs2_util.c \
|
||||
)
|
||||
else
|
||||
CFLAGS_MOD += -DMICROPY_VFS_LFS2=0
|
||||
|
||||
$(BUILD)/$(LITTLEFS_DIR)/lfs2.o: CFLAGS += -Wno-missing-field-initializers
|
||||
endif
|
||||
@ -48,13 +81,14 @@ endif
|
||||
################################################################################
|
||||
# ussl
|
||||
|
||||
ifeq ($(MICROPY_PY_USSL),1)
|
||||
CFLAGS_MOD += -DMICROPY_PY_USSL=1
|
||||
ifeq ($(MICROPY_PY_SSL),1)
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_SSL=1
|
||||
ifeq ($(MICROPY_SSL_AXTLS),1)
|
||||
CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include
|
||||
AXTLS_DIR = lib/axtls
|
||||
GIT_SUBMODULES += $(AXTLS_DIR)
|
||||
CFLAGS_EXTMOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include
|
||||
$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition -Dmp_stream_errno=errno $(AXTLS_DEFS_EXTRA)
|
||||
SRC_MOD += $(addprefix $(AXTLS_DIR)/,\
|
||||
SRC_THIRDPARTY_C += $(addprefix $(AXTLS_DIR)/,\
|
||||
ssl/asn1.c \
|
||||
ssl/loader.c \
|
||||
ssl/tls1.c \
|
||||
@ -71,8 +105,12 @@ SRC_MOD += $(addprefix $(AXTLS_DIR)/,\
|
||||
)
|
||||
else ifeq ($(MICROPY_SSL_MBEDTLS),1)
|
||||
MBEDTLS_DIR = lib/mbedtls
|
||||
CFLAGS_MOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include
|
||||
SRC_MOD += $(addprefix $(MBEDTLS_DIR)/library/,\
|
||||
MBEDTLS_CONFIG_FILE ?= \"mbedtls/mbedtls_config.h\"
|
||||
GIT_SUBMODULES += $(MBEDTLS_DIR)
|
||||
CFLAGS_EXTMOD += -DMBEDTLS_CONFIG_FILE=$(MBEDTLS_CONFIG_FILE)
|
||||
CFLAGS_EXTMOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include
|
||||
SRC_THIRDPARTY_C += lib/mbedtls_errors/mp_mbedtls_errors.c
|
||||
SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\
|
||||
aes.c \
|
||||
aesni.c \
|
||||
arc4.c \
|
||||
@ -100,7 +138,6 @@ SRC_MOD += $(addprefix $(MBEDTLS_DIR)/library/,\
|
||||
ecp_curves.c \
|
||||
entropy.c \
|
||||
entropy_poll.c \
|
||||
error.c \
|
||||
gcm.c \
|
||||
havege.c \
|
||||
hmac_drbg.c \
|
||||
@ -108,7 +145,6 @@ SRC_MOD += $(addprefix $(MBEDTLS_DIR)/library/,\
|
||||
md4.c \
|
||||
md5.c \
|
||||
md.c \
|
||||
md_wrap.c \
|
||||
oid.c \
|
||||
padlock.c \
|
||||
pem.c \
|
||||
@ -133,9 +169,11 @@ SRC_MOD += $(addprefix $(MBEDTLS_DIR)/library/,\
|
||||
ssl_cli.c \
|
||||
ssl_cookie.c \
|
||||
ssl_srv.c \
|
||||
ssl_msg.c \
|
||||
ssl_ticket.c \
|
||||
ssl_tls.c \
|
||||
timing.c \
|
||||
constant_time.c \
|
||||
x509.c \
|
||||
x509_create.c \
|
||||
x509_crl.c \
|
||||
@ -152,13 +190,14 @@ endif
|
||||
# lwip
|
||||
|
||||
ifeq ($(MICROPY_PY_LWIP),1)
|
||||
GIT_SUBMODULES += lib/lwip
|
||||
# A port should add an include path where lwipopts.h can be found (eg extmod/lwip-include)
|
||||
LWIP_DIR = lib/lwip/src
|
||||
INC += -I$(TOP)/$(LWIP_DIR)/include
|
||||
CFLAGS_MOD += -DMICROPY_PY_LWIP=1
|
||||
$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS_MOD += -Wno-address
|
||||
SRC_MOD += extmod/modlwip.c shared/netutils/netutils.c
|
||||
SRC_MOD += $(addprefix $(LWIP_DIR)/,\
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_LWIP=1
|
||||
$(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address
|
||||
SRC_THIRDPARTY_C += shared/netutils/netutils.c
|
||||
SRC_THIRDPARTY_C += $(addprefix $(LWIP_DIR)/,\
|
||||
apps/mdns/mdns.c \
|
||||
core/def.c \
|
||||
core/dns.c \
|
||||
@ -197,8 +236,8 @@ SRC_MOD += $(addprefix $(LWIP_DIR)/,\
|
||||
netif/ethernet.c \
|
||||
)
|
||||
ifeq ($(MICROPY_PY_LWIP_SLIP),1)
|
||||
CFLAGS_MOD += -DMICROPY_PY_LWIP_SLIP=1
|
||||
SRC_MOD += $(LWIP_DIR)/netif/slipif.c
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_LWIP_SLIP=1
|
||||
SRC_THIRDPARTY_C += $(LWIP_DIR)/netif/slipif.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -209,8 +248,7 @@ ifeq ($(MICROPY_PY_BTREE),1)
|
||||
BTREE_DIR = lib/berkeley-db-1.xx
|
||||
BTREE_DEFS = -D__DBINTERFACE_PRIVATE=1 -Dmpool_error=printf -Dabort=abort_ "-Dvirt_fd_t=void*" $(BTREE_DEFS_EXTRA)
|
||||
INC += -I$(TOP)/$(BTREE_DIR)/PORT/include
|
||||
SRC_MOD += extmod/modbtree.c
|
||||
SRC_MOD += $(addprefix $(BTREE_DIR)/,\
|
||||
SRC_THIRDPARTY_C += $(addprefix $(BTREE_DIR)/,\
|
||||
btree/bt_close.c \
|
||||
btree/bt_conv.c \
|
||||
btree/bt_debug.c \
|
||||
@ -226,9 +264,122 @@ SRC_MOD += $(addprefix $(BTREE_DIR)/,\
|
||||
btree/bt_utils.c \
|
||||
mpool/mpool.c \
|
||||
)
|
||||
CFLAGS_MOD += -DMICROPY_PY_BTREE=1
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_BTREE=1
|
||||
# we need to suppress certain warnings to get berkeley-db to compile cleanly
|
||||
# and we have separate BTREE_DEFS so the definitions don't interfere with other source code
|
||||
$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
|
||||
$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter -Wno-deprecated-non-prototype -Wno-unknown-warning-option $(BTREE_DEFS)
|
||||
$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# networking
|
||||
|
||||
ifeq ($(MICROPY_PY_NETWORK_CYW43),1)
|
||||
CYW43_DIR = lib/cyw43-driver
|
||||
GIT_SUBMODULES += $(CYW43_DIR)
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_NETWORK_CYW43=1
|
||||
SRC_THIRDPARTY_C += $(addprefix $(CYW43_DIR)/src/,\
|
||||
cyw43_ctrl.c \
|
||||
cyw43_lwip.c \
|
||||
cyw43_ll.c \
|
||||
cyw43_sdio.c \
|
||||
cyw43_stats.c \
|
||||
)
|
||||
ifeq ($(MICROPY_PY_BLUETOOTH),1)
|
||||
DRIVERS_SRC_C += drivers/cyw43/cywbt.c
|
||||
endif
|
||||
|
||||
$(BUILD)/$(CYW43_DIR)/src/cyw43_%.o: CFLAGS += -std=c11
|
||||
endif # MICROPY_PY_NETWORK_CYW43
|
||||
|
||||
ifneq ($(MICROPY_PY_NETWORK_WIZNET5K),)
|
||||
ifneq ($(MICROPY_PY_NETWORK_WIZNET5K),0)
|
||||
WIZNET5K_DIR=lib/wiznet5k
|
||||
GIT_SUBMODULES += lib/wiznet5k
|
||||
INC += -I$(TOP)/$(WIZNET5K_DIR) -I$(TOP)/$(WIZNET5K_DIR)/Ethernet
|
||||
CFLAGS += -DMICROPY_PY_NETWORK_WIZNET5K=$(MICROPY_PY_NETWORK_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_NETWORK_WIZNET5K)
|
||||
CFLAGS_THIRDPARTY += -DWIZCHIP_PREFIXED_EXPORTS=1
|
||||
ifeq ($(MICROPY_PY_LWIP),1)
|
||||
# When using MACRAW mode (with lwIP), maximum buffer space must be used for the raw socket
|
||||
CFLAGS_THIRDPARTY += -DWIZCHIP_USE_MAX_BUFFER
|
||||
endif
|
||||
SRC_THIRDPARTY_C += $(addprefix $(WIZNET5K_DIR)/,\
|
||||
Ethernet/W$(MICROPY_PY_NETWORK_WIZNET5K)/w$(MICROPY_PY_NETWORK_WIZNET5K).c \
|
||||
Ethernet/wizchip_conf.c \
|
||||
Ethernet/socket.c \
|
||||
Internet/DNS/dns.c \
|
||||
Internet/DHCP/dhcp.c \
|
||||
)
|
||||
endif
|
||||
endif # MICROPY_PY_NETWORK_WIZNET5K
|
||||
|
||||
ifeq ($(MICROPY_PY_NETWORK_ESP_HOSTED),1)
|
||||
ESP_HOSTED_DIR = drivers/esp-hosted
|
||||
PROTOBUF_C_DIR = lib/protobuf-c
|
||||
PROTOC ?= protoc-c
|
||||
GIT_SUBMODULES += $(PROTOBUF_C_DIR)
|
||||
|
||||
CFLAGS += -DMICROPY_PY_NETWORK_ESP_HOSTED=1
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_NETWORK_ESP_HOSTED=1
|
||||
INC += -I$(TOP)/$(ESP_HOSTED_DIR)
|
||||
|
||||
ESP_HOSTED_SRC_C = $(addprefix $(ESP_HOSTED_DIR)/,\
|
||||
esp_hosted_wifi.c \
|
||||
esp_hosted_netif.c \
|
||||
esp_hosted_hal.c \
|
||||
)
|
||||
|
||||
ifeq ($(MICROPY_PY_BLUETOOTH),1)
|
||||
ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci.c
|
||||
endif
|
||||
|
||||
# Include the protobuf-c support functions
|
||||
ESP_HOSTED_SRC_C += $(addprefix $(PROTOBUF_C_DIR)/,\
|
||||
protobuf-c/protobuf-c.c \
|
||||
)
|
||||
|
||||
$(BUILD)/$(PROTOBUF_C_DIR)/%.o: CFLAGS += -Wno-unused-but-set-variable
|
||||
|
||||
# Generate esp_hosted-pb-c.c|h from esp_hosted.proto
|
||||
PROTO_GEN_SRC = $(BUILD)/extmod/esp_hosted.pb-c.c
|
||||
ESP_HOSTED_SRC_C += $(PROTO_GEN_SRC)
|
||||
|
||||
$(PROTO_GEN_SRC): $(TOP)/$(ESP_HOSTED_DIR)/esp_hosted.proto
|
||||
$(PROTOC) --proto_path=$(dir $<) --c_out=$(dir $@) $<
|
||||
|
||||
# Scope the protobuf include paths to the esp_hosted source files, only
|
||||
ESP_HOSTED_OBJS = $(addprefix $(BUILD)/, $(ESP_HOSTED_SRC_C:.c=.o))
|
||||
$(ESP_HOSTED_OBJS): $(PROTO_GEN_SRC)
|
||||
$(ESP_HOSTED_OBJS): CFLAGS += -I$(dir $(PROTO_GEN_SRC)) -I$(TOP)/$(PROTOBUF_C_DIR)
|
||||
|
||||
DRIVERS_SRC_C += $(ESP_HOSTED_SRC_C)
|
||||
|
||||
endif # MICROPY_PY_NETWORK_ESP_HOSTED
|
||||
|
||||
################################################################################
|
||||
# bluetooth
|
||||
|
||||
ifeq ($(MICROPY_PY_BLUETOOTH),1)
|
||||
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH=1
|
||||
|
||||
ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1)
|
||||
ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
|
||||
$(error Cannot enable both NimBLE and BTstack at the same time)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(MICROPY_BLUETOOTH_NIMBLE),1)
|
||||
ifneq ($(MICROPY_BLUETOOTH_BTSTACK),1)
|
||||
$(error Must enable one of MICROPY_BLUETOOTH_NIMBLE or MICROPY_BLUETOOTH_BTSTACK)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MICROPY_BLUETOOTH_NIMBLE),1)
|
||||
include $(TOP)/extmod/nimble/nimble.mk
|
||||
endif
|
||||
|
||||
ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
|
||||
include $(TOP)/extmod/btstack/btstack.mk
|
||||
endif
|
||||
|
||||
endif
|
||||
|
@ -1,8 +1,28 @@
|
||||
// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H
|
||||
#define MICROPY_INCLUDED_STM32_FONT_PETME128_8X8_H
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
|
||||
* Copyright (c) 2014-2016 Damien P. George
|
||||
* 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
|
||||
@ -23,13 +24,25 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
|
||||
#define MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MISC_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MISC_H
|
||||
|
||||
#ifdef EXTERNAL_FLASH_DEVICES
|
||||
#include "supervisor/shared/external_flash/external_flash_root_pointers.h"
|
||||
// This file contains cumulative declarations for extmod/ .
|
||||
|
||||
#include <stddef.h>
|
||||
#include "py/runtime.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_dupterm_obj);
|
||||
|
||||
#if MICROPY_PY_OS_DUPTERM
|
||||
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);
|
||||
void mp_os_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
|
||||
#else
|
||||
#include "supervisor/internal_flash_root_pointers.h"
|
||||
#define mp_os_dupterm_tx_strn(s, l)
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_SUPERVISOR_FLASH_ROOT_POINTERS_H
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_MISC_H
|
@ -29,14 +29,12 @@
|
||||
#include "py/pairheap.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#if MICROPY_PY_ASYNCIO
|
||||
|
||||
#if CIRCUITPY && !(defined(__unix__) || defined(__APPLE__))
|
||||
#include "shared-bindings/supervisor/__init__.h"
|
||||
#endif
|
||||
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
#if MICROPY_PY_UASYNCIO
|
||||
|
||||
// Used when task cannot be guaranteed to be non-NULL.
|
||||
#define TASK_PAIRHEAP(task) ((task) ? &(task)->pairheap : NULL)
|
||||
|
||||
@ -65,14 +63,15 @@ STATIC const mp_obj_type_t task_queue_type;
|
||||
STATIC const mp_obj_type_t task_type;
|
||||
|
||||
STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf);
|
||||
|
||||
/******************************************************************************/
|
||||
// Ticks for task ordering in pairing heap
|
||||
|
||||
// CIRCUITPY-CHANGE: ticks() must match adafruit_ticks()
|
||||
#define _TICKS_PERIOD (1lu << 29)
|
||||
#define _TICKS_MAX (_TICKS_PERIOD - 1)
|
||||
#define _TICKS_HALFPERIOD (_TICKS_PERIOD >> 1)
|
||||
|
||||
#if !CIRCUITPY || (defined(__unix__) || defined(__APPLE__))
|
||||
STATIC mp_obj_t ticks(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & _TICKS_MAX);
|
||||
@ -86,6 +85,7 @@ STATIC mp_obj_t ticks(void) {
|
||||
#define ticks() supervisor_ticks_ms()
|
||||
#endif
|
||||
|
||||
// CIRCUITPY-CHANGE: ticks_diff must match adafruit_ticks
|
||||
STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
|
||||
mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
|
||||
mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
|
||||
@ -105,8 +105,7 @@ STATIC int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
|
||||
STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
(void)args;
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
mp_obj_task_queue_t *self = m_new_obj(mp_obj_task_queue_t);
|
||||
self->base.type = type;
|
||||
mp_obj_task_queue_t *self = mp_obj_malloc(mp_obj_task_queue_t, type);
|
||||
self->heap = (mp_obj_task_t *)mp_pairheap_new(task_lt);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
@ -121,7 +120,7 @@ STATIC mp_obj_t task_queue_peek(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_peek_obj, task_queue_peek);
|
||||
|
||||
STATIC mp_obj_t task_queue_push_sorted(size_t n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t task_queue_push(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_obj_task_t *task = MP_OBJ_TO_PTR(args[1]);
|
||||
task->data = mp_const_none;
|
||||
@ -134,9 +133,9 @@ STATIC mp_obj_t task_queue_push_sorted(size_t n_args, const mp_obj_t *args) {
|
||||
self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, TASK_PAIRHEAP(self->heap), TASK_PAIRHEAP(task));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_sorted_obj, 2, 3, task_queue_push_sorted);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_obj, 2, 3, task_queue_push);
|
||||
|
||||
STATIC mp_obj_t task_queue_pop_head(mp_obj_t self_in) {
|
||||
STATIC mp_obj_t task_queue_pop(mp_obj_t self_in) {
|
||||
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_task_t *head = (mp_obj_task_t *)mp_pairheap_peek(task_lt, &self->heap->pairheap);
|
||||
if (head == NULL) {
|
||||
@ -145,7 +144,7 @@ STATIC mp_obj_t task_queue_pop_head(mp_obj_t self_in) {
|
||||
self->heap = (mp_obj_task_t *)mp_pairheap_pop(task_lt, &self->heap->pairheap);
|
||||
return MP_OBJ_FROM_PTR(head);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_pop_head_obj, task_queue_pop_head);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_pop_obj, task_queue_pop);
|
||||
|
||||
STATIC mp_obj_t task_queue_remove(mp_obj_t self_in, mp_obj_t task_in) {
|
||||
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
@ -157,25 +156,30 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_queue_remove_obj, task_queue_remove);
|
||||
|
||||
STATIC const mp_rom_map_elem_t task_queue_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_peek), MP_ROM_PTR(&task_queue_peek_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_push_sorted), MP_ROM_PTR(&task_queue_push_sorted_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_push_head), MP_ROM_PTR(&task_queue_push_sorted_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pop_head), MP_ROM_PTR(&task_queue_pop_head_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&task_queue_push_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&task_queue_pop_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&task_queue_remove_obj) },
|
||||
|
||||
// CIRCUITPY-CHANGE: Remove these in CircuitPython 10.0.0
|
||||
{ MP_ROM_QSTR(MP_QSTR_push_head), MP_ROM_PTR(&task_queue_push_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_push_sorted), MP_ROM_PTR(&task_queue_push_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pop_head), MP_ROM_PTR(&task_queue_pop_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(task_queue_locals_dict, task_queue_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t task_queue_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_TaskQueue,
|
||||
.make_new = task_queue_make_new,
|
||||
.locals_dict = (mp_obj_dict_t *)&task_queue_locals_dict,
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
task_queue_type,
|
||||
MP_QSTR_TaskQueue,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, task_queue_make_new,
|
||||
locals_dict, &task_queue_locals_dict
|
||||
);
|
||||
|
||||
/******************************************************************************/
|
||||
// Task class
|
||||
|
||||
// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
|
||||
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
|
||||
// This is the core asyncio context with cur_task, _task_queue and CancelledError.
|
||||
STATIC mp_obj_t asyncio_context = MP_OBJ_NULL;
|
||||
|
||||
STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 2, false);
|
||||
@ -187,7 +191,7 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
|
||||
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
|
||||
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
|
||||
if (n_args == 2) {
|
||||
uasyncio_context = args[1];
|
||||
asyncio_context = args[1];
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
@ -205,7 +209,7 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
||||
return mp_const_false;
|
||||
}
|
||||
// Can't cancel self (not supported yet).
|
||||
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
if (self_in == cur_task) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
|
||||
}
|
||||
@ -214,7 +218,7 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
||||
self = MP_OBJ_TO_PTR(self->data);
|
||||
}
|
||||
|
||||
mp_obj_t _task_queue = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
|
||||
mp_obj_t _task_queue = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
|
||||
|
||||
// Reschedule Task as a cancelled task.
|
||||
mp_obj_t dest[3];
|
||||
@ -223,26 +227,29 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
||||
// Not on the main running queue, remove the task from the queue it's on.
|
||||
dest[2] = MP_OBJ_FROM_PTR(self);
|
||||
mp_call_method_n_kw(1, 0, dest);
|
||||
// _task_queue.push_head(self)
|
||||
// _task_queue.push(self)
|
||||
dest[0] = _task_queue;
|
||||
dest[1] = MP_OBJ_FROM_PTR(self);
|
||||
task_queue_push_sorted(2, dest);
|
||||
task_queue_push(2, dest);
|
||||
} else if (ticks_diff(self->ph_key, ticks()) > 0) {
|
||||
// On the main running queue but scheduled in the future, so bring it forward to now.
|
||||
// _task_queue.remove(self)
|
||||
task_queue_remove(_task_queue, MP_OBJ_FROM_PTR(self));
|
||||
// _task_queue.push_head(self)
|
||||
// _task_queue.push(self)
|
||||
dest[0] = _task_queue;
|
||||
dest[1] = MP_OBJ_FROM_PTR(self);
|
||||
task_queue_push_sorted(2, dest);
|
||||
task_queue_push(2, dest);
|
||||
}
|
||||
|
||||
self->data = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
|
||||
self->data = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
|
||||
|
||||
return mp_const_true;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
|
||||
|
||||
// CIRCUITPY-CHANGE: CircuitPython provides __await__().
|
||||
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf);
|
||||
|
||||
STATIC mp_obj_t task_await(mp_obj_t self_in) {
|
||||
return task_getiter(self_in, NULL);
|
||||
}
|
||||
@ -291,6 +298,9 @@ STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
} else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
|
||||
// Allocate the waiting queue.
|
||||
self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
} else if (mp_obj_get_type(self->state) != &task_queue_type) {
|
||||
// Task has state used for another purpose, so can't also wait on it.
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't wait"));
|
||||
}
|
||||
return self_in;
|
||||
}
|
||||
@ -307,46 +317,44 @@ STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
|
||||
}
|
||||
} else {
|
||||
// Put calling task on waiting queue.
|
||||
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t args[2] = { self->state, cur_task };
|
||||
task_queue_push_sorted(2, args);
|
||||
task_queue_push(2, args);
|
||||
// Set calling task's data to this task that it waits on, to double-link it.
|
||||
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_obj_type_t task_type = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_Task,
|
||||
.make_new = task_make_new,
|
||||
.attr = task_attr,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
STATIC const mp_getiter_iternext_custom_t task_getiter_iternext = {
|
||||
.getiter = task_getiter,
|
||||
.iternext = task_iternext,
|
||||
),
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// C-level uasyncio module
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
task_type,
|
||||
MP_QSTR_Task,
|
||||
MP_TYPE_FLAG_ITER_IS_CUSTOM,
|
||||
make_new, task_make_new,
|
||||
attr, task_attr,
|
||||
iter, &task_getiter_iternext
|
||||
);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_uasyncio_globals_table[] = {
|
||||
#if CIRCUITPY
|
||||
/******************************************************************************/
|
||||
// C-level asyncio module
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_asyncio_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__asyncio) },
|
||||
#else
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__uasyncio) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_TaskQueue), MP_ROM_PTR(&task_queue_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Task), MP_ROM_PTR(&task_type) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uasyncio_globals, mp_module_uasyncio_globals_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_asyncio_globals, mp_module_asyncio_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uasyncio = {
|
||||
const mp_obj_module_t mp_module_asyncio = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_uasyncio_globals,
|
||||
.globals = (mp_obj_dict_t *)&mp_module_asyncio_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR__asyncio, mp_module_uasyncio, MICROPY_PY_UASYNCIO);
|
||||
MP_REGISTER_MODULE(MP_QSTR__asyncio, mp_module_asyncio);
|
||||
|
||||
#endif // MICROPY_PY_UASYNCIO
|
||||
#endif // MICROPY_PY_ASYNCIO
|
222
extmod/modbinascii.c
Normal file
222
extmod/modbinascii.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/objstr.h"
|
||||
|
||||
#if MICROPY_PY_BINASCII
|
||||
|
||||
static void check_not_unicode(const mp_obj_t arg) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (mp_obj_is_str(arg)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("a bytes-like object is required"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_BYTES_HEX
|
||||
STATIC mp_obj_t bytes_hex_as_bytes(size_t n_args, const mp_obj_t *args) {
|
||||
return mp_obj_bytes_hex(n_args, args, &mp_type_bytes);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_hex_as_bytes_obj, 1, 2, bytes_hex_as_bytes);
|
||||
|
||||
STATIC mp_obj_t bytes_fromhex_bytes(mp_obj_t data) {
|
||||
return mp_obj_bytes_fromhex(MP_OBJ_FROM_PTR(&mp_type_bytes), data);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bytes_fromhex_obj, bytes_fromhex_bytes);
|
||||
#endif
|
||||
|
||||
// If ch is a character in the base64 alphabet, and is not a pad character, then
|
||||
// the corresponding integer between 0 and 63, inclusively, is returned.
|
||||
// Otherwise, -1 is returned.
|
||||
static int mod_binascii_sextet(byte ch) {
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
return ch - 'A';
|
||||
} else if (ch >= 'a' && ch <= 'z') {
|
||||
return ch - 'a' + 26;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
return ch - '0' + 52;
|
||||
} else if (ch == '+') {
|
||||
return 62;
|
||||
} else if (ch == '/') {
|
||||
return 63;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
byte *in = bufinfo.buf;
|
||||
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, (bufinfo.len * 3) / 4 + 1); // Potentially over-allocate
|
||||
byte *out = (byte *)vstr.buf;
|
||||
|
||||
uint shift = 0;
|
||||
int nbits = 0; // Number of meaningful bits in shift
|
||||
bool hadpad = false; // Had a pad character since last valid character
|
||||
for (size_t i = 0; i < bufinfo.len; i++) {
|
||||
if (in[i] == '=') {
|
||||
if ((nbits == 2) || ((nbits == 4) && hadpad)) {
|
||||
nbits = 0;
|
||||
break;
|
||||
}
|
||||
hadpad = true;
|
||||
}
|
||||
|
||||
int sextet = mod_binascii_sextet(in[i]);
|
||||
if (sextet == -1) {
|
||||
continue;
|
||||
}
|
||||
hadpad = false;
|
||||
shift = (shift << 6) | sextet;
|
||||
nbits += 6;
|
||||
|
||||
if (nbits >= 8) {
|
||||
nbits -= 8;
|
||||
out[vstr.len++] = (shift >> nbits) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbits) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
|
||||
}
|
||||
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
|
||||
|
||||
STATIC mp_obj_t mod_binascii_b2a_base64(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_newline };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_newline, MP_ARG_BOOL, {.u_bool = true} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
uint8_t newline = args[ARG_newline].u_bool;
|
||||
// CIRCUITPY-CHANGE
|
||||
check_not_unicode(pos_args[0]);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(pos_args[0], &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + newline);
|
||||
|
||||
// First pass, we convert input buffer to numeric base 64 values
|
||||
byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
|
||||
mp_uint_t i;
|
||||
for (i = bufinfo.len; i >= 3; i -= 3) {
|
||||
*out++ = (in[0] & 0xFC) >> 2;
|
||||
*out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
|
||||
*out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6;
|
||||
*out++ = in[2] & 0x3F;
|
||||
in += 3;
|
||||
}
|
||||
if (i != 0) {
|
||||
*out++ = (in[0] & 0xFC) >> 2;
|
||||
if (i == 2) {
|
||||
*out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
|
||||
*out++ = (in[1] & 0x0F) << 2;
|
||||
} else {
|
||||
*out++ = (in[0] & 0x03) << 4;
|
||||
*out++ = 64;
|
||||
}
|
||||
*out = 64;
|
||||
}
|
||||
|
||||
// Second pass, we convert number base 64 values to actual base64 ascii encoding
|
||||
out = (byte *)vstr.buf;
|
||||
for (mp_uint_t j = vstr.len - newline; j--;) {
|
||||
if (*out < 26) {
|
||||
*out += 'A';
|
||||
} else if (*out < 52) {
|
||||
*out += 'a' - 26;
|
||||
} else if (*out < 62) {
|
||||
*out += '0' - 52;
|
||||
} else if (*out == 62) {
|
||||
*out = '+';
|
||||
} else if (*out == 63) {
|
||||
*out = '/';
|
||||
} else {
|
||||
*out = '=';
|
||||
}
|
||||
out++;
|
||||
}
|
||||
if (newline) {
|
||||
*out = '\n';
|
||||
}
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_binascii_b2a_base64_obj, 1, mod_binascii_b2a_base64);
|
||||
|
||||
// CIRCUITPY-CHANGE: no deflate
|
||||
#if MICROPY_PY_BINASCII_CRC32
|
||||
#include "lib/uzlib/uzlib.h"
|
||||
|
||||
STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
// CIRCUITPY-CHANGE
|
||||
check_not_unicode(args[0]);
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
||||
uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;
|
||||
crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
|
||||
return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
|
||||
#if MICROPY_PY_BUILTINS_BYTES_HEX
|
||||
{ MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&bytes_hex_as_bytes_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&bytes_fromhex_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },
|
||||
// CIRCUITPY-CHANGE: no deflate
|
||||
#if MICROPY_PY_BINASCII_CRC32
|
||||
{ MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_binascii = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_binascii, mp_module_binascii);
|
||||
|
||||
#endif // MICROPY_PY_BINASCII
|
@ -1,367 +0,0 @@
|
||||
// Copyright (c) 2016 Paul Sokolovsky
|
||||
// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h> // for declaration of global errno variable
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
|
||||
#if MICROPY_PY_BTREE
|
||||
|
||||
#include <db.h>
|
||||
#include <../../btree/btree.h>
|
||||
|
||||
typedef struct _mp_obj_btree_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t stream; // retain a reference to prevent GC from reclaiming it
|
||||
DB *db;
|
||||
mp_obj_t start_key;
|
||||
mp_obj_t end_key;
|
||||
#define FLAG_END_KEY_INCL 1
|
||||
#define FLAG_DESC 2
|
||||
#define FLAG_ITER_TYPE_MASK 0xc0
|
||||
#define FLAG_ITER_KEYS 0x40
|
||||
#define FLAG_ITER_VALUES 0x80
|
||||
#define FLAG_ITER_ITEMS 0xc0
|
||||
byte flags;
|
||||
byte next_flags;
|
||||
} mp_obj_btree_t;
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_obj_type_t btree_type;
|
||||
#endif
|
||||
|
||||
#define CHECK_ERROR(res) \
|
||||
if (res == RET_ERROR) { \
|
||||
mp_raise_OSError(errno); \
|
||||
}
|
||||
|
||||
void __dbpanic(DB *db) {
|
||||
mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
|
||||
}
|
||||
|
||||
STATIC mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) {
|
||||
mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);
|
||||
o->base.type = (mp_obj_type_t *)&btree_type;
|
||||
o->stream = stream;
|
||||
o->db = db;
|
||||
o->start_key = mp_const_none;
|
||||
o->end_key = mp_const_none;
|
||||
o->next_flags = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<btree %p>", self->db);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_flush(mp_obj_t self_in) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(__bt_sync(self->db, 0));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_flush_obj, btree_flush);
|
||||
|
||||
STATIC mp_obj_t btree_close(mp_obj_t self_in) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_close_obj, btree_close);
|
||||
|
||||
STATIC mp_obj_t btree_put(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
DBT key, val;
|
||||
key.data = (void *)mp_obj_str_get_data(args[1], &key.size);
|
||||
val.data = (void *)mp_obj_str_get_data(args[2], &val.size);
|
||||
return MP_OBJ_NEW_SMALL_INT(__bt_put(self->db, &key, &val, 0));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_put_obj, 3, 4, btree_put);
|
||||
|
||||
STATIC mp_obj_t btree_get(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
DBT key, val;
|
||||
key.data = (void *)mp_obj_str_get_data(args[1], &key.size);
|
||||
int res = __bt_get(self->db, &key, &val, 0);
|
||||
if (res == RET_SPECIAL) {
|
||||
if (n_args > 2) {
|
||||
return args[2];
|
||||
} else {
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
return mp_obj_new_bytes(val.data, val.size);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_get_obj, 2, 3, btree_get);
|
||||
|
||||
STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
int flags = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||
DBT key, val;
|
||||
if (n_args > 2) {
|
||||
key.data = (void *)mp_obj_str_get_data(args[2], &key.size);
|
||||
}
|
||||
|
||||
int res = __bt_seq(self->db, &key, &val, flags);
|
||||
CHECK_ERROR(res);
|
||||
if (res == RET_SPECIAL) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t pair_o = mp_obj_new_tuple(2, NULL);
|
||||
mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o);
|
||||
pair->items[0] = mp_obj_new_bytes(key.data, key.size);
|
||||
pair->items[1] = mp_obj_new_bytes(val.data, val.size);
|
||||
return pair_o;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_seq_obj, 2, 4, btree_seq);
|
||||
|
||||
STATIC mp_obj_t btree_init_iter(size_t n_args, const mp_obj_t *args, byte type) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
self->next_flags = type;
|
||||
self->start_key = mp_const_none;
|
||||
self->end_key = mp_const_none;
|
||||
if (n_args > 1) {
|
||||
self->start_key = args[1];
|
||||
if (n_args > 2) {
|
||||
self->end_key = args[2];
|
||||
if (n_args > 3) {
|
||||
self->next_flags = type | MP_OBJ_SMALL_INT_VALUE(args[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return args[0];
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_keys(size_t n_args, const mp_obj_t *args) {
|
||||
return btree_init_iter(n_args, args, FLAG_ITER_KEYS);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_keys_obj, 1, 4, btree_keys);
|
||||
|
||||
STATIC mp_obj_t btree_values(size_t n_args, const mp_obj_t *args) {
|
||||
return btree_init_iter(n_args, args, FLAG_ITER_VALUES);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_values_obj, 1, 4, btree_values);
|
||||
|
||||
STATIC mp_obj_t btree_items(size_t n_args, const mp_obj_t *args) {
|
||||
return btree_init_iter(n_args, args, FLAG_ITER_ITEMS);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_items_obj, 1, 4, btree_items);
|
||||
|
||||
STATIC mp_obj_t btree_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
(void)iter_buf;
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->next_flags != 0) {
|
||||
// If we're called immediately after keys(), values(), or items(),
|
||||
// use their setup for iteration.
|
||||
self->flags = self->next_flags;
|
||||
self->next_flags = 0;
|
||||
} else {
|
||||
// Otherwise, iterate over all keys.
|
||||
self->flags = FLAG_ITER_KEYS;
|
||||
self->start_key = mp_const_none;
|
||||
self->end_key = mp_const_none;
|
||||
}
|
||||
|
||||
return self_in;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_iternext(mp_obj_t self_in) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
DBT key, val;
|
||||
int res;
|
||||
bool desc = self->flags & FLAG_DESC;
|
||||
if (self->start_key != MP_OBJ_NULL) {
|
||||
int flags = R_FIRST;
|
||||
if (self->start_key != mp_const_none) {
|
||||
key.data = (void *)mp_obj_str_get_data(self->start_key, &key.size);
|
||||
flags = R_CURSOR;
|
||||
} else if (desc) {
|
||||
flags = R_LAST;
|
||||
}
|
||||
res = __bt_seq(self->db, &key, &val, flags);
|
||||
self->start_key = MP_OBJ_NULL;
|
||||
} else {
|
||||
res = __bt_seq(self->db, &key, &val, desc ? R_PREV : R_NEXT);
|
||||
}
|
||||
|
||||
if (res == RET_SPECIAL) {
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
|
||||
if (self->end_key != mp_const_none) {
|
||||
DBT end_key;
|
||||
end_key.data = (void *)mp_obj_str_get_data(self->end_key, &end_key.size);
|
||||
BTREE *t = self->db->internal;
|
||||
int cmp = t->bt_cmp(&key, &end_key);
|
||||
if (desc) {
|
||||
cmp = -cmp;
|
||||
}
|
||||
if (self->flags & FLAG_END_KEY_INCL) {
|
||||
cmp--;
|
||||
}
|
||||
if (cmp >= 0) {
|
||||
self->end_key = MP_OBJ_NULL;
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
}
|
||||
|
||||
switch (self->flags & FLAG_ITER_TYPE_MASK) {
|
||||
case FLAG_ITER_KEYS:
|
||||
return mp_obj_new_bytes(key.data, key.size);
|
||||
case FLAG_ITER_VALUES:
|
||||
return mp_obj_new_bytes(val.data, val.size);
|
||||
default: {
|
||||
mp_obj_t pair_o = mp_obj_new_tuple(2, NULL);
|
||||
mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(pair_o);
|
||||
pair->items[0] = mp_obj_new_bytes(key.data, key.size);
|
||||
pair->items[1] = mp_obj_new_bytes(val.data, val.size);
|
||||
return pair_o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
mp_obj_btree_t *self = mp_obj_cast_to_native_base(self_in, &btree_type);
|
||||
if (value == MP_OBJ_NULL) {
|
||||
// delete
|
||||
DBT key;
|
||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||
int res = __bt_delete(self->db, &key, 0);
|
||||
if (res == RET_SPECIAL) {
|
||||
mp_raise_type(&mp_type_KeyError);
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
return mp_const_none;
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
// load
|
||||
DBT key, val;
|
||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||
int res = __bt_get(self->db, &key, &val, 0);
|
||||
if (res == RET_SPECIAL) {
|
||||
mp_raise_type(&mp_type_KeyError);
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
return mp_obj_new_bytes(val.data, val.size);
|
||||
} else {
|
||||
// store
|
||||
DBT key, val;
|
||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||
val.data = (void *)mp_obj_str_get_data(value, &val.size);
|
||||
int res = __bt_put(self->db, &key, &val, 0);
|
||||
CHECK_ERROR(res);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in);
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_CONTAINS: {
|
||||
DBT key, val;
|
||||
key.data = (void *)mp_obj_str_get_data(rhs_in, &key.size);
|
||||
int res = __bt_get(self->db, &key, &val, 0);
|
||||
CHECK_ERROR(res);
|
||||
return mp_obj_new_bool(res != RET_SPECIAL);
|
||||
}
|
||||
default:
|
||||
// op not supported
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&btree_get_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&btree_put_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_seq), MP_ROM_PTR(&btree_seq_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_keys), MP_ROM_PTR(&btree_keys_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_values), MP_ROM_PTR(&btree_values_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_items), MP_ROM_PTR(&btree_items_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t btree_type = {
|
||||
{ &mp_type_type },
|
||||
// Save on qstr's, reuse same as for module
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_btree,
|
||||
.print = btree_print,
|
||||
.locals_dict = (void *)&btree_locals_dict,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.getiter = btree_getiter,
|
||||
.iternext = btree_iternext,
|
||||
.binary_op = btree_binary_op,
|
||||
.subscr = btree_subscr,
|
||||
),
|
||||
};
|
||||
#endif
|
||||
|
||||
STATIC const FILEVTABLE btree_stream_fvtable = {
|
||||
mp_stream_posix_read,
|
||||
mp_stream_posix_write,
|
||||
mp_stream_posix_lseek,
|
||||
mp_stream_posix_fsync
|
||||
};
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_cachesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_pagesize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_minkeypage, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
|
||||
// Make sure we got a stream object
|
||||
mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
|
||||
|
||||
struct {
|
||||
mp_arg_val_t flags;
|
||||
mp_arg_val_t cachesize;
|
||||
mp_arg_val_t pagesize;
|
||||
mp_arg_val_t minkeypage;
|
||||
} args;
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
|
||||
BTREEINFO openinfo = {0};
|
||||
openinfo.flags = args.flags.u_int;
|
||||
openinfo.cachesize = args.cachesize.u_int;
|
||||
openinfo.psize = args.pagesize.u_int;
|
||||
openinfo.minkeypage = args.minkeypage.u_int;
|
||||
|
||||
DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, /*dflags*/ 0);
|
||||
if (db == NULL) {
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0]));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_btree_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_btree) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mod_btree_open_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INCL), MP_ROM_INT(FLAG_END_KEY_INCL) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DESC), MP_ROM_INT(FLAG_DESC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_btree = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_btree_globals,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_BTREE
|
415
extmod/moddeflate.c
Normal file
415
extmod/moddeflate.c
Normal file
@ -0,0 +1,415 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Jim Mussared
|
||||
*
|
||||
* Based on extmod/modzlib.c
|
||||
* Copyright (c) 2014-2016 Paul Sokolovsky
|
||||
* Copyright (c) 2021-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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mperrno.h"
|
||||
|
||||
#if MICROPY_PY_DEFLATE
|
||||
|
||||
#include "lib/uzlib/uzlib.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
DEFLATEIO_FORMAT_MIN = 0,
|
||||
DEFLATEIO_FORMAT_AUTO = DEFLATEIO_FORMAT_MIN, // Read mode this means auto-detect zlib/gzip, write mode this means RAW.
|
||||
DEFLATEIO_FORMAT_RAW = 1,
|
||||
DEFLATEIO_FORMAT_ZLIB = 2,
|
||||
DEFLATEIO_FORMAT_GZIP = 3,
|
||||
DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP,
|
||||
} deflateio_format_t;
|
||||
|
||||
// This is used when the wbits is unset in the DeflateIO constructor. Default
|
||||
// to the smallest window size (faster compression, less RAM usage, etc).
|
||||
const int DEFLATEIO_DEFAULT_WBITS = 8;
|
||||
|
||||
typedef struct {
|
||||
void *window;
|
||||
uzlib_uncomp_t decomp;
|
||||
bool eof;
|
||||
} mp_obj_deflateio_read_t;
|
||||
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
typedef struct {
|
||||
void *window;
|
||||
size_t input_len;
|
||||
uint32_t input_checksum;
|
||||
uzlib_lz77_state_t lz77;
|
||||
} mp_obj_deflateio_write_t;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t stream;
|
||||
uint8_t format : 2;
|
||||
uint8_t window_bits : 4;
|
||||
bool close : 1;
|
||||
mp_obj_deflateio_read_t *read;
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
mp_obj_deflateio_write_t *write;
|
||||
#endif
|
||||
} mp_obj_deflateio_t;
|
||||
|
||||
STATIC int deflateio_read_stream(void *data) {
|
||||
mp_obj_deflateio_t *self = data;
|
||||
const mp_stream_p_t *stream = mp_get_stream(self->stream);
|
||||
int err;
|
||||
byte c;
|
||||
mp_uint_t out_sz = stream->read(self->stream, &c, 1, &err);
|
||||
if (out_sz == MP_STREAM_ERROR) {
|
||||
mp_raise_OSError(err);
|
||||
}
|
||||
if (out_sz == 0) {
|
||||
mp_raise_type(&mp_type_EOFError);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
STATIC bool deflateio_init_read(mp_obj_deflateio_t *self) {
|
||||
if (self->read) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mp_get_stream_raise(self->stream, MP_STREAM_OP_READ);
|
||||
|
||||
self->read = m_new_obj(mp_obj_deflateio_read_t);
|
||||
memset(&self->read->decomp, 0, sizeof(self->read->decomp));
|
||||
self->read->decomp.source_read_data = self;
|
||||
self->read->decomp.source_read_cb = deflateio_read_stream;
|
||||
self->read->eof = false;
|
||||
|
||||
// Don't modify self->window_bits as it may also be used for write.
|
||||
int wbits = self->window_bits;
|
||||
|
||||
if (self->format == DEFLATEIO_FORMAT_RAW) {
|
||||
if (wbits == 0) {
|
||||
// The docs recommends always setting wbits explicitly when using
|
||||
// RAW, but we still allow a default.
|
||||
wbits = DEFLATEIO_DEFAULT_WBITS;
|
||||
}
|
||||
} else {
|
||||
// Parse the header if we're in NONE/ZLIB/GZIP modes.
|
||||
int header_wbits;
|
||||
int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits);
|
||||
if (header_type < 0) {
|
||||
// Stream header was invalid.
|
||||
return false;
|
||||
}
|
||||
if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) {
|
||||
// Not what we expected.
|
||||
return false;
|
||||
}
|
||||
// header_wbits will either be 15 (gzip) or 8-15 (zlib).
|
||||
if (wbits == 0 || header_wbits < wbits) {
|
||||
// If the header specified something lower, then use that instead.
|
||||
// No point doing a bigger allocation than we need to.
|
||||
wbits = header_wbits;
|
||||
}
|
||||
}
|
||||
|
||||
size_t window_len = 1 << wbits;
|
||||
self->read->window = m_new(uint8_t, window_len);
|
||||
|
||||
uzlib_uncompress_init(&self->read->decomp, self->read->window, window_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
STATIC void deflateio_out_byte(void *data, uint8_t b) {
|
||||
mp_obj_deflateio_t *self = data;
|
||||
const mp_stream_p_t *stream = mp_get_stream(self->stream);
|
||||
int err;
|
||||
mp_uint_t ret = stream->write(self->stream, &b, 1, &err);
|
||||
if (ret == MP_STREAM_ERROR) {
|
||||
mp_raise_OSError(err);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool deflateio_init_write(mp_obj_deflateio_t *self) {
|
||||
if (self->write) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const mp_stream_p_t *stream = mp_get_stream_raise(self->stream, MP_STREAM_OP_WRITE);
|
||||
|
||||
self->write = m_new_obj(mp_obj_deflateio_write_t);
|
||||
self->write->input_len = 0;
|
||||
|
||||
int wbits = self->window_bits;
|
||||
if (wbits == 0) {
|
||||
// Same default wbits for all formats.
|
||||
wbits = DEFLATEIO_DEFAULT_WBITS;
|
||||
}
|
||||
size_t window_len = 1 << wbits;
|
||||
self->write->window = m_new(uint8_t, window_len);
|
||||
|
||||
uzlib_lz77_init(&self->write->lz77, self->write->window, window_len);
|
||||
self->write->lz77.dest_write_data = self;
|
||||
self->write->lz77.dest_write_cb = deflateio_out_byte;
|
||||
|
||||
// Write header if needed.
|
||||
mp_uint_t ret = 0;
|
||||
int err;
|
||||
if (self->format == DEFLATEIO_FORMAT_ZLIB) {
|
||||
// -----CMF------ ----------FLG---------------
|
||||
// CINFO(5) CM(3) FLEVEL(2) FDICT(1) FCHECK(5)
|
||||
uint8_t buf[] = { 0x08, 0x80 }; // CM=2 (deflate), FLEVEL=2 (default), FDICT=0 (no dictionary)
|
||||
buf[0] |= MAX(wbits - 8, 1) << 4; // base-2 logarithm of the LZ77 window size, minus eight.
|
||||
buf[1] |= 31 - ((buf[0] * 256 + buf[1]) % 31); // (CMF*256 + FLG) % 31 == 0.
|
||||
ret = stream->write(self->stream, buf, sizeof(buf), &err);
|
||||
|
||||
self->write->input_checksum = 1; // ADLER32
|
||||
} else if (self->format == DEFLATEIO_FORMAT_GZIP) {
|
||||
// ID1(8) ID2(8) CM(8) ---FLG--- MTIME(32) XFL(8) OS(8)
|
||||
// FLG: x x x FCOMMENT FNAME FEXTRA FHCRC FTEXT
|
||||
uint8_t buf[] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03 }; // MTIME=0, XFL=4 (fastest), OS=3 (unix)
|
||||
ret = stream->write(self->stream, buf, sizeof(buf), &err);
|
||||
|
||||
self->write->input_checksum = ~0; // CRC32
|
||||
}
|
||||
if (ret == MP_STREAM_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write starting block.
|
||||
uzlib_start_block(&self->write->lz77);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t deflateio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
// args: stream, format=NONE, wbits=0, close=False
|
||||
mp_arg_check_num(n_args, n_kw, 1, 4, false);
|
||||
|
||||
mp_int_t format = n_args > 1 ? mp_obj_get_int(args_in[1]) : DEFLATEIO_FORMAT_AUTO;
|
||||
mp_int_t wbits = n_args > 2 ? mp_obj_get_int(args_in[2]) : 0;
|
||||
|
||||
if (format < DEFLATEIO_FORMAT_MIN || format > DEFLATEIO_FORMAT_MAX) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("format"));
|
||||
}
|
||||
if (wbits != 0 && (wbits < 5 || wbits > 15)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wbits"));
|
||||
}
|
||||
|
||||
mp_obj_deflateio_t *self = mp_obj_malloc(mp_obj_deflateio_t, type);
|
||||
self->stream = args_in[0];
|
||||
self->format = format;
|
||||
self->window_bits = wbits;
|
||||
self->read = NULL;
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
self->write = NULL;
|
||||
#endif
|
||||
self->close = n_args > 3 ? mp_obj_is_true(args_in[3]) : false;
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_uint_t deflateio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(o_in);
|
||||
|
||||
if (self->stream == MP_OBJ_NULL || !deflateio_init_read(self)) {
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
if (self->read->eof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->read->decomp.dest = buf;
|
||||
self->read->decomp.dest_limit = (uint8_t *)buf + size;
|
||||
int st = uzlib_uncompress_chksum(&self->read->decomp);
|
||||
if (st == UZLIB_DONE) {
|
||||
self->read->eof = true;
|
||||
}
|
||||
if (st < 0) {
|
||||
DEBUG_printf("uncompress error=" INT_FMT "\n", st);
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
return self->read->decomp.dest - (uint8_t *)buf;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
STATIC mp_uint_t deflateio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->stream == MP_OBJ_NULL || !deflateio_init_write(self)) {
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
self->write->input_len += size;
|
||||
if (self->format == DEFLATEIO_FORMAT_ZLIB) {
|
||||
self->write->input_checksum = uzlib_adler32(buf, size, self->write->input_checksum);
|
||||
} else if (self->format == DEFLATEIO_FORMAT_GZIP) {
|
||||
self->write->input_checksum = uzlib_crc32(buf, size, self->write->input_checksum);
|
||||
}
|
||||
|
||||
uzlib_lz77_compress(&self->write->lz77, buf, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline void put_le32(char *buf, uint32_t value) {
|
||||
buf[0] = value & 0xff;
|
||||
buf[1] = value >> 8 & 0xff;
|
||||
buf[2] = value >> 16 & 0xff;
|
||||
buf[3] = value >> 24 & 0xff;
|
||||
}
|
||||
|
||||
static inline void put_be32(char *buf, uint32_t value) {
|
||||
buf[3] = value & 0xff;
|
||||
buf[2] = value >> 8 & 0xff;
|
||||
buf[1] = value >> 16 & 0xff;
|
||||
buf[0] = value >> 24 & 0xff;
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC mp_uint_t deflateio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
if (request == MP_STREAM_CLOSE) {
|
||||
mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
mp_uint_t ret = 0;
|
||||
|
||||
if (self->stream != MP_OBJ_NULL) {
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
if (self->write) {
|
||||
uzlib_finish_block(&self->write->lz77);
|
||||
|
||||
const mp_stream_p_t *stream = mp_get_stream(self->stream);
|
||||
|
||||
// Write footer if needed.
|
||||
if (self->format == DEFLATEIO_FORMAT_ZLIB || self->format == DEFLATEIO_FORMAT_GZIP) {
|
||||
char footer[8];
|
||||
size_t footer_len;
|
||||
if (self->format == DEFLATEIO_FORMAT_ZLIB) {
|
||||
put_be32(&footer[0], self->write->input_checksum);
|
||||
footer_len = 4;
|
||||
} else { // DEFLATEIO_FORMAT_GZIP
|
||||
put_le32(&footer[0], ~self->write->input_checksum);
|
||||
put_le32(&footer[4], self->write->input_len);
|
||||
footer_len = 8;
|
||||
}
|
||||
if (stream->write(self->stream, footer, footer_len, errcode) == MP_STREAM_ERROR) {
|
||||
ret = MP_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Only close the stream if required. e.g. when using io.BytesIO
|
||||
// it needs to stay open so that getvalue() can be called.
|
||||
if (self->close) {
|
||||
mp_stream_close(self->stream);
|
||||
}
|
||||
|
||||
// Either way, free the reference to the stream.
|
||||
self->stream = MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
*errcode = MP_EINVAL;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_stream_p_t deflateio_stream_p = {
|
||||
.read = deflateio_read,
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
.write = deflateio_write,
|
||||
#endif
|
||||
.ioctl = deflateio_ioctl,
|
||||
};
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t deflateio_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
|
||||
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
deflateio_type,
|
||||
MP_QSTR_DeflateIO,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, deflateio_make_new,
|
||||
protocol, &deflateio_stream_p,
|
||||
locals_dict, &deflateio_locals_dict
|
||||
);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_deflate_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_deflate) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DeflateIO), MP_ROM_PTR(&deflateio_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTO), MP_ROM_INT(DEFLATEIO_FORMAT_AUTO) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RAW), MP_ROM_INT(DEFLATEIO_FORMAT_RAW) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ZLIB), MP_ROM_INT(DEFLATEIO_FORMAT_ZLIB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GZIP), MP_ROM_INT(DEFLATEIO_FORMAT_GZIP) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_deflate_globals, mp_module_deflate_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_deflate = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_deflate_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_deflate, mp_module_deflate);
|
||||
#endif // !MICROPY_ENABLE_DYNRUNTIME
|
||||
|
||||
// Source files #include'd here to make sure they're compiled in
|
||||
// only if the module is enabled.
|
||||
|
||||
#include "lib/uzlib/tinflate.c"
|
||||
#include "lib/uzlib/header.c"
|
||||
#include "lib/uzlib/adler32.c"
|
||||
#include "lib/uzlib/crc32.c"
|
||||
|
||||
#if MICROPY_PY_DEFLATE_COMPRESS
|
||||
#include "lib/uzlib/lz77.c"
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_DEFLATE
|
@ -1,667 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/objtype.h"
|
||||
#include "py/proto.h"
|
||||
|
||||
#if MICROPY_PY_FRAMEBUF
|
||||
|
||||
#include "font_petme128_8x8.h"
|
||||
|
||||
typedef struct _mp_obj_framebuf_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t buf_obj; // need to store this to prevent GC from reclaiming buf
|
||||
void *buf;
|
||||
uint16_t width, height, stride;
|
||||
uint8_t format;
|
||||
} mp_obj_framebuf_t;
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_obj_type_t mp_type_framebuf;
|
||||
#endif
|
||||
|
||||
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int, uint32_t);
|
||||
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int);
|
||||
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, unsigned int, unsigned int, unsigned int, unsigned int, uint32_t);
|
||||
|
||||
typedef struct _mp_framebuf_p_t {
|
||||
setpixel_t setpixel;
|
||||
getpixel_t getpixel;
|
||||
fill_rect_t fill_rect;
|
||||
} mp_framebuf_p_t;
|
||||
|
||||
// constants for formats
|
||||
#define FRAMEBUF_MVLSB (0)
|
||||
#define FRAMEBUF_RGB565 (1)
|
||||
#define FRAMEBUF_GS2_HMSB (5)
|
||||
#define FRAMEBUF_GS4_HMSB (2)
|
||||
#define FRAMEBUF_GS8 (6)
|
||||
#define FRAMEBUF_MHLSB (3)
|
||||
#define FRAMEBUF_MHMSB (4)
|
||||
|
||||
// Functions for MHLSB and MHMSB
|
||||
|
||||
STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
size_t index = (x + y * fb->stride) >> 3;
|
||||
unsigned int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
|
||||
((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);
|
||||
}
|
||||
|
||||
STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
size_t index = (x + y * fb->stride) >> 3;
|
||||
unsigned int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
|
||||
return (((uint8_t *)fb->buf)[index] >> (offset)) & 0x01;
|
||||
}
|
||||
|
||||
STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
unsigned int reverse = fb->format == FRAMEBUF_MHMSB;
|
||||
unsigned int advance = fb->stride >> 3;
|
||||
while (w--) {
|
||||
uint8_t *b = &((uint8_t *)fb->buf)[(x >> 3) + y * advance];
|
||||
unsigned int offset = reverse ? x & 7 : 7 - (x & 7);
|
||||
for (unsigned int hh = h; hh; --hh) {
|
||||
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
|
||||
b += advance;
|
||||
}
|
||||
++x;
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for MVLSB format
|
||||
|
||||
STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
size_t index = (y >> 3) * fb->stride + x;
|
||||
uint8_t offset = y & 0x07;
|
||||
((uint8_t *)fb->buf)[index] = (((uint8_t *)fb->buf)[index] & ~(0x01 << offset)) | ((col != 0) << offset);
|
||||
}
|
||||
|
||||
STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
return (((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;
|
||||
}
|
||||
|
||||
STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
while (h--) {
|
||||
uint8_t *b = &((uint8_t *)fb->buf)[(y >> 3) * fb->stride + x];
|
||||
uint8_t offset = y & 0x07;
|
||||
for (unsigned int ww = w; ww; --ww) {
|
||||
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
|
||||
++b;
|
||||
}
|
||||
++y;
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for RGB565 format
|
||||
|
||||
STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
((uint16_t *)fb->buf)[x + y * fb->stride] = col;
|
||||
}
|
||||
|
||||
STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
return ((uint16_t *)fb->buf)[x + y * fb->stride];
|
||||
}
|
||||
|
||||
STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
uint16_t *b = &((uint16_t *)fb->buf)[x + y * fb->stride];
|
||||
while (h--) {
|
||||
for (unsigned int ww = w; ww; --ww) {
|
||||
*b++ = col;
|
||||
}
|
||||
b += fb->stride - w;
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for GS2_HMSB format
|
||||
|
||||
STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2];
|
||||
uint8_t shift = (x & 0x3) << 1;
|
||||
uint8_t mask = 0x3 << shift;
|
||||
uint8_t color = (col & 0x3) << shift;
|
||||
*pixel = color | (*pixel & (~mask));
|
||||
}
|
||||
|
||||
STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
uint8_t pixel = ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 2];
|
||||
uint8_t shift = (x & 0x3) << 1;
|
||||
return (pixel >> shift) & 0x3;
|
||||
}
|
||||
|
||||
STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
for (unsigned int xx = x; xx < x + w; xx++) {
|
||||
for (unsigned int yy = y; yy < y + h; yy++) {
|
||||
gs2_hmsb_setpixel(fb, xx, yy, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for GS4_HMSB format
|
||||
|
||||
STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1];
|
||||
|
||||
if (x % 2) {
|
||||
*pixel = ((uint8_t)col & 0x0f) | (*pixel & 0xf0);
|
||||
} else {
|
||||
*pixel = ((uint8_t)col << 4) | (*pixel & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
if (x % 2) {
|
||||
return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f;
|
||||
}
|
||||
|
||||
return ((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1] >> 4;
|
||||
}
|
||||
|
||||
STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
col &= 0x0f;
|
||||
uint8_t *pixel_pair = &((uint8_t *)fb->buf)[(x + y * fb->stride) >> 1];
|
||||
uint8_t col_shifted_left = col << 4;
|
||||
uint8_t col_pixel_pair = col_shifted_left | col;
|
||||
unsigned int pixel_count_till_next_line = (fb->stride - w) >> 1;
|
||||
bool odd_x = (x % 2 == 1);
|
||||
|
||||
while (h--) {
|
||||
unsigned int ww = w;
|
||||
|
||||
if (odd_x && ww > 0) {
|
||||
*pixel_pair = (*pixel_pair & 0xf0) | col;
|
||||
pixel_pair++;
|
||||
ww--;
|
||||
}
|
||||
|
||||
memset(pixel_pair, col_pixel_pair, ww >> 1);
|
||||
pixel_pair += ww >> 1;
|
||||
|
||||
if (ww % 2) {
|
||||
*pixel_pair = col_shifted_left | (*pixel_pair & 0x0f);
|
||||
if (!odd_x) {
|
||||
pixel_pair++;
|
||||
}
|
||||
}
|
||||
|
||||
pixel_pair += pixel_count_till_next_line;
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for GS8 format
|
||||
|
||||
STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)];
|
||||
*pixel = col & 0xff;
|
||||
}
|
||||
|
||||
STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
return ((uint8_t *)fb->buf)[(x + y * fb->stride)];
|
||||
}
|
||||
|
||||
STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint32_t col) {
|
||||
uint8_t *pixel = &((uint8_t *)fb->buf)[(x + y * fb->stride)];
|
||||
while (h--) {
|
||||
memset(pixel, col, w);
|
||||
pixel += fb->stride;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_framebuf_p_t formats[] = {
|
||||
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
|
||||
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
|
||||
[FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect},
|
||||
[FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect},
|
||||
[FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect},
|
||||
[FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
|
||||
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
|
||||
};
|
||||
|
||||
static inline void setpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y, uint32_t col) {
|
||||
formats[fb->format].setpixel(fb, x, y, col);
|
||||
}
|
||||
|
||||
static inline uint32_t getpixel(const mp_obj_framebuf_t *fb, unsigned int x, unsigned int y) {
|
||||
return formats[fb->format].getpixel(fb, x, y);
|
||||
}
|
||||
|
||||
STATIC void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
|
||||
if (h < 1 || w < 1 || x + w <= 0 || y + h <= 0 || y >= fb->height || x >= fb->width) {
|
||||
// No operation needed.
|
||||
return;
|
||||
}
|
||||
|
||||
// clip to the framebuffer
|
||||
int xend = MIN(fb->width, x + w);
|
||||
int yend = MIN(fb->height, y + h);
|
||||
x = MAX(x, 0);
|
||||
y = MAX(y, 0);
|
||||
|
||||
formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col);
|
||||
}
|
||||
|
||||
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) {
|
||||
mp_arg_check_num(n_args, n_kw, 4, 5, false);
|
||||
|
||||
mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);
|
||||
o->base.type = type;
|
||||
o->buf_obj = args[0];
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
o->buf = bufinfo.buf;
|
||||
|
||||
o->width = mp_obj_get_int(args[1]);
|
||||
o->height = mp_obj_get_int(args[2]);
|
||||
o->format = mp_obj_get_int(args[3]);
|
||||
if (n_args >= 5) {
|
||||
o->stride = mp_obj_get_int(args[4]);
|
||||
} else {
|
||||
o->stride = o->width;
|
||||
}
|
||||
|
||||
switch (o->format) {
|
||||
case FRAMEBUF_MVLSB:
|
||||
case FRAMEBUF_RGB565:
|
||||
break;
|
||||
case FRAMEBUF_MHLSB:
|
||||
case FRAMEBUF_MHMSB:
|
||||
o->stride = (o->stride + 7) & ~7;
|
||||
break;
|
||||
case FRAMEBUF_GS2_HMSB:
|
||||
o->stride = (o->stride + 3) & ~3;
|
||||
break;
|
||||
case FRAMEBUF_GS4_HMSB:
|
||||
o->stride = (o->stride + 1) & ~1;
|
||||
break;
|
||||
case FRAMEBUF_GS8:
|
||||
break;
|
||||
default:
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
#if !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME)
|
||||
STATIC const mp_obj_type_t mp_type_framebuf;
|
||||
#endif
|
||||
|
||||
// Helper to ensure we have the native super class instead of a subclass.
|
||||
static mp_obj_framebuf_t *native_framebuf(mp_obj_t framebuf_obj) {
|
||||
mp_obj_t native_framebuf = mp_obj_cast_to_native_base(framebuf_obj, &mp_type_framebuf);
|
||||
mp_obj_assert_native_inited(native_framebuf);
|
||||
if (native_framebuf == MP_OBJ_NULL) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
return MP_OBJ_TO_PTR(native_framebuf);
|
||||
}
|
||||
|
||||
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 = native_framebuf(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;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {
|
||||
mp_obj_framebuf_t *self = native_framebuf(self_in);
|
||||
mp_int_t col = mp_obj_get_int(col_in);
|
||||
formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf_fill_obj, framebuf_fill);
|
||||
|
||||
STATIC mp_obj_t framebuf_fill_rect(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
mp_int_t y = mp_obj_get_int(args[2]);
|
||||
mp_int_t width = mp_obj_get_int(args[3]);
|
||||
mp_int_t height = mp_obj_get_int(args[4]);
|
||||
mp_int_t col = mp_obj_get_int(args[5]);
|
||||
|
||||
fill_rect(self, x, y, width, height, col);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect);
|
||||
|
||||
STATIC mp_obj_t framebuf_pixel(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
mp_int_t y = mp_obj_get_int(args[2]);
|
||||
if (0 <= x && x < self->width && 0 <= y && y < self->height) {
|
||||
if (n_args == 3) {
|
||||
// get
|
||||
return MP_OBJ_NEW_SMALL_INT(getpixel(self, x, y));
|
||||
} else {
|
||||
// set
|
||||
setpixel(self, x, y, mp_obj_get_int(args[3]));
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_pixel_obj, 3, 4, framebuf_pixel);
|
||||
|
||||
STATIC mp_obj_t framebuf_hline(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
mp_int_t y = mp_obj_get_int(args[2]);
|
||||
mp_int_t w = mp_obj_get_int(args[3]);
|
||||
mp_int_t col = mp_obj_get_int(args[4]);
|
||||
|
||||
fill_rect(self, x, y, w, 1, col);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_hline_obj, 5, 5, framebuf_hline);
|
||||
|
||||
STATIC mp_obj_t framebuf_vline(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
mp_int_t y = mp_obj_get_int(args[2]);
|
||||
mp_int_t h = mp_obj_get_int(args[3]);
|
||||
mp_int_t col = mp_obj_get_int(args[4]);
|
||||
|
||||
fill_rect(self, x, y, 1, h, col);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_vline_obj, 5, 5, framebuf_vline);
|
||||
|
||||
STATIC mp_obj_t framebuf_rect(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x = mp_obj_get_int(args[1]);
|
||||
mp_int_t y = mp_obj_get_int(args[2]);
|
||||
mp_int_t w = mp_obj_get_int(args[3]);
|
||||
mp_int_t h = mp_obj_get_int(args[4]);
|
||||
mp_int_t col = mp_obj_get_int(args[5]);
|
||||
|
||||
fill_rect(self, x, y, w, 1, col);
|
||||
fill_rect(self, x, y + h - 1, w, 1, col);
|
||||
fill_rect(self, x, y, 1, h, col);
|
||||
fill_rect(self, x + w - 1, y, 1, h, col);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_rect_obj, 6, 6, framebuf_rect);
|
||||
|
||||
STATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_int_t x1 = mp_obj_get_int(args[1]);
|
||||
mp_int_t y1 = mp_obj_get_int(args[2]);
|
||||
mp_int_t x2 = mp_obj_get_int(args[3]);
|
||||
mp_int_t y2 = mp_obj_get_int(args[4]);
|
||||
mp_int_t col = mp_obj_get_int(args[5]);
|
||||
|
||||
mp_int_t dx = x2 - x1;
|
||||
mp_int_t sx;
|
||||
if (dx > 0) {
|
||||
sx = 1;
|
||||
} else {
|
||||
dx = -dx;
|
||||
sx = -1;
|
||||
}
|
||||
|
||||
mp_int_t dy = y2 - y1;
|
||||
mp_int_t sy;
|
||||
if (dy > 0) {
|
||||
sy = 1;
|
||||
} else {
|
||||
dy = -dy;
|
||||
sy = -1;
|
||||
}
|
||||
|
||||
bool steep;
|
||||
if (dy > dx) {
|
||||
mp_int_t temp;
|
||||
temp = x1;
|
||||
x1 = y1;
|
||||
y1 = temp;
|
||||
temp = dx;
|
||||
dx = dy;
|
||||
dy = temp;
|
||||
temp = sx;
|
||||
sx = sy;
|
||||
sy = temp;
|
||||
steep = true;
|
||||
} else {
|
||||
steep = false;
|
||||
}
|
||||
|
||||
mp_int_t e = 2 * dy - dx;
|
||||
for (mp_int_t i = 0; i < dx; ++i) {
|
||||
if (steep) {
|
||||
if (0 <= y1 && y1 < self->width && 0 <= x1 && x1 < self->height) {
|
||||
setpixel(self, y1, x1, col);
|
||||
}
|
||||
} else {
|
||||
if (0 <= x1 && x1 < self->width && 0 <= y1 && y1 < self->height) {
|
||||
setpixel(self, x1, y1, col);
|
||||
}
|
||||
}
|
||||
while (e >= 0) {
|
||||
y1 += sy;
|
||||
e -= 2 * dx;
|
||||
}
|
||||
x1 += sx;
|
||||
e += 2 * dy;
|
||||
}
|
||||
|
||||
if (0 <= x2 && x2 < self->width && 0 <= y2 && y2 < self->height) {
|
||||
setpixel(self, x2, y2, col);
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_line_obj, 6, 6, framebuf_line);
|
||||
|
||||
STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
mp_obj_framebuf_t *source = native_framebuf(args[1]);
|
||||
mp_int_t x = mp_obj_get_int(args[2]);
|
||||
mp_int_t y = mp_obj_get_int(args[3]);
|
||||
mp_int_t key = -1;
|
||||
if (n_args > 4) {
|
||||
key = mp_obj_get_int(args[4]);
|
||||
}
|
||||
mp_obj_framebuf_t *palette = NULL;
|
||||
if (n_args > 5 && args[5] != mp_const_none) {
|
||||
palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
|
||||
}
|
||||
|
||||
if (
|
||||
(x >= self->width) ||
|
||||
(y >= self->height) ||
|
||||
(-x >= source->width) ||
|
||||
(-y >= source->height)
|
||||
) {
|
||||
// Out of bounds, no-op.
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// Clip.
|
||||
int x0 = MAX(0, x);
|
||||
int y0 = MAX(0, y);
|
||||
int x1 = MAX(0, -x);
|
||||
int y1 = MAX(0, -y);
|
||||
int x0end = MIN(self->width, x + source->width);
|
||||
int y0end = MIN(self->height, y + source->height);
|
||||
|
||||
for (; y0 < y0end; ++y0) {
|
||||
int cx1 = x1;
|
||||
for (int cx0 = x0; cx0 < x0end; ++cx0) {
|
||||
uint32_t col = getpixel(source, cx1, y1);
|
||||
if (palette) {
|
||||
col = getpixel(palette, col, 0);
|
||||
}
|
||||
if (col != (uint32_t)key) {
|
||||
setpixel(self, cx0, y0, col);
|
||||
}
|
||||
++cx1;
|
||||
}
|
||||
++y1;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 6, framebuf_blit);
|
||||
|
||||
STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
|
||||
mp_obj_framebuf_t *self = native_framebuf(self_in);
|
||||
mp_int_t xstep = mp_obj_get_int(xstep_in);
|
||||
mp_int_t ystep = mp_obj_get_int(ystep_in);
|
||||
int sx, y, xend, yend, dx, dy;
|
||||
if (xstep < 0) {
|
||||
sx = 0;
|
||||
xend = self->width + xstep;
|
||||
dx = 1;
|
||||
} else {
|
||||
sx = self->width - 1;
|
||||
xend = xstep - 1;
|
||||
dx = -1;
|
||||
}
|
||||
if (ystep < 0) {
|
||||
y = 0;
|
||||
yend = self->height + ystep;
|
||||
dy = 1;
|
||||
} else {
|
||||
y = self->height - 1;
|
||||
yend = ystep - 1;
|
||||
dy = -1;
|
||||
}
|
||||
for (; y != yend; y += dy) {
|
||||
for (int x = sx; x != xend; x += dx) {
|
||||
setpixel(self, x, y, getpixel(self, x - xstep, y - ystep));
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf_scroll_obj, framebuf_scroll);
|
||||
|
||||
STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) {
|
||||
// extract arguments
|
||||
mp_obj_framebuf_t *self = native_framebuf(args[0]);
|
||||
const char *str = mp_obj_str_get_str(args[1]);
|
||||
mp_int_t x0 = mp_obj_get_int(args[2]);
|
||||
mp_int_t y0 = mp_obj_get_int(args[3]);
|
||||
mp_int_t col = 1;
|
||||
if (n_args >= 5) {
|
||||
col = mp_obj_get_int(args[4]);
|
||||
}
|
||||
|
||||
// loop over chars
|
||||
for (; *str; ++str) {
|
||||
// get char and make sure its in range of font
|
||||
int chr = *(uint8_t *)str;
|
||||
if (chr < 32 || chr > 127) {
|
||||
chr = 127;
|
||||
}
|
||||
// get char data
|
||||
const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8];
|
||||
// loop over char data
|
||||
for (int j = 0; j < 8; j++, x0++) {
|
||||
if (0 <= x0 && x0 < self->width) { // clip x
|
||||
uint vline_data = chr_data[j]; // each byte is a column of 8 pixels, LSB at top
|
||||
for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column
|
||||
if (vline_data & 1) { // only draw if pixel set
|
||||
if (0 <= y && y < self->height) { // clip y
|
||||
setpixel(self, x0, y, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text);
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf_pixel_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&framebuf_hline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&framebuf_vline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&framebuf_rect_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&framebuf_line_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&framebuf_blit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf_scroll_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf_text_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t mp_type_framebuf = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||
.name = MP_QSTR_FrameBuffer,
|
||||
.make_new = framebuf_make_new,
|
||||
.locals_dict = (mp_obj_dict_t *)&framebuf_locals_dict,
|
||||
MP_TYPE_EXTENDED_FIELDS(
|
||||
.buffer_p = { .get_buffer = framebuf_get_buffer },
|
||||
),
|
||||
};
|
||||
#endif
|
||||
|
||||
// this factory function is provided for backwards compatibility with old FrameBuffer1 class
|
||||
STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);
|
||||
o->base.type = (mp_obj_type_t *)&mp_type_framebuf;
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
o->buf = bufinfo.buf;
|
||||
|
||||
o->width = mp_obj_get_int(args[1]);
|
||||
o->height = mp_obj_get_int(args[2]);
|
||||
o->format = FRAMEBUF_MVLSB;
|
||||
if (n_args >= 4) {
|
||||
o->stride = mp_obj_get_int(args[3]);
|
||||
} else {
|
||||
o->stride = o->width;
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
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) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_framebuf = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&framebuf_module_globals,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_FRAMEBUF
|
388
extmod/modhashlib.c
Normal file
388
extmod/modhashlib.c
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_HASHLIB
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
#include "mbedtls/version.h"
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_HASHLIB_SHA256
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
#include "mbedtls/sha256.h"
|
||||
#else
|
||||
#include "lib/crypto-algorithms/sha256.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_HASHLIB_SHA1 || MICROPY_PY_HASHLIB_MD5
|
||||
|
||||
#if MICROPY_SSL_AXTLS
|
||||
#include "lib/axtls/crypto/crypto.h"
|
||||
#endif
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
#include "mbedtls/md5.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _mp_obj_hash_t {
|
||||
mp_obj_base_t base;
|
||||
bool final; // if set, update and digest raise an exception
|
||||
uintptr_t state[0]; // must be aligned to a machine word
|
||||
} mp_obj_hash_t;
|
||||
|
||||
static void hashlib_ensure_not_final(mp_obj_hash_t *self) {
|
||||
if (self->final) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_HASHLIB_SHA256
|
||||
STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#define mbedtls_sha256_starts_ret mbedtls_sha256_starts
|
||||
#define mbedtls_sha256_update_ret mbedtls_sha256_update
|
||||
#define mbedtls_sha256_finish_ret mbedtls_sha256_finish
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context), type);
|
||||
o->final = false;
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
||||
if (n_args == 1) {
|
||||
hashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 32);
|
||||
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void check_not_unicode(const mp_obj_t arg) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (mp_obj_is_str(arg)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("a bytes-like object is required"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "lib/crypto-algorithms/sha256.c"
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX), type);
|
||||
o->final = false;
|
||||
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
hashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
check_not_unicode(arg);
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_sha256_update_obj, hashlib_sha256_update);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_sha256_digest_obj, hashlib_sha256_digest);
|
||||
|
||||
STATIC const mp_rom_map_elem_t hashlib_sha256_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_sha256_update_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_sha256_digest_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(hashlib_sha256_locals_dict, hashlib_sha256_locals_dict_table);
|
||||
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
hashlib_sha256_type,
|
||||
MP_QSTR_sha256,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, hashlib_sha256_make_new,
|
||||
locals_dict, &hashlib_sha256_locals_dict
|
||||
);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_HASHLIB_SHA1
|
||||
STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);
|
||||
|
||||
#if MICROPY_SSL_AXTLS
|
||||
STATIC mp_obj_t hashlib_sha1_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(SHA1_CTX), type);
|
||||
o->final = false;
|
||||
SHA1_Init((SHA1_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
hashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA1_SIZE);
|
||||
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#define mbedtls_sha1_starts_ret mbedtls_sha1_starts
|
||||
#define mbedtls_sha1_update_ret mbedtls_sha1_update
|
||||
#define mbedtls_sha1_finish_ret mbedtls_sha1_finish
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t hashlib_sha1_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context), type);
|
||||
o->final = false;
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
||||
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
hashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 20);
|
||||
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
|
||||
mbedtls_sha1_free((mbedtls_sha1_context *)self->state);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_sha1_update_obj, hashlib_sha1_update);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_sha1_digest_obj, hashlib_sha1_digest);
|
||||
|
||||
STATIC const mp_rom_map_elem_t hashlib_sha1_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_sha1_update_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_sha1_digest_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(hashlib_sha1_locals_dict, hashlib_sha1_locals_dict_table);
|
||||
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
hashlib_sha1_type,
|
||||
MP_QSTR_sha1,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, hashlib_sha1_make_new,
|
||||
locals_dict, &hashlib_sha1_locals_dict
|
||||
);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_HASHLIB_MD5
|
||||
STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg);
|
||||
|
||||
#if MICROPY_SSL_AXTLS
|
||||
STATIC mp_obj_t hashlib_md5_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(MD5_CTX), type);
|
||||
o->final = false;
|
||||
MD5_Init((MD5_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
hashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, MD5_SIZE);
|
||||
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
#endif // MICROPY_SSL_AXTLS
|
||||
|
||||
#if MICROPY_SSL_MBEDTLS
|
||||
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x02070000
|
||||
#define mbedtls_md5_starts_ret mbedtls_md5_starts
|
||||
#define mbedtls_md5_update_ret mbedtls_md5_update
|
||||
#define mbedtls_md5_finish_ret mbedtls_md5_finish
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t hashlib_md5_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);
|
||||
mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context), type);
|
||||
o->final = false;
|
||||
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
||||
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
hashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t hashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
hashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 16);
|
||||
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
|
||||
mbedtls_md5_free((mbedtls_md5_context *)self->state);
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
#endif // MICROPY_SSL_MBEDTLS
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_md5_update_obj, hashlib_md5_update);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_md5_digest_obj, hashlib_md5_digest);
|
||||
|
||||
STATIC const mp_rom_map_elem_t hashlib_md5_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_md5_update_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_md5_digest_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(hashlib_md5_locals_dict, hashlib_md5_locals_dict_table);
|
||||
|
||||
STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||
hashlib_md5_type,
|
||||
MP_QSTR_md5,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, hashlib_md5_make_new,
|
||||
locals_dict, &hashlib_md5_locals_dict
|
||||
);
|
||||
#endif // MICROPY_PY_HASHLIB_MD5
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) },
|
||||
#if MICROPY_PY_HASHLIB_SHA256
|
||||
{ MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&hashlib_sha256_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_HASHLIB_SHA1
|
||||
{ MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&hashlib_sha1_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_HASHLIB_MD5
|
||||
{ MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&hashlib_md5_type) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_hashlib = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_hashlib_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_hashlib, mp_module_hashlib);
|
||||
|
||||
#endif // MICROPY_PY_HASHLIB
|
124
extmod/modheapq.c
Normal file
124
extmod/modheapq.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/objlist.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_HEAPQ
|
||||
|
||||
// the algorithm here is modelled on CPython's heapq.py
|
||||
|
||||
STATIC mp_obj_list_t *heapq_get_heap(mp_obj_t heap_in) {
|
||||
if (!mp_obj_is_type(heap_in, &mp_type_list)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("heap must be a list"));
|
||||
}
|
||||
return MP_OBJ_TO_PTR(heap_in);
|
||||
}
|
||||
|
||||
STATIC void heapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
mp_obj_t item = heap->items[pos];
|
||||
while (pos > start_pos) {
|
||||
mp_uint_t parent_pos = (pos - 1) >> 1;
|
||||
mp_obj_t parent = heap->items[parent_pos];
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
|
||||
heap->items[pos] = parent;
|
||||
pos = parent_pos;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
}
|
||||
|
||||
STATIC void heapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
mp_uint_t start_pos = pos;
|
||||
mp_uint_t end_pos = heap->len;
|
||||
mp_obj_t item = heap->items[pos];
|
||||
for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
|
||||
// choose right child if it's <= left child
|
||||
if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
|
||||
child_pos += 1;
|
||||
}
|
||||
// bubble up the smaller child
|
||||
heap->items[pos] = heap->items[child_pos];
|
||||
pos = child_pos;
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
heapq_heap_siftdown(heap, start_pos, pos);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_heapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
|
||||
mp_obj_list_t *heap = heapq_get_heap(heap_in);
|
||||
mp_obj_list_append(heap_in, item);
|
||||
heapq_heap_siftdown(heap, 0, heap->len - 1);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_heapq_heappush_obj, mod_heapq_heappush);
|
||||
|
||||
STATIC mp_obj_t mod_heapq_heappop(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = heapq_get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
|
||||
}
|
||||
mp_obj_t item = heap->items[0];
|
||||
heap->len -= 1;
|
||||
heap->items[0] = heap->items[heap->len];
|
||||
heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
|
||||
if (heap->len) {
|
||||
heapq_heap_siftup(heap, 0);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_heapq_heappop_obj, mod_heapq_heappop);
|
||||
|
||||
STATIC mp_obj_t mod_heapq_heapify(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = heapq_get_heap(heap_in);
|
||||
for (mp_uint_t i = heap->len / 2; i > 0;) {
|
||||
heapq_heap_siftup(heap, --i);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_heapq_heapify_obj, mod_heapq_heapify);
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t mp_module_heapq_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_heapq) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_heapq_heappush_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_heappop), MP_ROM_PTR(&mod_heapq_heappop_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_heapify), MP_ROM_PTR(&mod_heapq_heapify_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_heapq_globals, mp_module_heapq_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_heapq = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_heapq_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_heapq, mp_module_heapq);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_HEAPQ
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user