Merge branch 'adafruit:main' into add-raspberry-breadstick

This commit is contained in:
Michael Rangen 2023-11-18 12:30:42 -07:00 committed by GitHub
commit f45046bb11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2714 changed files with 68876 additions and 46380 deletions

View File

@ -20,3 +20,9 @@ deques
extint
shs
pass-thru
numer
arithmetics
ftbfs
straightaway
ftbs
ftb

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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: |

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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: |

View File

@ -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
View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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).

View File

@ -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,

View File

@ -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:

View File

@ -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
View File

@ -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

View File

@ -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;
}

View File

@ -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"));
}

View File

@ -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"));
// }
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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 = {

View File

@ -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"));
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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, /)

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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>`_.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
View File

@ -0,0 +1,38 @@
:mod:`platform` -- access to underlying platforms identifying data
===================================================================
.. module:: platform
:synopsis: access to underlying platforms 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.

View File

@ -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

View File

@ -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

View File

@ -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
View 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`

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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
View 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;
}

View File

@ -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

View File

@ -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
View 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 :
```

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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

View File

@ -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

View 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
}

View 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

View 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
}

View File

@ -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
}

View File

@ -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

View 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
}

View File

@ -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

View 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
}

View File

@ -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

View File

@ -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));

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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++

View File

@ -0,0 +1 @@
This is an example of a user C module that includes subpackages.

View 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)

View 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

View 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);

View File

@ -0,0 +1,2 @@
Q(example_package.foo)
Q(example_package.foo.bar)

View File

@ -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"

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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
View 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

View File

@ -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
View 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
View 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