7 Commits

Author SHA1 Message Date
ccdecf255d rp2: Allow using btree module with rp2 port
Integrate btree extmod in rp2 CMakeLists so it can be enabeled with
MICROPY_PY_BTREE=On.

Default values for DEFPSIZE and MINCACHE copied from esp8266 board.

Note: To be able to use the btree module, you must set the
MICROPY_C_HEAP_SIZE CMake option to at least 8192.
2025-08-19 19:57:04 +02:00
Angus Gratton
a792c8f3bf lib/littlefs: Fix string initializer in lfs1.c.
Avoids the new Wunterminated-string-literal when compiled with gcc 15.1.

It would be preferable to just disable this warning, but Clang
-Wunknown-warning-option kicks in even when disabling warnings so this
becomes fiddly to apply.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2025-05-20 20:04:43 +02:00
Angus Gratton
f4ff9dac89 py/emitinlinethumb: Refactor string literal as array initializer.
Avoids the new Wunterminated-string-literal when compiled with gcc 15.1.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2025-05-20 20:04:31 +02:00
Angus Gratton
fb05f048e9 extmod/moductypes: Refactor string literal as array initializer.
Avoids the new Wunterminated-string-literal when compiled with gcc 15.1.

Also split out the duplicate string to a top-level array (probably the
duplicate string literal was interned, so unlikely to have any impact.)

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2025-05-20 20:04:17 +02:00
Angus Gratton
f6a4651af9 rp2: Add temporary workaround for GCC 15.1 build failure.
This is a workaround for this upstream issue:
https://github.com/raspberrypi/pico-sdk/issues/2448

Can be removed after the next pico-sdk update.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
2025-05-20 20:03:58 +02:00
33dc78967d rp2: Fix stacks for multicore operation
Unfortunately, no way to override this from board config.
2025-05-20 19:57:07 +02:00
074dd7ac06 rp2: Modify linker script to run MP3 decoder from RAM 2025-05-20 19:56:50 +02:00
880 changed files with 6198 additions and 24945 deletions

View File

@@ -5,8 +5,6 @@ on:
pull_request:
paths:
- docs/**
- py/**
- tests/cpydiff/**
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -21,7 +19,5 @@ jobs:
- uses: actions/setup-python@v5
- name: Install Python packages
run: pip install -r docs/requirements.txt
- name: Build unix port
run: source tools/ci.sh && ci_unix_build_helper
- name: Build docs
run: make -C docs/ html

View File

@@ -25,7 +25,6 @@ jobs:
ci_func: # names are functions in ci.sh
- esp32_build_cmod_spiram_s2
- esp32_build_s3_c3
- esp32_build_c2_c6
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View File

@@ -20,20 +20,13 @@ concurrency:
jobs:
build_and_test_arm:
strategy:
fail-fast: false
matrix:
ci_func: # names are functions in ci.sh
- bigendian
- sabrelite
- thumb
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install packages
run: source tools/ci.sh && ci_qemu_setup_arm
- name: Build and run test suite ci_qemu_build_arm_${{ matrix.ci_func }}
run: source tools/ci.sh && ci_qemu_build_arm_${{ matrix.ci_func }}
- name: Build and run test suite
run: source tools/ci.sh && ci_qemu_build_arm
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures

View File

@@ -71,11 +71,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
with:
python-version: '3.11'
- name: Install packages
run: source tools/ci.sh && ci_unix_coverage_setup
- name: Build
@@ -134,20 +129,6 @@ jobs:
if: failure()
run: tests/run-tests.py --print-failures
longlong:
runs-on: ubuntu-22.04 # use 22.04 to get python2, and libffi-dev:i386
steps:
- uses: actions/checkout@v4
- name: Install packages
run: source tools/ci.sh && ci_unix_32bit_setup
- name: Build
run: source tools/ci.sh && ci_unix_longlong_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_longlong_run_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
float:
runs-on: ubuntu-latest
steps:
@@ -160,18 +141,6 @@ jobs:
if: failure()
run: tests/run-tests.py --print-failures
gil_enabled:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: source tools/ci.sh && ci_unix_gil_enabled_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_gil_enabled_run_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
stackless_clang:
runs-on: ubuntu-latest
steps:
@@ -200,6 +169,23 @@ jobs:
if: failure()
run: tests/run-tests.py --print-failures
settrace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
with:
python-version: '3.11'
- name: Build
run: source tools/ci.sh && ci_unix_settrace_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_settrace_run_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
settrace_stackless:
runs-on: ubuntu-latest
steps:
@@ -276,53 +262,3 @@ jobs:
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
sanitize_address:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
with:
python-version: '3.11'
- name: Install packages
run: source tools/ci.sh && ci_unix_coverage_setup
- name: Build
run: source tools/ci.sh && ci_unix_sanitize_address_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_sanitize_address_run_tests
- name: Test merging .mpy files
run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests
- name: Build native mpy modules
run: source tools/ci.sh && ci_native_mpy_modules_build
- name: Test importing .mpy generated by mpy_ld.py
run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
sanitize_undefined:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
with:
python-version: '3.11'
- name: Install packages
run: source tools/ci.sh && ci_unix_coverage_setup
- name: Build
run: source tools/ci.sh && ci_unix_sanitize_undefined_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_sanitize_undefined_run_tests
- name: Test merging .mpy files
run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests
- name: Build native mpy modules
run: source tools/ci.sh && ci_native_mpy_modules_build
- name: Test importing .mpy generated by mpy_ld.py
run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures

View File

@@ -28,10 +28,13 @@ jobs:
visualstudio: ['2017', '2019', '2022']
include:
- visualstudio: '2017'
runner: windows-latest
vs_version: '[15, 16)'
- visualstudio: '2019'
runner: windows-2019
vs_version: '[16, 17)'
- visualstudio: '2022'
runner: windows-2022
vs_version: '[17, 18)'
# trim down the number of jobs in the matrix
exclude:
@@ -39,9 +42,9 @@ jobs:
configuration: Debug
- visualstudio: '2019'
configuration: Debug
runs-on: windows-latest
env:
CI_BUILD_CONFIGURATION: ${{ matrix.configuration }}
runs-on: ${{ matrix.runner }}
steps:
- name: Install Visual Studio 2017
if: matrix.visualstudio == '2017'
@@ -49,15 +52,13 @@ jobs:
choco install visualstudio2017buildtools
choco install visualstudio2017-workload-vctools
choco install windows-sdk-8.1
- name: Install Visual Studio 2019
if: matrix.visualstudio == '2019'
run: |
choco install visualstudio2019buildtools
choco install visualstudio2019-workload-vctools
choco install windows-sdk-8.1
- uses: microsoft/setup-msbuild@v2
with:
vs-version: ${{ matrix.vs_version }}
- uses: actions/setup-python@v5
if: matrix.runner == 'windows-2019'
with:
python-version: '3.9'
- uses: actions/checkout@v4
- name: Build mpy-cross.exe
run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }}
@@ -102,7 +103,7 @@ jobs:
env: i686
- sys: mingw64
env: x86_64
runs-on: windows-latest
runs-on: windows-2022
env:
CHERE_INVOKING: enabled_from_arguments
defaults:

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ruff version should be kept in sync with .pre-commit-config.yaml & also micropython-lib
- run: pipx install ruff==0.11.6
# ruff version should be kept in sync with .pre-commit-config.yaml
- run: pipx install ruff==0.9.6
- run: ruff check --output-format=github .
- run: ruff format --diff .

View File

@@ -12,8 +12,8 @@ repos:
verbose: true
stages: [commit-msg]
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Version should be kept in sync with .github/workflows/ruff.yml & also micropython-lib
rev: v0.11.6
# Version should be kept in sync with .github/workflows/ruff.yml
rev: v0.9.6
hooks:
- id: ruff
- id: ruff-format

View File

@@ -206,21 +206,14 @@ adhere to the existing style and use `tools/codeformat.py` to check any changes.
The main conventions, and things not enforceable via the auto-formatter, are
described below.
As the MicroPython code base is over ten years old, not every source file
conforms fully to these conventions. If making small changes to existing code,
then it's usually acceptable to follow the existing code's style. New code or
major changes should follow the conventions described here.
## White space
White space:
- Expand tabs to 4 spaces.
- Don't leave trailing whitespace at the end of a line.
- For control blocks (if, for, while), put 1 space between the
keyword and the opening parenthesis.
- Put 1 space after a comma, and 1 space around operators.
## Braces
Braces:
- Use braces for all blocks, even no-line and single-line pieces of
code.
- Put opening braces on the end of the line it belongs to, not on
@@ -228,43 +221,18 @@ major changes should follow the conventions described here.
- For else-statements, put the else on the same line as the previous
closing brace.
## Header files
Header files:
- Header files should be protected from multiple inclusion with #if
directives. See an existing header for naming convention.
## Names
Names:
- Use underscore_case, not camelCase for all names.
- Use CAPS_WITH_UNDERSCORE for enums and macros.
- When defining a type use underscore_case and put '_t' after it.
### Public names (declared in headers)
- MicroPython-specific names (especially any declared in `py/` and `extmod/`
directories) should generally start with `mp_` or `MP_`.
- Functions and variables declared in a header should generally share a longer
common prefix. Usually the prefix matches the file name (i.e. items defined in
`py/obj.c` are declared in `py/obj.h` and should be prefixed `mp_obj_`). There
are exceptions, for example where one header file contains declarations
implemented in multiple source files for expediency.
### Private names (specific to a single .c file)
- For static functions and variables exposed to Python (i.e. a static C function
that is wrapped in `MP_DEFINE_CONST_FUN_...` and attached to a module), use
the file-level shared common prefix, i.e. name them as if the function or
variable was not static.
- Other static definitions in source files (i.e. functions or variables defined
in a .c file that are only used within that .c file) don't need any prefix
(specifically: no `s_` or `_` prefix, and generally avoid adding the
file-level common prefix).
## Integer types
MicroPython runs on 16, 32, and 64 bit machines, so it's important to use the
correctly-sized (and signed) integer types. The general guidelines are:
Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's
important to use the correctly-sized (and signed) integer types. The
general guidelines are:
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
integer values. These are guaranteed to be machine-word sized and
therefore big enough to hold the value from a MicroPython small-int
@@ -273,13 +241,11 @@ correctly-sized (and signed) integer types. The general guidelines are:
- You can use int/uint, but remember that they may be 16-bits wide.
- If in doubt, use mp_int_t/mp_uint_t.
## Comments
Comments:
- Be concise and only write comments for things that are not obvious.
- Use `// ` prefix, NOT `/* ... */`. No extra fluff.
## Memory allocation
Memory allocation:
- Use m_new, m_renew, m_del (and friends) to allocate and free heap memory.
These macros are defined in py/misc.h.

View File

@@ -67,9 +67,6 @@ The known limitations are:
* static BSS variables are not supported; workaround: use global BSS variables
* thread-local storage variables are not supported on rv32imc; workaround: use
global BSS variables or allocate some space on the heap to store them
So, if your C code has writable data, make sure the data is defined globally,
without an initialiser, and only written to within functions.
@@ -84,14 +81,7 @@ Linker limitation: the native module is not linked against the symbol table of t
full MicroPython firmware. Rather, it is linked against an explicit table of exported
symbols found in ``mp_fun_table`` (in ``py/nativeglue.h``), that is fixed at firmware
build time. It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system
function, for example, unless that resides at a fixed address. In that case, the path
of a linkerscript containing a series of symbol names and their fixed address can be
passed to ``mpy_ld.py`` via the ``--externs`` command line argument. That way symbols
appearing in the linkerscript will take precedence over what is provided from object
files, but at the moment the object files' implementation will still reside in the
final MPY file. The linkerscript parser is limited in its capabilities, and is
currently used only for parsing the ESP8266 port ROM symbols list (see
``ports/esp8266/boards/eagle.rom.addr.v6.ld``).
function, for example.
New symbols can be added to the end of the table and the firmware rebuilt.
The symbols also need to be added to ``tools/mpy_ld.py``'s ``fun_table`` dict in the
@@ -228,26 +218,6 @@ other module, for example::
print(factorial.factorial(10))
# should display 3628800
Using Picolibc when building modules
------------------------------------
Using `Picolibc <https://github.com/picolibc/picolibc>`_ as your C standard
library is not only supported, but in fact it is the default for the rv32imc
platform. However, there are a couple of things worth mentioning to make sure
you don't run into problems later when building code.
Some pre-built Picolibc versions (for example, those provided by Ubuntu Linux
as the ``picolibc-arm-none-eabi``, ``picolibc-riscv64-unknown-elf``, and
``picolibc-xtensa-lx106-elf`` packages) assume thread-local storage (TLS) is
available at runtime, but unfortunately MicroPython modules do not support that
on some architectures (namely ``rv32imc``). This means that some
functionalities provided by Picolibc will default to use TLS, returning an
error either during compilation or during linking.
For an example on how this may affect you, the ``examples/natmod/btree``
example module contains a workaround to make sure ``errno`` works (look for
``__PICOLIBC_ERRNO_FUNCTION`` in the Makefile and follow the trail from there).
Further examples
----------------

View File

@@ -25,8 +25,7 @@ Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new features
+--------------------------------------------------------+--------------------------------------------------+-----------------+
| `PEP 468 <https://www.python.org/dev/peps/pep-0468/>`_ | Preserving the order of *kwargs* in a function | |
+--------------------------------------------------------+--------------------------------------------------+-----------------+
| `PEP 487 <https://www.python.org/dev/peps/pep-0487/>`_ | Simpler customization of class creation | Partial |
| | | [#setname]_ |
| `PEP 487 <https://www.python.org/dev/peps/pep-0487/>`_ | Simpler customization of class creation | |
+--------------------------------------------------------+--------------------------------------------------+-----------------+
| `PEP 520 <https://www.python.org/dev/peps/pep-0520/>`_ | Preserving Class Attribute Definition Order | |
+--------------------------------------------------------+--------------------------------------------------+-----------------+
@@ -199,7 +198,3 @@ Changes to built-in modules:
+--------------------------------------------------------------------------------------------------------------+----------------+
| The *compress()* and *decompress()* functions now accept keyword arguments | |
+--------------------------------------------------------------------------------------------------------------+----------------+
.. rubric:: Notes
.. [#setname] Currently, only :func:`__set_name__` is implemented.

View File

@@ -148,7 +148,6 @@ Required keyword arguments for the constructor:
- ``mdc`` and ``mdio`` - :class:`machine.Pin` objects (or integers) specifying
the MDC and MDIO pins.
- ``phy_type`` - Select the PHY device type. Supported devices are
``PHY_GENERIC``,
``PHY_LAN8710``, ``PHY_LAN8720``, ``PHY_IP101``, ``PHY_RTL8201``,
``PHY_DP83848``, ``PHY_KSZ8041`` and ``PHY_KSZ8081``. These values are all
constants defined in the ``network`` module.
@@ -271,10 +270,8 @@ Use the :mod:`time <time>` module::
Timers
------
The ESP32 port has one, two or four hardware timers, depending on the ESP32 device type.
There is 1 timer for ESP32C2, 2 timers for ESP32C4, ESP32C6 and ESP32H4, and
4 timers otherwise. Use the :ref:`machine.Timer <machine.Timer>` class
with a timer ID of 0, 0 and 1, or from 0 to 3 (inclusive)::
The ESP32 port has four hardware timers. Use the :ref:`machine.Timer <machine.Timer>` class
with a timer ID from 0 to 3 (inclusive)::
from machine import Timer
@@ -284,8 +281,7 @@ with a timer ID of 0, 0 and 1, or from 0 to 3 (inclusive)::
tim1 = Timer(1)
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))
The period is in milliseconds. When using UART.IRQ_RXIDLE, timer 0 is needed for
the IRQ_RXIDLE mechanism and must not be used otherwise.
The period is in milliseconds.
Virtual timers are not currently supported on this port.
@@ -387,7 +383,7 @@ for more details.
Use the :ref:`machine.PWM <machine.PWM>` class::
from machine import Pin, PWM, lightsleep
from machine import Pin, PWM
pwm0 = PWM(Pin(0), freq=5000, duty_u16=32768) # create PWM object from a pin
freq = pwm0.freq() # get current frequency
@@ -397,7 +393,7 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
pwm0.duty(256) # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%)
duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65535
pwm0.duty_u16(65536*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
pwm0.duty_u16(2**16*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
duty_ns = pwm0.duty_ns() # get current pulse width in ns
pwm0.duty_ns(250_000) # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%)
@@ -406,35 +402,19 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
print(pwm2) # view PWM settings
pwm2.deinit() # turn off PWM on the pin
pwm0 = PWM(Pin(0), duty_u16=16384) # The output is at a high level 25% of the time.
pwm2 = PWM(Pin(2), duty_u16=16384, invert=1) # The output is at a low level 25% of the time.
pwm4 = PWM(Pin(4), lightsleep=True) # Allow PWM during light sleep mode
lightsleep(10*1000) # pwm0, pwm2 goes off, pwm4 stays on during 10s light sleep
# pwm0, pwm2, pwm4 on after 10s light sleep
ESP chips have different hardware peripherals:
======================================================= ======== ========= ==========
Hardware specification ESP32 ESP32-S2, ESP32-C2,
ESP32-S3, ESP32-C3,
ESP32-P4 ESP32-C5,
ESP32-C6,
ESP32-H2
------------------------------------------------------- -------- --------- ----------
Number of groups (speed modes) 2 1 1
Number of timers per group 4 4 4
Number of channels per group 8 8 6
------------------------------------------------------- -------- --------- ----------
Different PWM frequencies = (groups * timers) 8 4 4
Total PWM channels (Pins, duties) = (groups * channels) 16 8 6
======================================================= ======== ========= ==========
In light sleep, the ESP32 PWM can only operate in low speed mode, so only 4 timers and
8 channels are available.
===================================================== ======== ======== ========
Hardware specification ESP32 ESP32-S2 ESP32-C3
----------------------------------------------------- -------- -------- --------
Number of groups (speed modes) 2 1 1
Number of timers per group 4 4 4
Number of channels per group 8 8 6
----------------------------------------------------- -------- -------- --------
Different PWM frequencies (groups * timers) 8 4 4
Total PWM channels (Pins, duties) (groups * channels) 16 8 6
===================================================== ======== ======== ========
A maximum number of PWM channels (Pins) are available on the ESP32 - 16 channels,
but only 8 different PWM frequencies are available, the remaining 8 channels must
@@ -544,63 +524,14 @@ Legacy methods:
Equivalent to ``ADC.block().init(bits=bits)``.
The only chip that can switch resolution to a lower one is the normal esp32.
The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits.
For compatibility, the ``ADC`` object also provides constants matching the
supported ADC resolutions, per chip:
supported ADC resolutions:
ESP32:
- ``ADC.WIDTH_9BIT`` = 9
- ``ADC.WIDTH_10BIT`` = 10
- ``ADC.WIDTH_11BIT`` = 11
- ``ADC.WIDTH_12BIT`` = 12
ESP32 C3 & S3:
- ``ADC.WIDTH_12BIT`` = 12
ESP32 S2:
- ``ADC.WIDTH_13BIT`` = 13
.. method:: ADC.deinit()
Provided to deinit the adc driver.
Pulse Counter (pin pulse/edge counting)
---------------------------------------
The ESP32 provides up to 8 pulse counter peripherals depending on the hardware,
with id 0..7. These can be configured to count rising and/or falling edges on
any input pin.
Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
from machine import Pin
from esp32 import PCNT
counter = PCNT(0, pin=Pin(2), rising=PCNT.INCREMENT) # create counter
counter.start() # start counter
count = counter.value() # read count, -32768..32767
counter.value(0) # reset counter
count = counter.value(0) # read and reset
The PCNT hardware supports monitoring multiple pins in a single unit to
implement quadrature decoding or up/down signal counters.
See the :ref:`machine.Counter <machine.Counter>` and
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
common pulse counting applications::
from machine import Pin, Counter
counter = Counter(0, Pin(2)) # create a counter as above and start it
count = counter.value() # read the count as an arbitrary precision signed integer
encoder = Encoder(0, Pin(12), Pin(14)) # create an encoder and begin counting
count = encoder.value() # read the count as an arbitrary precision signed integer
Note that the id passed to these ``Counter()`` and ``Encoder()`` objects must be
a PCNT id.
Software SPI bus
----------------
@@ -838,9 +769,6 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with
# The channel resolution is 100ns (1/(source_freq/clock_div)).
r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
The ESP32-C2 family does not include any RMT peripheral, so this class is
unavailable on those SoCs.
OneWire driver
--------------

View File

@@ -11,20 +11,16 @@ compared with the length of a single period (low plus high time). Maximum
duty cycle is when the pin is high all of the time, and minimum is when it is
low all of the time.
* More comprehensive example with all **16 PWM channels and 8 timers**::
* More comprehensive example with all 16 PWM channels and 8 timers::
from time import sleep
from machine import Pin, PWM
try:
F = 10000 # Hz
D = 65536 // 16 # 6.25%
pins = (2, 4, 12, 13, 14, 15, 16, 18, 19, 22, 23, 25, 26, 27, 32, 33)
f = 100 # Hz
d = 1024 // 16 # 6.25%
pins = (15, 2, 4, 16, 18, 19, 22, 23, 25, 26, 27, 14 , 12, 13, 32, 33)
pwms = []
for i, pin in enumerate(pins):
f = F * (i // 2 + 1)
d = min(65535, D * (i + 1))
pwms.append(PWM(pin, freq=f, duty_u16=d))
sleep(2 / f)
pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1)))
print(pwms[i])
finally:
for pwm in pwms:
@@ -35,100 +31,65 @@ low all of the time.
Output is::
PWM(Pin(2), freq=10000, duty_u16=4096)
PWM(Pin(4), freq=10000, duty_u16=8192)
PWM(Pin(12), freq=20000, duty_u16=12288)
PWM(Pin(13), freq=20000, duty_u16=16384)
PWM(Pin(14), freq=30030, duty_u16=20480)
PWM(Pin(15), freq=30030, duty_u16=24576)
PWM(Pin(16), freq=40000, duty_u16=28672)
PWM(Pin(18), freq=40000, duty_u16=32768)
PWM(Pin(19), freq=50000, duty_u16=36864)
PWM(Pin(22), freq=50000, duty_u16=40960)
PWM(Pin(23), freq=60060, duty_u16=45056)
PWM(Pin(25), freq=60060, duty_u16=49152)
PWM(Pin(26), freq=69930, duty_u16=53248)
PWM(Pin(27), freq=69930, duty_u16=57344)
PWM(Pin(32), freq=80000, duty_u16=61440)
PWM(Pin(33), freq=80000, duty_u16=65535)
PWM(Pin(15), freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0)
PWM(Pin(2), freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0)
PWM(Pin(4), freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1)
PWM(Pin(16), freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1)
PWM(Pin(18), freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2)
PWM(Pin(19), freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2)
PWM(Pin(22), freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3)
PWM(Pin(23), freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3)
PWM(Pin(25), freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0)
PWM(Pin(26), freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0)
PWM(Pin(27), freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1)
PWM(Pin(14), freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1)
PWM(Pin(12), freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2)
PWM(Pin(13), freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2)
PWM(Pin(32), freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3)
PWM(Pin(33), freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3)
* Example of a **smooth frequency change**::
* Example of a smooth frequency change::
from time import sleep
from machine import Pin, PWM
F_MIN = 1000
F_MAX = 10000
F_MIN = 500
F_MAX = 1000
f = F_MIN
delta_f = F_MAX // 50
delta_f = 1
pwm = PWM(Pin(27), f)
p = PWM(Pin(5), f)
print(p)
while True:
pwm.freq(f)
sleep(1 / f)
sleep(0.1)
print(pwm)
p.freq(f)
sleep(10 / F_MIN)
f += delta_f
if f > F_MAX or f < F_MIN:
if f >= F_MAX or f <= F_MIN:
delta_f = -delta_f
print()
if f > F_MAX:
f = F_MAX
elif f < F_MIN:
f = F_MIN
See PWM wave on Pin(27) with an oscilloscope.
See PWM wave at Pin(5) with an oscilloscope.
Output is::
PWM(Pin(27), freq=998, duty_u16=32768)
PWM(Pin(27), freq=1202, duty_u16=32768)
PWM(Pin(27), freq=1401, duty_u16=32768)
PWM(Pin(27), freq=1598, duty_u16=32768)
...
PWM(Pin(27), freq=9398, duty_u16=32768)
PWM(Pin(27), freq=9615, duty_u16=32768)
PWM(Pin(27), freq=9804, duty_u16=32768)
PWM(Pin(27), freq=10000, duty_u16=32768)
PWM(Pin(27), freq=10000, duty_u16=32768)
PWM(Pin(27), freq=9804, duty_u16=32768)
PWM(Pin(27), freq=9615, duty_u16=32768)
PWM(Pin(27), freq=9398, duty_u16=32768)
...
PWM(Pin(27), freq=1598, duty_u16=32768)
PWM(Pin(27), freq=1401, duty_u16=32768)
PWM(Pin(27), freq=1202, duty_u16=32768)
PWM(Pin(27), freq=998, duty_u16=32768)
* Example of a **smooth duty change**::
* Example of a smooth duty change::
from time import sleep
from machine import Pin, PWM
DUTY_MAX = 65535
DUTY_MAX = 2**16 - 1
duty_u16 = 0
delta_d = 256
delta_d = 16
pwm = PWM(Pin(27), freq=1000, duty_u16=duty_u16)
p = PWM(Pin(5), 1000, duty_u16=duty_u16)
print(p)
while True:
pwm.duty_u16(duty_u16)
sleep(2 / pwm.freq())
print(pwm)
p.duty_u16(duty_u16)
if duty_u16 >= DUTY_MAX:
print()
sleep(2)
elif duty_u16 <= 0:
print()
sleep(2)
sleep(1 / 1000)
duty_u16 += delta_d
if duty_u16 >= DUTY_MAX:
@@ -138,106 +99,9 @@ low all of the time.
duty_u16 = 0
delta_d = -delta_d
PWM wave on Pin(27) with an oscilloscope.
See PWM wave at Pin(5) with an oscilloscope.
Output is::
PWM(Pin(27), freq=998, duty_u16=0)
PWM(Pin(27), freq=998, duty_u16=256)
PWM(Pin(27), freq=998, duty_u16=512)
PWM(Pin(27), freq=998, duty_u16=768)
PWM(Pin(27), freq=998, duty_u16=1024)
...
PWM(Pin(27), freq=998, duty_u16=64512)
PWM(Pin(27), freq=998, duty_u16=64768)
PWM(Pin(27), freq=998, duty_u16=65024)
PWM(Pin(27), freq=998, duty_u16=65280)
PWM(Pin(27), freq=998, duty_u16=65535)
PWM(Pin(27), freq=998, duty_u16=65279)
PWM(Pin(27), freq=998, duty_u16=65023)
PWM(Pin(27), freq=998, duty_u16=64767)
PWM(Pin(27), freq=998, duty_u16=64511)
...
PWM(Pin(27), freq=998, duty_u16=1023)
PWM(Pin(27), freq=998, duty_u16=767)
PWM(Pin(27), freq=998, duty_u16=511)
PWM(Pin(27), freq=998, duty_u16=255)
PWM(Pin(27), freq=998, duty_u16=0)
* Example of a **smooth duty change and PWM output inversion**::
from utime import sleep
from machine import Pin, PWM
try:
DUTY_MAX = 65535
duty_u16 = 0
delta_d = 65536 // 32
pwm = PWM(Pin(27))
pwmi = PWM(Pin(32), invert=1)
while True:
pwm.duty_u16(duty_u16)
pwmi.duty_u16(duty_u16)
duty_u16 += delta_d
if duty_u16 >= DUTY_MAX:
duty_u16 = DUTY_MAX
delta_d = -delta_d
elif duty_u16 <= 0:
duty_u16 = 0
delta_d = -delta_d
sleep(.01)
print(pwm)
print(pwmi)
finally:
try:
pwm.deinit()
except:
pass
try:
pwmi.deinit()
except:
pass
Output is::
PWM(Pin(27), freq=5000, duty_u16=0)
PWM(Pin(32), freq=5000, duty_u16=32768, invert=1)
PWM(Pin(27), freq=5000, duty_u16=2048)
PWM(Pin(32), freq=5000, duty_u16=2048, invert=1)
PWM(Pin(27), freq=5000, duty_u16=4096)
PWM(Pin(32), freq=5000, duty_u16=4096, invert=1)
PWM(Pin(27), freq=5000, duty_u16=6144)
PWM(Pin(32), freq=5000, duty_u16=6144, invert=1)
PWM(Pin(27), freq=5000, duty_u16=8192)
PWM(Pin(32), freq=5000, duty_u16=8192, invert=1)
...
See PWM waves on Pin(27) and Pin(32) with an oscilloscope.
Note: New PWM parameters take effect in the next PWM cycle.
pwm = PWM(2, duty=512)
print(pwm)
>>> PWM(Pin(2), freq=5000, duty=1023) # the duty is not relevant
pwm.init(freq=2, duty=64)
print(pwm)
>>> PWM(Pin(2), freq=2, duty=16) # the duty is not relevant
time.sleep(1 / 2) # wait one PWM period
print(pwm)
>>> PWM(Pin(2), freq=2, duty=64) # the duty is actual
Note: machine.freq(20_000_000) reduces the highest PWM frequency to 10 MHz.
Note: the Pin.OUT mode does not need to be specified. The channel is initialized
Note: the Pin.OUT mode does not need to be specified. The channel is initialized
to PWM mode internally once for each Pin that is passed to the PWM constructor.
The following code is wrong::

View File

@@ -764,5 +764,4 @@ Constructor
The **value** can be either:
- A 16-bit integer. e.g. ``0x2908``.
- An object with the buffer protocol and that is 2, 4 or 16 bytes long, e.g. ``b'\x08\x29'``.
- A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``.

View File

@@ -151,10 +151,10 @@ Constants
.. data:: INCL
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that
A flag for `keys()`, `values()`, `items()` methods to specify that
scanning should be inclusive of the end key.
.. data:: DESC
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that
A flag for `keys()`, `values()`, `items()` methods to specify that
scanning should be in descending direction of keys.

View File

@@ -18,31 +18,23 @@ Functions
Configure whether or not a touch will wake the device from sleep.
*wake* should be a boolean value.
.. note:: This is only available for boards that have touch sensor support.
.. function:: wake_on_ulp(wake)
Configure whether or not the Ultra-Low-Power co-processor can wake the
device from sleep. *wake* should be a boolean value.
.. note:: This is only available for boards that have ULP coprocessor support.
.. function:: wake_on_ext0(pin, level)
Configure how EXT0 wakes the device from sleep. *pin* can be ``None``
or a valid Pin object. *level* should be ``esp32.WAKEUP_ALL_LOW`` or
``esp32.WAKEUP_ANY_HIGH``.
.. note:: This is only available for boards that have ext0 support.
.. function:: wake_on_ext1(pins, level)
Configure how EXT1 wakes the device from sleep. *pins* can be ``None``
or a tuple/list of valid Pin objects. *level* should be ``esp32.WAKEUP_ALL_LOW``
or ``esp32.WAKEUP_ANY_HIGH``.
.. note:: This is only available for boards that have ext1 support.
.. function:: gpio_deep_sleep_hold(enable)
Configure whether non-RTC GPIO pin configuration is retained during
@@ -88,29 +80,6 @@ Functions
The result of :func:`gc.mem_free()` is the total of the current "free"
and "max new split" values printed by :func:`micropython.mem_info()`.
.. function:: idf_task_info()
Returns information about running ESP-IDF/FreeRTOS tasks, which include
MicroPython threads. This data is useful to gain insight into how much time
tasks spend running or if they are blocked for significant parts of time,
and to determine if allocated stacks are fully utilized or might be reduced.
``CONFIG_FREERTOS_USE_TRACE_FACILITY=y`` must be set in the board
configuration to make this method available. Additionally configuring
``CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y`` and
``CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y`` is recommended to be able to
retrieve the total and per-task runtime and the core ID respectively.
The return value is a 2-tuple where the first value is the total runtime,
and the second a list of tasks. Each task is a 7-tuple containing: the task
ID, name, current state, priority, runtime, stack high water mark, and the
ID of the core it is running on. Runtime and core ID will be None when the
respective FreeRTOS configuration option is not enabled.
.. note:: For an easier to use output based on this function you can use the
`utop library <https://github.com/micropython/micropython-lib/tree/master/micropython/utop>`_,
which implements a live overview similar to the Unix ``top`` command.
Flash partitions
----------------
@@ -195,151 +164,6 @@ Constants
Used in `idf_heap_info`.
.. _esp32.PCNT:
PCNT
----
This class provides access to the ESP32 hardware support for pulse counting.
There are 8 pulse counter units, with id 0..7.
See the :ref:`machine.Counter <machine.Counter>` and
:ref:`machine.Encoder <machine.Encoder>` classes for simpler and portable
abstractions of common pulse counting applications. These classes are
implemented as thin Python shims around :class:`PCNT`.
.. class:: PCNT(id, *, ...)
Returns the singleton PCNT instance for the given unit ``id``.
Keyword arguments are passed to the ``init()`` method as described
below.
.. method:: PCNT.init(*, ...)
(Re-)initialise a pulse counter unit. Supported keyword arguments are:
- ``channel``: see description below
- ``pin``: the input Pin to monitor for pulses
- ``rising``: an action to take on a rising edge - one of
``PCNT.INCREMENT``, ``PCNT.DECREMENT`` or ``PCNT.IGNORE`` (the default)
- ``falling``: an action to take on a falling edge (takes the save values
as the ``rising`` argument).
- ``mode_pin``: ESP32 pulse counters support monitoring a second pin and
altering the behaviour of the counter based on its level - set this
keyword to any input Pin
- ``mode_low``: set to either ``PCNT.HOLD`` or ``PCNT.REVERSE`` to
either suspend counting or reverse the direction of the counter (i.e.,
``PCNT.INCREMENT`` behaves as ``PCNT.DECREMENT`` and vice versa)
when ``mode_pin`` is low
- ``mode_high``: as ``mode_low`` but for the behaviour when ``mode_pin``
is high
- ``filter``: set to a value 1..1023, in ticks of the 80MHz clock, to
enable the pulse width filter
- ``min``: set to the minimum level of the counter value when
decrementing (-32768..-1) or 0 to disable
- ``max``: set to the maximum level of the counter value when
incrementing (1..32767) or 0 to disable
- ``threshold0``: sets the counter value for the
``PCNT.IRQ_THRESHOLD0`` event (see ``irq`` method)
- ``threshold1``: sets the counter value for the
``PCNT.IRQ_THRESHOLD1`` event (see ``irq`` method)
- ``value``: can be set to ``0`` to reset the counter value
The hardware initialisation is done in stages and so some of the keyword
arguments can be used in groups or in isolation to partially reconfigure a
unit:
- the ``pin`` keyword (optionally combined with ``mode_pin``) can be used
to change just the bound pin(s)
- ``rising``, ``falling``, ``mode_low`` and ``mode_high`` can be used
(singly or together) to change the counting logic - omitted keywords
use their default (``PCNT.IGNORE`` or ``PCNT.NORMAL``)
- ``filter`` can be used to change only the pulse width filter (with 0
disabling it)
- each of ``min``, ``max``, ``threshold0`` and ``threshold1`` can
be used to change these limit/event values individually; however,
setting any will reset the counter to zero (i.e., they imply
``value=0``)
Each pulse counter unit supports two channels, 0 and 1, each able to
monitor different pins with different counting logic but updating the same
counter value. Use ``channel=1`` with the ``pin``, ``rising``, ``falling``,
``mode_pin``, ``mode_low`` and ``mode_high`` keywords to configure the
second channel.
The second channel can be used to configure 4X quadrature decoding with a
single counter unit::
pin_a = Pin(2, Pin.INPUT, pull=Pin.PULL_UP)
pin_b = Pin(3, Pin.INPUT, pull=Pin.PULL_UP)
rotary = PCNT(0, min=-32000, max=32000)
rotary.init(channel=0, pin=pin_a, falling=PCNT.INCREMENT, rising=PCNT.DECREMENT, mode_pin=pin_b, mode_low=PCNT.REVERSE)
rotary.init(channel=1, pin=pin_b, falling=PCNT.DECREMENT, rising=PCNT.INCREMENT, mode_pin=pin_a, mode_low=PCNT.REVERSE)
rotary.start()
.. method:: PCNT.value([value])
Call this method with no arguments to return the current counter value.
If the optional *value* argument is set to ``0`` then the counter is
reset (but the previous value is returned). Read and reset is not atomic and
so it is possible for a pulse to be missed. Any value other than ``0`` will
raise an error.
.. method:: PCNT.irq(handler=None, trigger=PCNT.IRQ_ZERO)
ESP32 pulse counters support interrupts on these counter events:
- ``PCNT.IRQ_ZERO``: the counter has reset to zero
- ``PCNT.IRQ_MIN``: the counter has hit the ``min`` value
- ``PCNT.IRQ_MAX``: the counter has hit the ``max`` value
- ``PCNT.IRQ_THRESHOLD0``: the counter has hit the ``threshold0`` value
- ``PCNT.IRQ_THRESHOLD1``: the counter has hit the ``threshold1`` value
``trigger`` should be a bit-mask of the desired events OR'ed together. The
``handler`` function should take a single argument which is the
:class:`PCNT` instance that raised the event.
This method returns a callback object. The callback object can be used to
access the bit-mask of events that are outstanding on the PCNT unit.::
def pcnt_irq(pcnt):
flags = pcnt.irq().flags()
if flags & PCNT.IRQ_ZERO:
# reset
if flags & PCNT.IRQ_MAX:
# overflow...
... etc
pcnt.irq(handler=pcnt_irq, trigger=PCNT.IRQ_ZERO | PCNT.IRQ_MAX | ...)
**Note:** Accessing ``irq.flags()`` will clear the flags, so only call it
once per invocation of the handler.
The handler is called with the MicroPython scheduler and so will run at a
point after the interrupt. If another interrupt occurs before the handler
has been called then the events will be coalesced together into a single
call and the bit mask will indicate all events that have occurred.
To avoid race conditions between a handler being called and retrieving the
current counter value, the ``value()`` method will force execution of any
pending events before returning the current counter value (and potentially
resetting the value).
Only one handler can be in place per-unit. Set ``handler`` to ``None`` to
disable the event interrupt.
.. Note::
ESP32 pulse counters reset to *zero* when reaching the minimum or maximum
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
events occurs.
See the :ref:`machine.Counter <machine.Counter>` and
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
common pulse counting applications.
.. _esp32.RMT:
RMT

View File

@@ -137,18 +137,6 @@ Other methods
is compared to the value from *palette*, not to the value directly from
*fbuf*.)
*fbuf* can be another FrameBuffer instance, or a tuple or list of the form::
(buffer, width, height, format)
or::
(buffer, width, height, format, stride)
This matches the signature of the FrameBuffer constructor, and the elements
of the tuple/list are the same as the arguments to the constructor except that
the *buffer* here can be read-only.
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

View File

@@ -1,93 +0,0 @@
.. currentmodule:: machine
.. _machine.Counter:
class Counter -- pulse counter
==============================
Counter implements pulse counting by monitoring an input signal and counting
rising or falling edges.
Minimal example usage::
from machine import Pin, Counter
counter = Counter(0, Pin(0, Pin.IN)) # create Counter for pin 0 and begin counting
value = counter.value() # retrieve current pulse count
Availability: **ESP32**
Constructors
------------
.. class:: Counter(id, ...)
Returns the singleton Counter object for the the given *id*. Values of *id*
depend on a particular port and its hardware. Values 0, 1, etc. are commonly
used to select hardware block #0, #1, etc.
Additional arguments are passed to the :meth:`init` method described below,
and will cause the Counter instance to be re-initialised and reset.
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
Methods
-------
.. method:: Counter.init(src, *, ...)
Initialise and reset the Counter with the given parameters:
- *src* specifies the input pin as a :ref:`machine.Pin <machine.Pin>` object.
May be omitted on ports that have a predefined pin for a given hardware
block.
Additional keyword-only parameters that may be supported by a port are:
- *edge* specifies the edge to count. Either ``Counter.RISING`` (the default)
or ``Counter.FALLING``. *(Supported on ESP32)*
- *direction* specifies the direction to count. Either ``Counter.UP`` (the
default) or ``Counter.DOWN``. *(Supported on ESP32)*
- *filter_ns* specifies a minimum period of time in nanoseconds that the
source signal needs to be stable for a pulse to be counted. Implementations
should use the longest filter supported by the hardware that is less than
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
.. method:: Counter.deinit()
Stops the Counter, disabling any interrupts and releasing hardware resources.
A Soft Reset should deinitialize all Counter objects.
.. method:: Counter.value([value])
Get, and optionally set, the counter value as a signed integer.
Implementations must aim to do the get and set atomically (i.e. without
leading to skipped counts).
This counter value could exceed the range of a :term:`small integer`, which
means that calling :meth:`Counter.value` could cause a heap allocation, but
implementations should aim to ensure that internal state only uses small
integers and therefore will not allocate until the user calls
:meth:`Counter.value`.
For example, on ESP32, the internal state counts overflows of the hardware
counter (every 32000 counts), which means that it will not exceed the small
integer range until ``2**30 * 32000`` counts (slightly over 1 year at 1MHz).
In general, it is recommended that you should use ``Counter.value(0)`` to reset
the counter (i.e. to measure the counts since the last call), and this will
avoid this problem.
Constants
---------
.. data:: Counter.RISING
Counter.FALLING
Select the pulse edge.
.. data:: Counter.UP
Counter.DOWN
Select the counting direction.

View File

@@ -1,72 +0,0 @@
.. currentmodule:: machine
.. _machine.Encoder:
class Encoder -- quadrature decoding
====================================
Encoder implements decoding of quadrature signals as commonly output from
rotary encoders, by counting either up or down depending on the order of two
input pulses.
Minimal example usage::
from machine import Pin, Encoder
counter = Counter(0, Pin(0, Pin.IN), Pin(1, Pin.IN)) # create Encoder for pins 0, 1 and begin counting
value = counter.value() # retrieve current count
Availability: **ESP32**
Constructors
------------
.. class:: Encoder(id, ...)
Returns the singleton Encoder object for the the given *id*. Values of *id*
depend on a particular port and its hardware. Values 0, 1, etc. are commonly
used to select hardware block #0, #1, etc.
Additional arguments are passed to the :meth:`init` method described below,
and will cause the Encoder instance to be re-initialised and reset.
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
Methods
-------
.. method:: Encoder.init(phase_a, phase_b, *, ...)
Initialise and reset the Encoder with the given parameters:
- *phase_a* specifies the first input pin as a
:ref:`machine.Pin <machine.Pin>` object.
- *phase_b* specifies the second input pin as a
:ref:`machine.Pin <machine.Pin>` object.
These pins may be omitted on ports that have predefined pins for a given
hardware block.
Additional keyword-only parameters that may be supported by a port are:
- *filter_ns* specifies a minimum period of time in nanoseconds that the
source signal needs to be stable for a pulse to be counted. Implementations
should use the longest filter supported by the hardware that is less than
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
- *phases* specifies the number of signal edges to count and thus the
granularity of the decoding. e.g. 4 phases corresponds to "4x quadrature
decoding", and will result in four counts per pulse. Ports may support
either 1, 2, or 4 phases and the default is 1 phase. *(Supported on ESP32)*
.. method:: Encoder.deinit()
Stops the Encoder, disabling any interrupts and releasing hardware resources.
A Soft Reset should deinitialize all Encoder objects.
.. method:: Encoder.value([value])
Get, and optionally set, the encoder value as a signed integer.
Implementations should aim to do the get and set atomically.
See :meth:`machine.Counter.value` for details about overflow of this value.

View File

@@ -1,174 +0,0 @@
.. currentmodule:: machine
.. _machine.I2CTarget:
class I2CTarget -- an I2C target device
=======================================
An I2C target is a device which connects to an I2C bus and is controlled by an
I2C controller. I2C targets can take many forms. The :class:`machine.I2CTarget`
class implements an I2C target that can be configured as a memory/register device,
or as an arbitrary I2C device by using callbacks (if supported by the port).
Example usage for the case of a memory device::
from machine import I2CTarget
# Create the backing memory for the I2C target.
mem = bytearray(8)
# Create an I2C target. Depending on the port, extra parameters
# may be required to select the peripheral and/or pins to use.
i2c = I2CTarget(addr=67, mem=mem)
# At this point an I2C controller can read and write `mem`.
...
# Deinitialise the I2C target.
i2c.deinit()
Note that some ports require an ``id``, and maybe ``scl`` and ``sda`` pins, to be
passed to the `I2CTarget` constructor, to select the hardware I2C instance and
pins that it connects to.
When configured as a memory device, it's also possible to register to receive events.
For example to be notified when the memory is read/written::
from machine import I2CTarget
# Define an IRQ handler, for I2C events.
def irq_handler(i2c_target):
flags = i2c_target.irq().flags()
if flags & I2CTarget.IRQ_END_READ:
print("controller read target at addr", i2c_target.memaddr)
if flags & I2CTarget.IRQ_END_WRITE:
print("controller wrote target at addr", i2c_target.memaddr)
# Create the I2C target and register to receive default events.
mem = bytearray(8)
i2c = I2CTarget(addr=67, mem=mem)
i2c.irq(irq_handler)
More complicated I2C devices can be implemented using the full set of events. For
example, to see the raw events as they are triggered::
from machine import I2CTarget
# Define an IRQ handler that prints the event id and responds to reads/writes.
def irq_handler(i2c_target, buf=bytearray(1)):
flags = i2c_target.irq().flags()
print(flags)
if flags & I2CTarget.IRQ_READ_REQ:
i2c_target.write(buf)
if flags & I2CTarget.IRQ_WRITE_REQ:
i2c_target.readinto(buf)
# Create the I2C target and register to receive all events.
i2c = I2CTarget(addr=67)
all_triggers = (
I2CTarget.IRQ_ADDR_MATCH_READ
| I2CTarget.IRQ_ADDR_MATCH_WRITE
| I2CTarget.IRQ_READ_REQ
| I2CTarget.IRQ_WRITE_REQ
| I2CTarget.IRQ_END_READ
| I2CTarget.IRQ_END_WRITE
)
i2c.irq(irq_handler, trigger=all_triggers, hard=True)
Constructors
------------
.. class:: I2CTarget(id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None)
Construct and return a new I2CTarget object using the following parameters:
- *id* identifies a particular I2C peripheral. Allowed values depend on the
particular port/board. Some ports have a default in which case this parameter
can be omitted.
- *addr* is the I2C address of the target.
- *addrsize* is the number of bits in the I2C target address. Valid values
are 7 and 10.
- *mem* is an object with the buffer protocol that is writable. If not
specified then there is no backing memory and data must be read/written
using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods.
- *mem_addrsize* is the number of bits in the memory address. Valid values
are 0, 8, 16, 24 and 32.
- *scl* is a pin object specifying the pin to use for SCL.
- *sda* is a pin object specifying the pin to use for SDA.
Note that some ports/boards will have default values of *scl* and *sda*
that can be changed in this constructor. Others will have fixed values
of *scl* and *sda* that cannot be changed.
General Methods
---------------
.. method:: I2CTarget.deinit()
Deinitialise the I2C target. After this method is called the hardware will no
longer respond to requests on the I2C bus, and no other methods can be called.
.. method:: I2CTarget.readinto(buf)
Read into the given buffer any pending bytes written by the I2C controller.
Returns the number of bytes read.
.. method:: I2CTarget.write(buf)
Write out the bytes from the given buffer, to be passed to the I2C controller
after it sends a read request. Returns the number of bytes written. Most ports
only accept one byte at a time to this method.
.. method:: I2CTarget.irq(handler=None, trigger=IRQ_END_READ|IRQ_END_WRITE, hard=False)
Configure an IRQ *handler* to be called when an event occurs. The possible events are
given by the following constants, which can be or'd together and passed to the *trigger*
argument:
- ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a
controller for a read transaction.
- ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a
controller for a write transaction.
- ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this
request must be satisfied by calling `I2CTarget.write` with the data to be
passed back to the controller.
- ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the
data must be read by calling `I2CTarget.readinto`.
- ``IRQ_END_READ`` indicates that the controller has finished a read transaction.
- ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction.
Not all triggers are available on all ports. If a port has the constant then that
event is available.
Note the following restrictions:
- ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and
``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument
set to ``True``). This is because these events have very strict timing requirements
and must usually be satisfied synchronously with the hardware event.
- ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard
IRQ callback (although note that all events must be registered with the same handler,
so if any events need a hard callback then all events must be hard).
- If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE``
is not emitted for the transaction that writes the memory address. This is to
allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ
callbacks, where the IRQ handler may be called quite some time after the actual
hardware event.
.. attribute:: I2CTarget.memaddr
The integer value of the most recent memory address that was selected by the I2C
controller (only valid if ``mem`` was specified in the constructor).
Constants
---------
.. data:: I2CTarget.IRQ_ADDR_MATCH_READ
I2CTarget.IRQ_ADDR_MATCH_WRITE
I2CTarget.IRQ_READ_REQ
I2CTarget.IRQ_WRITE_REQ
I2CTarget.IRQ_END_READ
I2CTarget.IRQ_END_WRITE
IRQ trigger sources.

View File

@@ -11,20 +11,20 @@ Example usage::
from machine import PWM
pwm = PWM(pin, freq=50, duty_u16=8192) # create a PWM object on a pin
# and set freq 50 Hz and duty 12.5%
pwm.duty_u16(32768) # set duty to 50%
# and set freq and duty
pwm.duty_u16(32768) # set duty to 50%
# reinitialise with a period of 200us, duty of 5us
pwm.init(freq=5000, duty_ns=5000)
pwm.duty_ns(3000) # set pulse width to 3us
pwm.duty_ns(3000) # set pulse width to 3us
pwm.deinit()
Constructors
------------
.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert=False)
.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert)
Construct and return a new PWM object using the following parameters:
@@ -40,7 +40,7 @@ Constructors
Setting *freq* may affect other PWM objects if the objects share the same
underlying PWM generator (this is hardware specific).
Only one of *duty_u16* and *duty_ns* should be specified at a time.
*invert* is available only on the esp32, mimxrt, nrf, rp2, samd and zephyr ports.
*invert* is not available at all ports.
Methods
-------
@@ -116,10 +116,10 @@ Limitations of PWM
resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest
8 bits of *duty_u16* are insignificant. So::
pwm=PWM(Pin(13), freq=300_000, duty_u16=65536//2)
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2)
and::
pwm=PWM(Pin(13), freq=300_000, duty_u16=65536//2 + 255)
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255)
will generate PWM with the same 50% duty cycle.

View File

@@ -224,8 +224,7 @@ Methods
.. note::
- The ESP32 port does not support the option hard=True. It uses Timer(0)
for UART.IRQ_RXIDLE, so this timer cannot be used for other means.
- The ESP32 port does not support the option hard=True.
- The rp2 port's UART.IRQ_TXIDLE is only triggered when the message
is longer than 5 characters and the trigger happens when still 5 characters

View File

@@ -264,12 +264,9 @@ Classes
machine.UART.rst
machine.SPI.rst
machine.I2C.rst
machine.I2CTarget.rst
machine.I2S.rst
machine.RTC.rst
machine.Timer.rst
machine.Counter.rst
machine.Encoder.rst
machine.WDT.rst
machine.SD.rst
machine.SDCard.rst

View File

@@ -58,11 +58,6 @@ Methods
- *pull_thresh* is the threshold in bits before auto-pull or conditional
re-pulling is triggered.
Note: pins used for *in_base* need to be configured manually for input (or
otherwise) so that the PIO can see the desired signal (they could be input
pins, output pins, or connected to a different peripheral). The *jmp_pin*
can also be configured manually, but by default will be an input pin.
.. method:: StateMachine.active([value])
Gets or sets whether the state machine is currently running.

View File

@@ -227,28 +227,22 @@ Methods
has the same "no short writes" policy for blocking sockets, and will return
number of bytes sent on non-blocking sockets.
.. method:: socket.recv(bufsize, [flags])
.. method:: socket.recv(bufsize)
Receive data from the socket. The return value is a bytes object representing the data
received. The maximum amount of data to be received at once is specified by bufsize.
Most ports support the optional *flags* argument. Available *flags* are defined as constants
in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT``
are supported on all ports which accept the *flags* argument.
.. method:: socket.sendto(bytes, address)
Send data to the socket. The socket should not be connected to a remote socket, since the
destination socket is specified by *address*.
.. method:: socket.recvfrom(bufsize, [flags])
.. method:: socket.recvfrom(bufsize)
Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a
bytes object representing the data received and *address* is the address of the socket sending
the data.
See the `recv` function for an explanation of the optional *flags* argument.
.. method:: socket.setsockopt(level, optname, value)
Set the value of the given socket option. The needed symbolic constants are defined in the

View File

@@ -66,7 +66,7 @@ class SSLContext
Set the available ciphers for sockets created with this context. *ciphers* should be
a list of strings in the `IANA cipher suite format <https://wiki.mozilla.org/Security/Cipher_Suites>`_ .
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None, client_id=None)
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None)
Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, wrapping the underlying stream.
@@ -89,9 +89,6 @@ class SSLContext
server certificate. It also sets the name for Server Name Indication (SNI), allowing the server
to present the proper certificate.
- *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS
Server. See :ref:`dtls` for details.
.. warning::
Some implementations of ``ssl`` module do NOT validate server certificates,
@@ -120,8 +117,6 @@ Exceptions
This exception does NOT exist. Instead its base class, OSError, is used.
.. _dtls:
DTLS support
------------
@@ -130,47 +125,16 @@ DTLS support
This is a MicroPython extension.
On most ports, this module supports DTLS in client and server mode via the
`PROTOCOL_DTLS_CLIENT` and `PROTOCOL_DTLS_SERVER` constants that can be used as
the ``protocol`` argument of `SSLContext`.
This module supports DTLS in client and server mode via the `PROTOCOL_DTLS_CLIENT`
and `PROTOCOL_DTLS_SERVER` constants that can be used as the ``protocol`` argument
of `SSLContext`.
In this case the underlying socket is expected to behave as a datagram socket (i.e.
like the socket opened with ``socket.socket`` with ``socket.AF_INET`` as ``af`` and
``socket.SOCK_DGRAM`` as ``type``).
DTLS is only supported on ports that use mbedTLS, and it is enabled by default
in most configurations but can be manually disabled by defining
``MICROPY_PY_SSL_DTLS`` to 0.
DTLS server support
^^^^^^^^^^^^^^^^^^^
MicroPython's DTLS server support is configured with "Hello Verify" as required
for DTLS 1.2. This is transparent for DTLS clients, but there are relevant
considerations when implementing a DTLS server in MicroPython:
- The server should pass an additional argument *client_id* when calling
`SSLContext.wrap_socket()`. This ID must be a `bytes` object (or similar) with
a transport-specific identifier representing the client.
The simplest approach is to convert the tuple of ``(client_ip, client_port)``
returned from ``socket.recv_from()`` into a byte string, i.e.::
_, client_addr = sock.recvfrom(1, socket.MSG_PEEK)
sock.connect(client_addr) # Connect back to the client
sock = ssl_ctx.wrap_socket(sock, server_side=True,
client_id=repr(client_addr).encode())
- The first time a client connects, the server call to ``wrap_socket`` will fail
with a `OSError` error "Hello Verify Required". This is because the DTLS
"Hello Verify" cookie is not yet known by the client. If the same client
connects a second time then ``wrap_socket`` will succeed.
- DTLS cookies for "Hello Verify" are associated with the `SSLContext` object,
so the same `SSLContext` object should be used to wrap a subsequent connection
from the same client. The cookie implementation includes a timeout and has
constant memory use regardless of how many clients connect, so it's OK to
reuse the same `SSLContext` object for the lifetime of the server.
DTLS is only supported on ports that use mbed TLS, and it is not enabled by default:
it requires enabling ``MBEDTLS_SSL_PROTO_DTLS`` in the specific port configuration.
Constants
---------

View File

@@ -77,8 +77,6 @@ Constants
* *_mpy* - supported mpy file-format version (optional attribute)
* *_build* - string that can help identify the configuration that
MicroPython was built with
* *_thread* - optional string attribute, exists if the target has threading
and is either "GIL" or "unsafe"
This object is the recommended way to distinguish MicroPython from other
Python implementations (note that it still may not exist in the very
@@ -97,14 +95,6 @@ Constants
* On microcontroller targets, the first element is the board name and the second
element (if present) is the board variant, for example ``'RPI_PICO2-RISCV'``
The *_thread* entry was added in version 1.26.0 and if it exists then the
target has the ``_thread`` module. If the target enables the GIL (global
interpreter lock) then this attribute is ``"GIL"``. Otherwise the attribute
is ``"unsafe"`` and the target has threading but does not enable the GIL,
and mutable Python objects (such as `bytearray`, `list` and `dict`) that are
shared amongst threads must be protected explicitly by locks such as
``_thread.allocate_lock``.
.. admonition:: Difference to CPython
:class: attention

View File

@@ -9,10 +9,9 @@
The ``time`` module provides functions for getting the current time and date,
measuring time intervals, and for delays.
**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports
use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC.
The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC.
Epoch year may be determined with ``gmtime(0)[0]``.
**Time Epoch**: Unix port uses standard for POSIX systems epoch of
1970-01-01 00:00:00 UTC. However, some embedded ports use epoch of
2000-01-01 00:00:00 UTC. Epoch year may be determined with ``gmtime(0)[0]``.
**Maintaining actual calendar date/time**: This requires a
Real Time Clock (RTC). On systems with underlying OS (including some
@@ -58,11 +57,11 @@ Functions
* weekday is 0-6 for Mon-Sun
* yearday is 1-366
.. function:: mktime(date_time_tuple)
.. function:: mktime()
This is inverse function of localtime. It's argument is a full 8-tuple
which expresses a time as per localtime. It returns an integer which is
the number of seconds since the time epoch.
the number of seconds since Jan 1, 2000.
.. function:: sleep(seconds)

View File

@@ -358,13 +358,13 @@ Run WM8960 on a MIMXRT10xx_DEV board in secondary mode (default)::
sysclk_source=wm8960.SYSCLK_MCLK)
Record with a SparkFun WM8960 breakout board with Teensy in secondary mode (default)::
Record with a Sparkfun WM8960 breakout board with Teensy in secondary mode (default)::
# Micro_python WM8960 Codec driver
#
# The breakout board uses a fixed 24MHz MCLK. Therefore the internal
# PLL must be used as sysclk, which is the master audio clock.
# The SparkFun board has the WS pins for RX and TX connected on the
# The Sparkfun board has the WS pins for RX and TX connected on the
# board. Therefore adc_sync must be set to sync_adc, to configure
# it's ADCLRC pin as input.
#
@@ -379,11 +379,11 @@ Record with a SparkFun WM8960 breakout board with Teensy in secondary mode (defa
right_input=wm8960.INPUT_CLOSED)
Play with a SparkFun WM8960 breakout board with Teensy in secondary mode (default)::
Play with a Sparkfun WM8960 breakout board with Teensy in secondary mode (default)::
# The breakout board uses a fixed 24MHz MCLK. Therefore the internal
# PLL must be used as sysclk, which is the master audio clock.
# The SparkFun board has the WS pins for RX and TX connected on the
# The Sparkfun board has the WS pins for RX and TX connected on the
# board. Therefore adc_sync must be set to sync_adc, to configure
# it's ADCLRC pin as input.

View File

@@ -22,10 +22,9 @@ Functions
Returns the thread id of the current thread, which is used to reference the thread.
.. function:: thread_analyze(cpu)
.. function:: thread_analyze()
Runs the Zephyr debug thread analyzer on the current thread on the given cpu
and prints stack size statistics in the format:
Runs the Zephyr debug thread analyzer on the current thread and prints stack size statistics in the format:
"``thread_name``-20s: STACK: unused ``available_stack_space`` usage ``stack_space_used``
/ ``stack_size`` (``percent_stack_space_used`` %); CPU: ``cpu_utilization`` %"
@@ -36,9 +35,6 @@ Functions
For more information, see documentation for Zephyr `thread analyzer
<https://docs.zephyrproject.org/latest/guides/debug_tools/thread-analyzer.html#thread-analyzer>`_.
Note that the ``cpu`` argument is only used in Zephyr v4.0.0 and
newer and ignored otherwise.
.. function:: shell_exec(cmd_in)
Executes the given command on an UART backend. This function can only be accessed if ``CONFIG_SHELL_BACKEND_SERIAL``

View File

@@ -188,13 +188,6 @@ Glossary
Most MicroPython boards make a REPL available over a UART, and this is
typically accessible on a host PC via USB.
small integer
MicroPython optimises the internal representation of integers such that
"small" values do not take up space on the heap, and calculations with
them do not require heap allocation. On most 32-bit ports, this
corresponds to values in the interval ``-2**30 <= x < 2**30``, but this
should be considered an implementation detail and not relied upon.
stream
Also known as a "file-like object". A Python object which provides
sequential read-write access to the underlying data. A stream object

View File

@@ -108,7 +108,7 @@ The full list of supported commands are:
**Note:** Instead of using the ``connect`` command, there are several
:ref:`pre-defined shortcuts <mpremote_shortcuts>` for common device paths. For
example the ``a0`` shortcut command is equivalent to
``connect /dev/ttyACM0`` (Linux), or ``c1`` for ``COM1`` (Windows).
``connect /dev/ttyACM0`` (Linux), or ``c0`` for ``COM0`` (Windows).
**Note:** The ``auto`` option will only detect USB serial ports, i.e. a serial
port that has an associated USB VID/PID (i.e. CDC/ACM or FTDI-style
@@ -234,7 +234,6 @@ The full list of supported commands are:
- ``rmdir <dirs...>`` to remove directories on the device
- ``touch <file..>`` to create the files (if they don't already exist)
- ``sha256sum <file..>`` to calculate the SHA256 sum of files
- ``tree [-vsh] <dirs...>`` to print a tree of the given directories
The ``cp`` command uses a convention where a leading ``:`` represents a remote
path. Without a leading ``:`` means a local path. This is based on the
@@ -265,13 +264,6 @@ The full list of supported commands are:
There is no supported way to undelete files removed by ``mpremote rm -r :``.
Please use with caution.
The ``tree`` command will print a tree of the given directories.
Using the ``--size/-s`` option will print the size of each file, or use
``--human/-h`` to use a more human readable format.
Note: Directory size is only printed when a non-zero size is reported by the device's filesystem.
The ``-v`` option can be used to include the name of the serial device in
the output.
All other commands implicitly assume the path is a remote path, but the ``:``
can be optionally used for clarity.
@@ -487,16 +479,9 @@ Shortcuts can be defined using the macro system. Built-in shortcuts are:
- ``cat``, ``edit``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``touch``: Aliases for ``fs <sub-command>``
Additional shortcuts can be defined in the user configuration file ``mpremote/config.py``,
located in the User Configuration Directory.
The correct location for each OS is determined using the ``platformdirs`` module.
This is typically:
- ``$XDG_CONFIG_HOME/mpremote/config.py``
- ``$HOME/.config/mpremote/config.py``
- ``$env:LOCALAPPDATA/mpremote/config.py``
The ``config.py``` file should define a dictionary named ``commands``. The keys of this dictionary are the shortcuts
Additional shortcuts can be defined by in user-configuration files, which is
located at ``.config/mpremote/config.py``. This file should define a
dictionary named ``commands``. The keys of this dictionary are the shortcuts
and the values are either a string or a list-of-strings:
.. code-block:: python3

View File

@@ -246,13 +246,6 @@ There are certain limitations in the current implementation of the native code e
* Context managers are not supported (the ``with`` statement).
* Generators are not supported.
* If ``raise`` is used an argument must be supplied.
* The background scheduler (see `micropython.schedule`) is not run during
execution of native code.
* On targets with thrteading and the GIL, the GIL is not released during
execution of native code.
To mitigate the last two points, long running native functions should call
``time.sleep(0)`` periodically, which will run the scheduler and bounce the GIL.
The trade-off for the improved performance (roughly twice as fast as bytecode) is an
increase in compiled code size.

View File

@@ -135,12 +135,6 @@ Use the :mod:`machine.Timer` class::
tim = Timer(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
By default, timer callbacks run as soft IRQs so they can allocate but
are prone to GC jitter and delays. Pass ``hard=True`` to the ``Timer()``
constructor or ``init()`` method to run the callback in hard-IRQ context
instead. This reduces delay and jitter, but see :ref:`isr_rules` for the
restrictions that apply to hard-IRQ handlers.
.. _rp2_Pins_and_GPIO:

View File

@@ -650,124 +650,6 @@ Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
The board does not provide access to UART, I2C, SPI or DAC.
SparkFun Redboard Turbo assignment table
----------------------------------------
=== ==== ============ ==== ==== ====== ====== ====== ======
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
=== ==== ============ ==== ==== ====== ====== ====== ======
2 PA02 A0 2 0 - - - -
40 PB08 A1 8 2 - 4/0 4/0 -
41 PB09 A2 9 3 - 4/1 4/1 -
4 PA04 A3 4 4 - 0/0 0/0 -
5 PA05 A4 5 5 - 0/1 0/1 -
34 PB02 A5 2 10 - 5/0 6/0 -
11 PA11 D0 11 19 0/3 2/3 1/1 0/3
10 PA10 D1 10 18 0/2 2/2 1/0 0/2
14 PA14 D2 14 - 2/2 4/2 3/0 0/4
9 PA09 D3 9 17 0/1 2/1 0/1 1/3
8 PA08 D4 - 16 0/0 2/0 0/0 1/2
15 PA15 D5 15 - 2/3 4/3 3/1 0/5
20 PA20 D6 4 - 5/2 3/2 7/0 0/4
21 PA21 D7 5 - 5/3 3/3 7/1 0/7
6 PA06 D8 6 6 - 0/2 1/0 -
7 PA07 D9 7 7 - 0/3 1/1 -
11 PA11 RX 11 19 0/3 2/3 1/1 0/3
10 PA10 TX 10 18 0/2 2/2 1/0 0/2
3 PA03 AREF 3 1 - - - -
18 PA18 D10 2 - 1/2 3/2 3/0 0/2
16 PA16 D11 0 - 1/0 3/0 2/0 0/6
19 PA19 D12 3 - 1/3 3/3 3/1 0/3
17 PA17 D13 1 - 1/1 3/1 2/1 0/7
13 PA13 FLASH_CS 13 - 2/1 4/1 2/0 0/7
35 PB03 FLASH_MISO 3 11 - 5/1 6/1 -
54 PB22 FLASH_MOSI 6 - - 5/2 7/0 -
55 PB23 FLASH_SCK 7 - - 5/3 7/1 -
31 PA31 LED_RX 11 - - 1/3 1/1 -
27 PA27 LED_TX 15 - - - - -
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
42 PB10 MOSI 10 - - 4/2 5/0 0/4
30 PA30 NEOPIXEL 10 - - 1/2 1/0 -
43 PB11 SCK 11 - - 4/3 5/1 0/5
23 PA23 SCL 7 - 3/1 5/1 4/1 0/5
22 PA22 SDA 6 - 3/0 5/0 4/0 0/4
30 PA30 SWCLK 10 - - 1/2 1/0 -
31 PA31 SWDIO 11 - - 1/3 1/1 -
24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2
25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3
0 PA00 0 - - 1/0 2/0 -
1 PA01 1 - - 1/1 2/1 -
28 PA28 8 - - - - -
=== ==== ============ ==== ==== ====== ====== ====== ======
For the definition of the table columns see the explanation at the table for
Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
The default devices at the board are:
- UART 0 at pins PA11/PA10, labelled RX/TX
- I2C 3 at pins PA22/PA23, labelled SDA/SCL
- SPI 4 at pins PB10/PA12/PB11, labelled MISO, MOSI and SCK
- DAC output on pin PA02, labelled A0
SparkFun SAMD21 Dev Breakout assignment table
---------------------------------------------
=== ==== ============ ==== ==== ====== ====== ====== ======
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
=== ==== ============ ==== ==== ====== ====== ====== ======
2 PA02 A0 2 0 - - - -
40 PB08 A1 8 2 - 4/0 4/0 -
41 PB09 A2 9 3 - 4/1 4/1 -
4 PA04 A3 4 4 - 0/0 0/0 -
5 PA05 A4 5 5 - 0/1 0/1 -
34 PB02 A5 2 10 - 5/0 6/0 -
11 PA11 D0 11 19 0/3 2/3 1/1 0/3
10 PA10 D1 10 18 0/2 2/2 1/0 0/2
14 PA14 D2 14 - 2/2 4/2 3/0 0/4
9 PA09 D3 9 17 0/1 2/1 0/1 1/3
8 PA08 D4 - 16 0/0 2/0 0/0 1/2
15 PA15 D5 15 - 2/3 4/3 3/1 0/5
20 PA20 D6 4 - 5/2 3/2 7/0 0/4
21 PA21 D7 5 - 5/3 3/3 7/1 0/7
6 PA06 D8 6 6 - 0/2 1/0 -
7 PA07 D9 7 7 - 0/3 1/1 -
11 PA11 RX 11 19 0/3 2/3 1/1 0/3
10 PA10 TX 10 18 0/2 2/2 1/0 0/2
3 PA03 AREF 3 1 - - - -
18 PA18 D10 2 - 1/2 3/2 3/0 0/2
16 PA16 D11 0 - 1/0 3/0 2/0 0/6
19 PA19 D12 3 - 1/3 3/3 3/1 0/3
17 PA17 D13 1 - 1/1 3/1 2/1 0/7
54 PB22 D30 6 - - 5/2 7/0 -
55 PB23 D31 7 - - 5/3 7/1 -
13 PA13 D38 13 - 2/1 4/1 2/0 0/7
35 PB03 LED_RX 3 11 - 5/1 6/1 -
27 PA27 LED_TX 15 - - - - -
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
42 PB10 MOSI 10 - - 4/2 5/0 0/4
43 PB11 SCK 11 - - 4/3 5/1 0/5
23 PA23 SCL 7 - 3/1 5/1 4/1 0/5
22 PA22 SDA 6 - 3/0 5/0 4/0 0/4
30 PA30 SWCLK 10 - - 1/2 1/0 -
31 PA31 SWDIO 11 - - 1/3 1/1 -
24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2
25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3
0 PA00 0 - - 1/0 2/0 -
1 PA01 1 - - 1/1 2/1 -
28 PA28 8 - - - - -
=== ==== ============ ==== ==== ====== ====== ====== ======
For the definition of the table columns see the explanation at the table for
Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
The default devices at the board are:
- UART 0 at pins PA11/PA10, labelled RX/TX
- I2C 3 at pins PA22/PA23, labelled SDA/SCL
- SPI 4 at pins PB10/PA12/PB11, labelled MISO, MOSI and SCK
- DAC output on pin PA02, labelled A0
SAMD21 Xplained PRO pin assignment table
----------------------------------------
@@ -1010,7 +892,7 @@ Default pin assignments:
There seems to be no default pin assignment for this board.
SparkFun SAMD51 Thing Plus pin assignment table
Sparkfun SAMD51 Thing Plus pin assignment table
------------------------------------------------
=== ==== ============ ==== ==== ==== ====== ====== ===== ===== =====

View File

@@ -56,21 +56,6 @@ Use the :ref:`machine.Pin <machine.Pin>` class::
switch = Pin(("gpioc", 6), Pin.IN) # create input pin for a switch
switch.irq(lambda t: print("SW2 changed")) # enable an interrupt when switch state is changed
PWM
---
Use the :ref:`machine.PWM <machine.PWM>` class::
from machine import PWM
pwm = PWM(("pwm0", 0), freq=3921568, duty_ns=200, invert=True) # create pwm on PWM0
print(pwm) # print pwm
print(pwm.duty_ns()) # print pwm duty cycle in nanoseconds
pwm.duty_ns(255) # set new pwm duty cycle in nanoseconds
pwm.deinit()
Hardware I2C bus
----------------
@@ -153,8 +138,6 @@ Use the :ref:`zephyr.FlashArea <zephyr.FlashArea>` class to support filesystem::
f.write('Hello world') # write to the file
print(open('/flash/hello.txt').read()) # print contents of the file
The FlashAreas' IDs that are available are listed in the FlashArea module, as ID_*.
Sensor
------

View File

@@ -31,7 +31,7 @@ With your serial program open (PuTTY, screen, picocom, etc) you may see a
blank screen with a flashing cursor. Press Enter (or reset the board) and
you should be presented with the following text::
*** Booting Zephyr OS build v4.0.0 ***
*** Booting Zephyr OS build v3.7.0 ***
MicroPython v1.24.0-preview.179.g5b85b24bd on 2024-08-05; zephyr-frdm_k64f with mk64f12
Type "help()" for more information.
>>>

View File

@@ -46,7 +46,6 @@ typedef struct _mp_qspi_proto_t {
int (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
int (*read_cmd)(void *self, uint8_t cmd, size_t len, uint32_t *dest);
int (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, uint8_t num_dummy, size_t len, uint8_t *dest);
int (*direct_read)(void *self, uint32_t addr, size_t len, uint8_t *dest); // can be NULL if direct read not supported
} mp_qspi_proto_t;
typedef struct _mp_soft_qspi_obj_t {

17
drivers/cyw43/README.md Normal file
View File

@@ -0,0 +1,17 @@
CYW43xx WiFi SoC driver
=======================
This is a driver for the CYW43xx WiFi SoC.
There are four layers to the driver:
1. SDIO bus interface, provided by the host device/system.
2. Low-level CYW43xx interface, managing the bus, control messages, Ethernet
frames and asynchronous events. Includes download of SoC firmware. The
header file `cyw43_ll.h` defines the interface to this layer.
3. Mid-level CYW43xx control, to control and set WiFi parameters and manage
events. See `cyw43_ctrl.c`.
4. TCP/IP bindings to lwIP. See `cyw43_lwip.c`.

304
drivers/cyw43/cywbt.c Normal file
View File

@@ -0,0 +1,304 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 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/mphal.h"
#include "extmod/mpbthci.h"
#if MICROPY_PY_NETWORK_CYW43
#include "lib/cyw43-driver/src/cyw43_config.h"
#include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h"
// Provided by the port, and also possibly shared with the stack.
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
/******************************************************************************/
// CYW BT HCI low-level driver
#ifdef CYW43_PIN_BT_CTS
// This code is not portable and currently only builds on stm32 port.
#include "pin_static_af.h"
#include "uart.h"
// Provided by the port.
extern machine_uart_obj_t mp_bluetooth_hci_uart_obj;
static void cywbt_wait_cts_low(void) {
mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
for (int i = 0; i < 200; ++i) {
if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) {
break;
}
mp_hal_delay_ms(1);
}
mp_hal_pin_config_alt(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_ALT,
MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id);
}
#endif
static int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
mp_bluetooth_hci_uart_write((void *)buf, len);
for (int c, i = 0; i < 6; ++i) {
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
mp_event_wait_indefinite();
}
buf[i] = c;
}
// expect a command complete event (event 0x0e)
if (buf[0] != 0x04 || buf[1] != 0x0e) {
printf("unknown response: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
return -1;
}
/*
if buf[3:6] != cmd[:3]:
print('response doesn\'t match cmd:', cmd, ev)
return b''
*/
int sz = buf[2] - 3;
for (int c, i = 0; i < sz; ++i) {
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
mp_event_wait_indefinite();
}
buf[i] = c;
}
return 0;
}
static int cywbt_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
buf[0] = 0x01;
buf[1] = ocf;
buf[2] = ogf << 2 | ocf >> 8;
buf[3] = param_len;
if (param_len) {
memcpy(buf + 4, param_buf, param_len);
}
return cywbt_hci_cmd_raw(4 + param_len, buf);
}
static void put_le16(uint8_t *buf, uint16_t val) {
buf[0] = val;
buf[1] = val >> 8;
}
static void put_le32(uint8_t *buf, uint32_t val) {
buf[0] = val;
buf[1] = val >> 8;
buf[2] = val >> 16;
buf[3] = val >> 24;
}
static int cywbt_set_baudrate(uint32_t baudrate) {
uint8_t buf[6];
put_le16(buf, 0);
put_le32(buf + 2, baudrate);
return cywbt_hci_cmd(0x3f, 0x18, 6, buf);
}
// download firmware
static int cywbt_download_firmware(const uint8_t *firmware) {
cywbt_hci_cmd(0x3f, 0x2e, 0, NULL);
bool last_packet = false;
while (!last_packet) {
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
memcpy(buf + 1, firmware, 3);
firmware += 3;
last_packet = buf[1] == 0x4e;
if (buf[2] != 0xfc) {
printf("fail1 %02x\n", buf[2]);
break;
}
uint8_t len = buf[3];
memcpy(buf + 4, firmware, len);
firmware += len;
buf[0] = 1;
cywbt_hci_cmd_raw(4 + len, buf);
if (buf[0] != 0) {
printf("fail3 %02x\n", buf[0]);
break;
}
}
// RF switch must select high path during BT patch boot
#if MICROPY_HW_ENABLE_RF_SWITCH
mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
#endif
mp_hal_delay_ms(10); // give some time for CTS to go high
#ifdef CYW43_PIN_BT_CTS
cywbt_wait_cts_low();
#endif
#if MICROPY_HW_ENABLE_RF_SWITCH
// Select chip antenna (could also select external)
mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0);
#endif
mp_bluetooth_hci_uart_set_baudrate(115200);
cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
return 0;
}
int mp_bluetooth_hci_controller_init(void) {
// This is called immediately after the UART is initialised during stack initialisation.
mp_hal_pin_output(CYW43_PIN_BT_REG_ON);
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
#ifdef CYW43_PIN_BT_HOST_WAKE
mp_hal_pin_input(CYW43_PIN_BT_HOST_WAKE);
#endif
#ifdef CYW43_PIN_BT_DEV_WAKE
mp_hal_pin_output(CYW43_PIN_BT_DEV_WAKE);
mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE);
#endif
#if MICROPY_HW_ENABLE_RF_SWITCH
// TODO don't select antenna if wifi is enabled
mp_hal_pin_config(CYW43_PIN_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
mp_hal_pin_high(CYW43_PIN_WL_GPIO_4); // Turn the RF-switch on
#endif
uint8_t buf[256];
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
mp_bluetooth_hci_uart_set_baudrate(115200);
mp_hal_delay_ms(100);
mp_hal_pin_high(CYW43_PIN_BT_REG_ON);
#ifdef CYW43_PIN_BT_CTS
cywbt_wait_cts_low();
#else
mp_hal_delay_ms(100);
#endif
// Reset
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
#ifdef MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE
// Change baudrate
cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
#endif
cywbt_download_firmware((const uint8_t *)&cyw43_btfw_4343A1[0]);
// Reset
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
// Set BD_ADDR (sent as little endian)
uint8_t bdaddr[6];
mp_hal_get_mac(MP_HAL_MAC_BDADDR, bdaddr);
buf[0] = bdaddr[5];
buf[1] = bdaddr[4];
buf[2] = bdaddr[3];
buf[3] = bdaddr[2];
buf[4] = bdaddr[1];
buf[5] = bdaddr[0];
cywbt_hci_cmd(0x3f, 0x0001, 6, buf);
// Set local name
// memset(buf, 0, 248);
// memcpy(buf, "PYBD-BLE", 8);
// cywbt_hci_cmd(0x03, 0x0013, 248, buf);
// Configure sleep mode
cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t *)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00");
// HCI_Write_LE_Host_Support
cywbt_hci_cmd(3, 109, 2, (const uint8_t *)"\x01\x00");
#ifdef CYW43_PIN_BT_DEV_WAKE
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
#endif
return 0;
}
int mp_bluetooth_hci_controller_deinit(void) {
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
return 0;
}
#ifdef CYW43_PIN_BT_DEV_WAKE
static uint32_t bt_sleep_ticks;
#endif
int mp_bluetooth_hci_controller_sleep_maybe(void) {
#ifdef CYW43_PIN_BT_DEV_WAKE
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 0) {
if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) {
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
}
}
#endif
return 0;
}
bool mp_bluetooth_hci_controller_woken(void) {
#ifdef CYW43_PIN_BT_HOST_WAKE
bool host_wake = mp_hal_pin_read(CYW43_PIN_BT_HOST_WAKE);
/*
// this is just for info/tracing purposes
static bool last_host_wake = false;
if (host_wake != last_host_wake) {
printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake);
last_host_wake = host_wake;
}
*/
return host_wake;
#else
return true;
#endif
}
int mp_bluetooth_hci_controller_wakeup(void) {
#ifdef CYW43_PIN_BT_DEV_WAKE
bt_sleep_ticks = mp_hal_ticks_ms();
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 1) {
mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); // wake up
// Use delay_us rather than delay_ms to prevent running the scheduler (which
// might result in more BLE operations).
mp_hal_delay_us(5000); // can't go lower than this
}
#endif
return 0;
}
#endif

View File

@@ -72,7 +72,7 @@ int esp_hosted_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_
// Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen).
for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) {
while (!mp_bluetooth_hci_uart_any()) {
mp_event_wait_ms(1);
MICROPY_EVENT_POLL_HOOK
// Timeout.
if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
error_printf("timeout waiting for HCI packet\n");
@@ -126,7 +126,7 @@ int mp_bluetooth_hci_controller_init(void) {
if (mp_bluetooth_hci_uart_any()) {
mp_bluetooth_hci_uart_readchar();
}
mp_event_wait_ms(1);
MICROPY_EVENT_POLL_HOOK
}
#ifdef MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY

View File

@@ -243,7 +243,7 @@ static int esp_hosted_request(CtrlMsgId msg_id, void *ctrl_payload) {
static CtrlMsg *esp_hosted_response(CtrlMsgId msg_id, uint32_t timeout) {
CtrlMsg *ctrl_msg = NULL;
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_event_wait_ms(10)) {
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
if (!esp_hosted_stack_empty(&esp_state.stack)) {
ctrl_msg = esp_hosted_stack_pop(&esp_state.stack, true);
if (ctrl_msg->msg_id == msg_id) {
@@ -264,6 +264,8 @@ static CtrlMsg *esp_hosted_response(CtrlMsgId msg_id, uint32_t timeout) {
if ((mp_hal_ticks_ms() - start) >= timeout) {
return NULL;
}
MICROPY_EVENT_POLL_HOOK
}
// If message type is a response, check the response struct's return value.

View File

@@ -197,10 +197,6 @@ void mp_spiflash_init(mp_spiflash_t *self) {
} else {
uint8_t num_dummy = MICROPY_HW_SPIFLASH_QREAD_NUM_DUMMY(self);
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT, num_dummy);
if (self->config->bus.u_qspi.proto->direct_read != NULL) {
// A bus with a custom read function should not have any further initialisation done.
return;
}
}
mp_spiflash_acquire_bus(self);
@@ -322,10 +318,6 @@ int mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *de
if (len == 0) {
return 0;
}
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI && c->bus.u_qspi.proto->direct_read != NULL) {
return c->bus.u_qspi.proto->direct_read(c->bus.u_qspi.data, addr, len, dest);
}
mp_spiflash_acquire_bus(self);
int ret = mp_spiflash_read_data(self, addr, len, dest);
mp_spiflash_release_bus(self);

View File

@@ -114,13 +114,13 @@ void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
mode = NINA_GPIO_OUTPUT;
self->is_output = true;
} else {
mp_raise_ValueError(MP_ERROR_TEXT("only Pin.OUT and Pin.IN are supported for this pin"));
mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin");
}
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
uint8_t buf[] = {pin_map[self->id], mode};
if (mode == NINA_GPIO_OUTPUT) {
if (NINA_GPIO_IS_INPUT_ONLY(self->id)) {
mp_raise_ValueError(MP_ERROR_TEXT("only Pin.IN is supported for this pin"));
mp_raise_ValueError("only Pin.IN is supported for this pin");
}
machine_pin_ext_set(self, value);
}

View File

@@ -50,8 +50,8 @@
#define OCF_SET_EVENT_MASK (0x0001)
#define OCF_RESET (0x0003)
#define error_printf(...) // mp_printf(&mp_plat_print, "nina_bthci_uart.c: " __VA_ARGS__)
#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bthci_uart.c: " __VA_ARGS__)
#define error_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
// Provided by the port, and also possibly shared with the stack.
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];

View File

@@ -79,9 +79,12 @@ def decode_name(payload):
def decode_services(payload):
services = []
for code in (_ADV_TYPE_UUID16_COMPLETE, _ADV_TYPE_UUID32_COMPLETE, _ADV_TYPE_UUID128_COMPLETE):
for u in decode_field(payload, code):
services.append(bluetooth.UUID(u))
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
services.append(bluetooth.UUID(u))
return services

View File

@@ -8,7 +8,7 @@ MOD = btree_$(ARCH)
SRC = btree_c.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
ARCH ?= x64
ARCH = x64
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\"
@@ -32,18 +32,6 @@ SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
mpool/mpool.c \
)
ifeq ($(ARCH),xtensa)
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
endif
# Use our own errno implementation if Picolibc is used
CFLAGS += -D__PICOLIBC_ERRNO_FUNCTION=__errno
ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
endif
include $(MPY_DIR)/py/dynruntime.mk
# btree needs gnu99 defined

View File

@@ -8,17 +8,6 @@ MOD = deflate_$(ARCH)
SRC = deflate.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
ARCH ?= x64
ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
endif
ifeq ($(ARCH),xtensa)
# Link with libm.a and libgcc.a from the toolchain
LINK_RUNTIME = 1
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
endif
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -8,15 +8,6 @@ MOD = framebuf_$(ARCH)
SRC = framebuf.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH ?= x64
ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
endif
ifeq ($(ARCH),xtensa)
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
endif
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -4,9 +4,6 @@
#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);
}

View File

@@ -8,15 +8,6 @@ MOD = random_$(ARCH)
SRC = random.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
ARCH ?= x64
ifeq ($(ARCH),xtensa)
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
endif
ifeq ($(ARCH),$(filter $(ARCH),armv6m armv7m))
# Link with libm.a for soft-float helper functions
LINK_RUNTIME = 1
endif
ARCH = x64
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -10,9 +10,4 @@ SRC = re.c
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
ARCH = x64
ifeq ($(ARCH),armv6m)
# Link with libgcc.a for division helper functions
LINK_RUNTIME = 1
endif
include $(MPY_DIR)/py/dynruntime.mk

View File

@@ -23,7 +23,7 @@ PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP)
@asm_pio(
autopush=True,
push_thresh=8,
in_shiftdir=PIO.SHIFT_RIGHT,
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
fifo_join=PIO.JOIN_RX,
)
def uart_rx_mini():
@@ -42,7 +42,7 @@ def uart_rx_mini():
@asm_pio(
in_shiftdir=PIO.SHIFT_RIGHT,
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
)
def uart_rx():
# fmt: off

View File

@@ -86,12 +86,12 @@ static void example_AdvancedTimer_print(const mp_print_t *print, mp_obj_t self_i
mp_uint_t elapsed = mp_obj_get_int(example_Timer_time(self_in));
// We'll make all representations print at least the class name.
mp_printf(print, "%q()", (qstr)MP_QSTR_AdvancedTimer);
mp_printf(print, "%q()", MP_QSTR_AdvancedTimer);
// Decide what else to print based on print kind.
if (kind == PRINT_STR) {
// For __str__, let's attempt to make it more readable.
mp_printf(print, " # created %d seconds ago", (int)(elapsed / 1000));
mp_printf(print, " # created %d seconds ago", elapsed / 1000);
}
}

View File

@@ -163,16 +163,9 @@ def run_until_complete(main_task=None):
# A task waiting on _task_queue; "ph_key" is time to schedule task at
dt = max(0, ticks_diff(t.ph_key, ticks()))
elif not _io_queue.map:
# No tasks can be woken
# No tasks can be woken so finished running
cur_task = None
if not main_task or not main_task.state:
# no main_task, or main_task is done so finished running
return
# At this point, there is theoretically nothing that could wake the
# scheduler, but it is not allowed to exit either. We keep the code
# running so that a hypothetical debugger (or other such meta-process)
# can get a view of what is happening and possibly abort.
dt = 3
return
# print('(poll {})'.format(dt), len(_io_queue.map))
_io_queue.wait_io_event(dt)
@@ -194,33 +187,31 @@ def run_until_complete(main_task=None):
except excs_all as er:
# Check the task is not on any event queue
assert t.data is None
# If it's the main task, it is considered as awaited by the caller
awaited = t is main_task
if awaited:
# This task is done, check if it's the main task and then loop should stop
if t is main_task:
cur_task = None
if not isinstance(er, StopIteration):
t.state = False
raise er
if t.state is None:
t.state = False
if isinstance(er, StopIteration):
return er.value
raise er
if t.state:
# Task was running but is now finished.
waiting = False
if t.state is True:
# "None" indicates that the task is complete and not await'ed on (yet).
t.state = False if awaited else None
t.state = None
elif callable(t.state):
# The task has a callback registered to be called on completion.
t.state(t, er)
t.state = False
awaited = True
waiting = True
else:
# Schedule any other tasks waiting on the completion of this task.
while t.state.peek():
_task_queue.push(t.state.pop())
awaited = True
waiting = True
# "False" indicates that the task is complete and has been await'ed on.
t.state = False
if not awaited and not isinstance(er, excs_stop):
if not waiting and not isinstance(er, excs_stop):
# An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw).
@@ -238,9 +229,6 @@ def run_until_complete(main_task=None):
_exc_context["exception"] = exc
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# If it's the main task then the loop should stop
if t is main_task:
return er.value
# Create a new task from a coroutine and run it until it finishes

View File

@@ -705,12 +705,12 @@ int mp_bluetooth_init(void) {
return 0;
}
int mp_bluetooth_deinit(void) {
void mp_bluetooth_deinit(void) {
DEBUG_printf("mp_bluetooth_deinit\n");
// Nothing to do if not initialised.
if (!MP_STATE_PORT(bluetooth_btstack_root_pointers)) {
return 0;
return;
}
mp_bluetooth_gap_advertise_stop();
@@ -737,9 +737,6 @@ int mp_bluetooth_deinit(void) {
deinit_stack();
DEBUG_printf("mp_bluetooth_deinit: complete\n");
bool timeout = mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT;
return timeout ? MP_ETIMEDOUT : 0;
}
bool mp_bluetooth_is_active(void) {

View File

@@ -1,126 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2025 Damien P. George, Angus Gratton
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H
#define MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H
// The board-level config will be included here, so it can set some CYW43 values.
#include "py/mpconfig.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/runtime.h"
#include "extmod/modnetwork.h"
#include "lwip/apps/mdns.h"
#include "pendsv.h"
// This file is included at the top of port-specific cyw43_configport.h files,
// and holds the MicroPython-specific but non-port-specific parts.
//
// It's included into both MicroPython sources and the lib/cyw43-driver sources.
#define CYW43_IOCTL_TIMEOUT_US (1000000)
#define CYW43_NETUTILS (1)
#define CYW43_PRINTF(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__)
#define CYW43_EPERM MP_EPERM // Operation not permitted
#define CYW43_EIO MP_EIO // I/O error
#define CYW43_EINVAL MP_EINVAL // Invalid argument
#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out
#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER
#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT
#define CYW43_THREAD_LOCK_CHECK
#define CYW43_HOST_NAME mod_network_hostname_data
#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a)
#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT
#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT
#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE
#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP
#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN
#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0
#define CYW43_HAL_MAC_BDADDR MP_HAL_MAC_BDADDR
#define cyw43_hal_ticks_us mp_hal_ticks_us
#define cyw43_hal_ticks_ms mp_hal_ticks_ms
#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t
#define cyw43_hal_pin_config mp_hal_pin_config
#define cyw43_hal_pin_read mp_hal_pin_read
#define cyw43_hal_pin_low mp_hal_pin_low
#define cyw43_hal_pin_high mp_hal_pin_high
#define cyw43_hal_get_mac mp_hal_get_mac
#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii
#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac
#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func)
// Note: this function is only called if CYW43_POST_POLL_HOOK is defined in cyw43_configport.h
void cyw43_post_poll_hook(void);
#ifdef MICROPY_EVENT_POLL_HOOK
// Older style hook macros on some ports
#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK
#else
// Newer style hooks on other ports
#define CYW43_EVENT_POLL_HOOK mp_event_handle_nowait()
#endif
static inline void cyw43_delay_us(uint32_t us) {
uint32_t start = mp_hal_ticks_us();
while (mp_hal_ticks_us() - start < us) {
}
}
static inline void cyw43_delay_ms(uint32_t ms) {
// PendSV may be disabled via CYW43_THREAD_ENTER, so this delay is a busy loop.
uint32_t us = ms * 1000;
uint32_t start = mp_hal_ticks_us();
while (mp_hal_ticks_us() - start < us) {
CYW43_EVENT_POLL_HOOK;
}
}
#if LWIP_MDNS_RESPONDER == 1
// Hook for any additional TCP/IP initialization than needs to be done.
// Called after the netif specified by `itf` has been set up.
#ifndef CYW43_CB_TCPIP_INIT_EXTRA
#define CYW43_CB_TCPIP_INIT_EXTRA(self, itf) mdns_resp_add_netif(&self->netif[itf], mod_network_hostname_data)
#endif
// Hook for any additional TCP/IP deinitialization than needs to be done.
// Called before the netif specified by `itf` is removed.
#ifndef CYW43_CB_TCPIP_DEINIT_EXTRA
#define CYW43_CB_TCPIP_DEINIT_EXTRA(self, itf) mdns_resp_remove_netif(&self->netif[itf])
#endif
#endif
#endif // MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H

View File

@@ -11,7 +11,6 @@ set(MICROPY_SOURCE_EXTMOD
${MICROPY_EXTMOD_DIR}/machine_adc_block.c
${MICROPY_EXTMOD_DIR}/machine_bitstream.c
${MICROPY_EXTMOD_DIR}/machine_i2c.c
${MICROPY_EXTMOD_DIR}/machine_i2c_target.c
${MICROPY_EXTMOD_DIR}/machine_i2s.c
${MICROPY_EXTMOD_DIR}/machine_mem.c
${MICROPY_EXTMOD_DIR}/machine_pulse.c
@@ -136,13 +135,6 @@ if(MICROPY_PY_BTREE)
${MICROPY_LIB_BERKELEY_DIR}/include
)
target_link_options(micropy_extmod_btree PRIVATE
-Wl,--wrap=malloc
-Wl,--wrap=free
-Wl,--wrap=realloc
-Wl,--wrap=calloc
)
if(NOT BERKELEY_DB_CONFIG_FILE)
set(BERKELEY_DB_CONFIG_FILE "${MICROPY_DIR}/extmod/berkeley-db/berkeley_db_config_port.h")
endif()
@@ -160,13 +152,11 @@ if(MICROPY_PY_BTREE)
list(APPEND MICROPY_DEF_CORE
MICROPY_PY_BTREE=1
MICROPY_STREAMS_POSIX_API # Required for mp_stream_posix_ functions if !MICROPY_ENABLE_DYNRUNTIME
BERKELEY_DB_CONFIG_FILE="${BERKELEY_DB_CONFIG_FILE}"
)
list(APPEND MICROPY_SOURCE_EXTMOD
${MICROPY_EXTMOD_DIR}/modbtree.c
${MICROPY_EXTMOD_DIR}/modbtree_malloc.c
)
endif()

View File

@@ -6,7 +6,6 @@ SRC_EXTMOD_C += \
extmod/machine_adc_block.c \
extmod/machine_bitstream.c \
extmod/machine_i2c.c \
extmod/machine_i2c_target.c \
extmod/machine_i2s.c \
extmod/machine_mem.c \
extmod/machine_pinbase.c \
@@ -207,7 +206,7 @@ endif
ifeq ($(MICROPY_VFS_LFS2),1)
CFLAGS_EXTMOD += -DMICROPY_VFS_LFS2=1
CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_DEFINES=extmod/littlefs-include/lfs2_defines.h
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 \
@@ -505,7 +504,7 @@ ESP_HOSTED_SRC_C = $(addprefix $(ESP_HOSTED_DIR)/,\
)
ifeq ($(MICROPY_PY_BLUETOOTH),1)
ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci_uart.c
ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci.c
endif
# Include the protobuf-c support functions

View File

@@ -1,12 +0,0 @@
#ifndef LFS2_DEFINES_H
#define LFS2_DEFINES_H
#include "py/mpconfig.h"
#if MICROPY_PY_DEFLATE
// We reuse the CRC32 implementation from uzlib to save a few bytes
#include "lib/uzlib/uzlib.h"
#define LFS2_CRC(crc, buffer, size) uzlib_crc32(buffer, size, crc)
#endif
#endif

View File

@@ -28,9 +28,6 @@
#include "py/mpconfig.h"
// This is needed to access `next_timeout` via `sys_timeouts_get_next_timeout()`.
#define LWIP_TESTMODE 1
// This sys-arch protection is not needed.
// Ports either protect lwIP code with flags, or run it at PendSV priority.
#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0)

View File

@@ -1,424 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2025 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#if MICROPY_PY_MACHINE_I2C_TARGET
#include "extmod/modmachine.h"
#include "shared/runtime/mpirq.h"
enum {
// Events exposed to Python.
I2C_TARGET_IRQ_ADDR_MATCH_READ = 1 << 0,
I2C_TARGET_IRQ_ADDR_MATCH_WRITE = 1 << 1,
I2C_TARGET_IRQ_READ_REQ = 1 << 2,
I2C_TARGET_IRQ_WRITE_REQ = 1 << 3,
I2C_TARGET_IRQ_END_READ = 1 << 4,
I2C_TARGET_IRQ_END_WRITE = 1 << 5,
// Internal event, not exposed to Python.
I2C_TARGET_IRQ_MEM_ADDR_MATCH = 1 << 6,
};
// Define the IRQs that require a hard interrupt.
#define I2C_TARGET_IRQ_ALL_HARD ( \
I2C_TARGET_IRQ_ADDR_MATCH_READ \
| I2C_TARGET_IRQ_ADDR_MATCH_WRITE \
| I2C_TARGET_IRQ_READ_REQ \
| I2C_TARGET_IRQ_WRITE_REQ \
)
enum {
STATE_INACTIVE,
STATE_IDLE,
STATE_ADDR_MATCH_READ,
STATE_ADDR_MATCH_WRITE,
STATE_MEM_ADDR_SELECT,
STATE_READING,
STATE_WRITING,
};
typedef struct _machine_i2c_target_data_t {
uint8_t state;
uint8_t mem_addr_count;
uint8_t mem_addrsize;
uint32_t mem_addr_last;
uint32_t mem_addr;
uint32_t mem_len;
uint8_t *mem_buf;
} machine_i2c_target_data_t;
typedef struct _machine_i2c_target_irq_obj_t {
mp_irq_obj_t base;
uint32_t flags;
uint32_t trigger;
} machine_i2c_target_irq_obj_t;
// The port must provide implementations of these low-level I2C target functions.
static void mp_machine_i2c_target_event_callback(machine_i2c_target_irq_obj_t *irq);
// Read up to N bytes, and return the number of bytes read.
static size_t mp_machine_i2c_target_read_bytes(machine_i2c_target_obj_t *self, size_t len, uint8_t *buf);
// Write (or buffer) N bytes, and return the number of bytes written/buffered.
static size_t mp_machine_i2c_target_write_bytes(machine_i2c_target_obj_t *self, size_t len, const uint8_t *buf);
// Configure the given events to trigger an interrupt.
static void mp_machine_i2c_target_irq_config(machine_i2c_target_obj_t *self, unsigned int trigger);
static mp_obj_t mp_machine_i2c_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
static void mp_machine_i2c_target_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
static void mp_machine_i2c_target_deinit(machine_i2c_target_obj_t *self);
static const mp_irq_methods_t machine_i2c_target_irq_methods;
static machine_i2c_target_data_t machine_i2c_target_data[MICROPY_PY_MACHINE_I2C_TARGET_MAX];
// Needed to retain a root pointer to the memory object.
MP_REGISTER_ROOT_POINTER(mp_obj_t machine_i2c_target_mem_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
// Needed to retain a root pointer to the IRQ object.
MP_REGISTER_ROOT_POINTER(void *machine_i2c_target_irq_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
static bool handle_event(machine_i2c_target_data_t *data, unsigned int trigger) {
unsigned int id = data - &machine_i2c_target_data[0];
if (trigger & I2C_TARGET_IRQ_MEM_ADDR_MATCH) {
data->mem_addr_last = data->mem_addr;
}
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[id]);
if (irq != NULL && (trigger & irq->trigger)) {
irq->flags = trigger & irq->trigger;
mp_machine_i2c_target_event_callback(irq);
return true; // irq handled
}
return false; // irq not handled
}
static void machine_i2c_target_data_init(machine_i2c_target_data_t *data, mp_obj_t mem_obj, mp_int_t mem_addrsize) {
data->state = STATE_IDLE;
data->mem_addr_count = 0;
data->mem_addrsize = 0;
data->mem_addr_last = 0;
data->mem_addr = 0;
data->mem_len = 0;
data->mem_buf = NULL;
if (mem_obj != mp_const_none) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(mem_obj, &bufinfo, MP_BUFFER_RW);
if (mem_addrsize < 0 || mem_addrsize > 32 || mem_addrsize % 8 != 0) {
mp_raise_ValueError(MP_ERROR_TEXT("mem_addrsize must be 0, 8, 16, 24 or 32"));
}
data->mem_addrsize = mem_addrsize / 8;
data->mem_len = bufinfo.len;
data->mem_buf = bufinfo.buf;
}
}
static void machine_i2c_target_data_reset_helper(machine_i2c_target_data_t *data) {
if (data->state == STATE_READING) {
handle_event(data, I2C_TARGET_IRQ_END_READ);
} else if (data->state == STATE_ADDR_MATCH_WRITE || data->state == STATE_WRITING) {
handle_event(data, I2C_TARGET_IRQ_END_WRITE);
}
data->state = STATE_IDLE;
}
static void machine_i2c_target_data_addr_match(machine_i2c_target_data_t *data, bool read) {
machine_i2c_target_data_reset_helper(data);
if (read) {
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_READ);
data->state = STATE_ADDR_MATCH_READ;
} else {
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_WRITE);
data->state = STATE_ADDR_MATCH_WRITE;
}
}
static void machine_i2c_target_data_read_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
// Let the user handle the read request.
bool event_handled = handle_event(data, I2C_TARGET_IRQ_READ_REQ);
if (data->mem_buf == NULL) {
data->state = STATE_READING;
if (!event_handled) {
// No data source, just write out a zero.
uint8_t val = 0;
mp_machine_i2c_target_write_bytes(self, 1, &val);
}
} else {
// Have a buffer.
if (data->state == STATE_MEM_ADDR_SELECT) {
// Got a short memory address.
data->mem_addr %= data->mem_len;
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
}
if (data->state != STATE_READING) {
data->state = STATE_READING;
}
uint8_t val = data->mem_buf[data->mem_addr++];
if (data->mem_addr >= data->mem_len) {
data->mem_addr = 0;
}
mp_machine_i2c_target_write_bytes(self, 1, &val);
}
}
static void machine_i2c_target_data_write_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
// Let the user handle the write request.
bool event_handled = handle_event(data, I2C_TARGET_IRQ_WRITE_REQ);
if (data->mem_buf == NULL) {
data->state = STATE_WRITING;
if (!event_handled) {
// No data sink, just read and discard the incoming byte.
uint8_t buf = 0;
mp_machine_i2c_target_read_bytes(self, 1, &buf);
}
} else {
// Have a buffer.
uint8_t buf[4] = {0};
size_t n = mp_machine_i2c_target_read_bytes(self, sizeof(buf), &buf[0]);
for (size_t i = 0; i < n; ++i) {
uint8_t val = buf[i];
if (data->state == STATE_ADDR_MATCH_WRITE) {
data->state = STATE_MEM_ADDR_SELECT;
data->mem_addr = 0;
data->mem_addr_count = data->mem_addrsize;
}
if (data->state == STATE_MEM_ADDR_SELECT && data->mem_addr_count > 0) {
data->mem_addr = data->mem_addr << 8 | val;
--data->mem_addr_count;
if (data->mem_addr_count == 0) {
data->mem_addr %= data->mem_len;
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
}
} else {
if (data->state == STATE_MEM_ADDR_SELECT) {
data->state = STATE_WRITING;
}
data->mem_buf[data->mem_addr++] = val;
if (data->mem_addr >= data->mem_len) {
data->mem_addr = 0;
}
}
}
}
}
static inline void machine_i2c_target_data_restart_or_stop(machine_i2c_target_data_t *data) {
machine_i2c_target_data_reset_helper(data);
}
static inline void machine_i2c_target_data_stop(machine_i2c_target_data_t *data) {
machine_i2c_target_data_reset_helper(data);
}
// The port provides implementations of its bindings in this file.
#include MICROPY_PY_MACHINE_I2C_TARGET_INCLUDEFILE
static void machine_i2c_target_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
size_t index = mp_machine_i2c_target_get_index(self);
machine_i2c_target_data_t *data = &machine_i2c_target_data[index];
if (dest[0] == MP_OBJ_NULL) {
// Load attribute.
if (attr == MP_QSTR_memaddr) {
dest[0] = mp_obj_new_int(data->mem_addr_last);
} else {
// Continue lookup in locals_dict.
dest[1] = MP_OBJ_SENTINEL;
}
}
}
// I2CTarget.deinit()
static mp_obj_t machine_i2c_target_deinit(mp_obj_t self_in) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
size_t index = mp_machine_i2c_target_get_index(self);
if (machine_i2c_target_data[index].state != STATE_INACTIVE) {
machine_i2c_target_data[index].state = STATE_INACTIVE;
mp_machine_i2c_target_deinit(self);
MP_STATE_PORT(machine_i2c_target_mem_obj[index]) = MP_OBJ_NULL;
MP_STATE_PORT(machine_i2c_target_irq_obj[index]) = NULL;
}
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_target_deinit_obj, machine_i2c_target_deinit);
// I2CTarget.readinto(buf)
static mp_obj_t machine_i2c_target_readinto(mp_obj_t self_in, mp_obj_t buf_in) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
return MP_OBJ_NEW_SMALL_INT(mp_machine_i2c_target_read_bytes(self, bufinfo.len, bufinfo.buf));
}
static MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_target_readinto_obj, machine_i2c_target_readinto);
// I2CTarget.write(data)
static mp_obj_t machine_i2c_target_write(mp_obj_t self_in, mp_obj_t data_in) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
return MP_OBJ_NEW_SMALL_INT(mp_machine_i2c_target_write_bytes(self, bufinfo.len, bufinfo.buf));
}
static MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_target_write_obj, machine_i2c_target_write);
static machine_i2c_target_irq_obj_t *machine_i2c_target_get_irq(machine_i2c_target_obj_t *self) {
// Get the IRQ object.
size_t index = mp_machine_i2c_target_get_index(self);
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
// Allocate the IRQ object if it doesn't already exist.
if (irq == NULL) {
irq = m_new_obj(machine_i2c_target_irq_obj_t);
irq->base.base.type = &mp_irq_type;
irq->base.methods = (mp_irq_methods_t *)&machine_i2c_target_irq_methods;
irq->base.parent = MP_OBJ_FROM_PTR(self);
irq->base.handler = mp_const_none;
irq->base.ishard = false;
MP_STATE_PORT(machine_i2c_target_irq_obj[index]) = irq;
}
return irq;
}
// I2CTarget.irq(handler=None, trigger=IRQ_END_READ|IRQ_END_WRITE, hard=False)
static mp_obj_t machine_i2c_target_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger, ARG_hard };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = I2C_TARGET_IRQ_END_READ | I2C_TARGET_IRQ_END_WRITE} },
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
};
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
machine_i2c_target_irq_obj_t *irq = machine_i2c_target_get_irq(self);
if (n_args > 1 || kw_args->used != 0) {
// Update IRQ data.
mp_obj_t handler = args[ARG_handler].u_obj;
mp_uint_t trigger = args[ARG_trigger].u_int;
bool hard = args[ARG_hard].u_bool;
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
if ((trigger & I2C_TARGET_IRQ_ALL_HARD) && !hard) {
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ required"));
}
#else
if (hard) {
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ unsupported"));
}
#endif
// Disable all IRQs while data is updated.
mp_machine_i2c_target_irq_config(self, 0);
// Update IRQ data.
irq->base.handler = handler;
irq->base.ishard = hard;
irq->flags = 0;
irq->trigger = trigger;
// Enable IRQ if a handler is given.
if (handler != mp_const_none && trigger != 0) {
mp_machine_i2c_target_irq_config(self, trigger);
}
}
return MP_OBJ_FROM_PTR(irq);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_target_irq_obj, 1, machine_i2c_target_irq);
static const mp_rom_map_elem_t machine_i2c_target_locals_dict_table[] = {
#if MICROPY_PY_MACHINE_I2C_TARGET_FINALISER
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_i2c_target_deinit_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2c_target_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_target_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_target_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2c_target_irq_obj) },
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_READ), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_READ) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_WRITE) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_READ_REQ), MP_ROM_INT(I2C_TARGET_IRQ_READ_REQ) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_WRITE_REQ), MP_ROM_INT(I2C_TARGET_IRQ_WRITE_REQ) },
#endif
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_READ), MP_ROM_INT(I2C_TARGET_IRQ_END_READ) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_END_WRITE) },
};
static MP_DEFINE_CONST_DICT(machine_i2c_target_locals_dict, machine_i2c_target_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
machine_i2c_target_type,
MP_QSTR_I2CTarget,
MP_TYPE_FLAG_NONE,
make_new, mp_machine_i2c_target_make_new,
print, mp_machine_i2c_target_print,
attr, &machine_i2c_target_attr,
locals_dict, &machine_i2c_target_locals_dict
);
static mp_uint_t machine_i2c_target_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
size_t index = mp_machine_i2c_target_get_index(self);
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
mp_machine_i2c_target_irq_config(self, 0);
irq->flags = 0;
irq->trigger = new_trigger;
mp_machine_i2c_target_irq_config(self, new_trigger);
return 0;
}
static mp_uint_t machine_i2c_target_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
size_t index = mp_machine_i2c_target_get_index(self);
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
if (info_type == MP_IRQ_INFO_FLAGS) {
return irq->flags;
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
return irq->trigger;
}
return 0;
}
static const mp_irq_methods_t machine_i2c_target_irq_methods = {
.trigger = machine_i2c_target_irq_trigger,
.info = machine_i2c_target_irq_info,
};
#if !MICROPY_PY_MACHINE_I2C_TARGET_FINALISER
void mp_machine_i2c_target_deinit_all(void) {
for (size_t i = 0; i < MICROPY_PY_MACHINE_I2C_TARGET_MAX; ++i) {
if (machine_i2c_target_data[i].state != STATE_INACTIVE) {
machine_i2c_target_deinit(MP_OBJ_FROM_PTR(&machine_i2c_target_obj[i]));
}
}
}
#endif
#endif // MICROPY_PY_MACHINE_I2C_TARGET

View File

@@ -30,35 +30,20 @@
#if MICROPY_PY_MACHINE_PULSE
mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
mp_uint_t nchanges = 2;
MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
mp_uint_t start = mp_hal_ticks_us();
for (;;) {
// Sample ticks and pin as close together as possible, and always in the same
// order each time around the loop. This gives the most accurate measurement.
mp_uint_t t = mp_hal_ticks_us();
int pin_value = mp_hal_pin_read(pin);
if (pin_value == pulse_level) {
// Pin is at desired value. Flip desired value and see if we are done.
pulse_level = 1 - pulse_level;
if (--nchanges == 0) {
return t - start;
}
start = t;
} else {
// Pin hasn't changed yet, check for timeout.
mp_uint_t dt = t - start;
if (dt >= timeout_us) {
return -nchanges;
}
// Allow a port to perform background task processing if needed.
#ifdef MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK
MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK(dt);
#endif
while (mp_hal_pin_read(pin) != pulse_level) {
if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {
return (mp_uint_t)-2;
}
}
start = mp_hal_ticks_us();
while (mp_hal_pin_read(pin) == pulse_level) {
if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {
return (mp_uint_t)-1;
}
}
return mp_hal_ticks_us() - start;
}
static mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) {

View File

@@ -108,7 +108,7 @@ static mp_obj_t usb_device_submit_xfer(mp_obj_t self, mp_obj_t ep, mp_obj_t buff
//
// This C layer doesn't otherwise keep track of which endpoints the host
// is aware of (or not).
mp_raise_ValueError(MP_ERROR_TEXT("ep"));
mp_raise_ValueError("ep");
}
if (!usbd_edpt_claim(USBD_RHPORT, ep_addr)) {

View File

@@ -26,8 +26,6 @@
#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
#define MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
#include "py/mpconfig.h"
// If you want to debug MBEDTLS uncomment the following and
// pass "3" to mbedtls_debug_set_threshold in socket_new.
// #define MBEDTLS_DEBUG_C
@@ -91,18 +89,12 @@
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#if MICROPY_PY_SSL_DTLS
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
#define MBEDTLS_SSL_COOKIE_C
#endif
// A port may enable this option to select additional bare-metal configuration.
#if MICROPY_MBEDTLS_CONFIG_BARE_METAL
@@ -123,8 +115,4 @@ void m_tracked_free(void *ptr);
#endif
// Workaround for a mimxrt platform driver header that defines ARRAY_SIZE,
// which is also defined in some mbedtls source files.
#undef ARRAY_SIZE
#endif // MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H

View File

@@ -290,13 +290,12 @@ static mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args,
static mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) {
if (n_args == 2) {
// Boolean enable/disable argument supplied, set current state.
int err;
if (mp_obj_is_true(args[1])) {
err = mp_bluetooth_init();
int err = mp_bluetooth_init();
bluetooth_handle_errno(err);
} else {
err = mp_bluetooth_deinit();
mp_bluetooth_deinit();
}
bluetooth_handle_errno(err);
}
// Return current state.
return mp_obj_new_bool(mp_bluetooth_is_active());
@@ -341,7 +340,7 @@ static mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
}
for (size_t i = 0; i < kwargs->alloc; ++i) {
if (mp_map_slot_is_filled(kwargs, i)) {
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
mp_map_elem_t *e = &kwargs->table[i];
switch (mp_obj_str_get_qstr(e->key)) {
case MP_QSTR_gap_name: {

View File

@@ -295,7 +295,7 @@ extern const mp_obj_type_t mp_type_bluetooth_uuid;
int mp_bluetooth_init(void);
// Disables the Bluetooth stack. Is a no-op when not enabled.
int mp_bluetooth_deinit(void);
void mp_bluetooth_deinit(void);
// Returns true when the Bluetooth stack is active.
bool mp_bluetooth_is_active(void);

View File

@@ -1,40 +0,0 @@
#include "py/runtime.h"
#include <string.h>
void *__wrap_malloc(size_t size) {
// Allocate an extra sizeof(size_t) bytes
size_t *addr = (size_t *)m_tracked_calloc(sizeof(uint8_t), size + sizeof(size_t));
// Tag our memory with its allocated size
*addr = size;
// Skip past the size_t size
addr++;
#ifdef BTREE_DEBUG_MALLOC
mp_printf(&mp_plat_print, "malloc %lu %p : %p\n", size, addr, (uint8_t *)addr + size);
#endif
return (void *)addr;
}
void __wrap_free(void *p) {
size_t *pp = (size_t *)p; // Convert our void pointer to size_t* so we can read the size marker
pp--; // Skip back to get our real start
size_t size __attribute__((unused)) = *pp;
m_tracked_free((void *)pp);
#ifdef BTREE_DEBUG_MALLOC
mp_printf(&mp_plat_print, "free %p (size %d)\n", p, size);
#endif
}
void *__wrap_realloc(void *p, size_t size) {
void *addr = __wrap_malloc(size);
size_t old_size = *((size_t *)p - 1);
memcpy(addr, p, old_size < size ? old_size : size);
__wrap_free(p);
#ifdef BTREE_DEBUG_MALLOC
mp_printf(&mp_plat_print, "realloc %lu -> %lu, %p -> %p : %p\n", old_size, size, p, addr, (uint8_t *)addr + size);
#endif
return addr;
}
void *__wrap_calloc(size_t nitems, size_t size) {
return __wrap_malloc(size * nitems);
}

View File

@@ -270,7 +270,8 @@ static void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, u
formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col);
}
static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in, unsigned int buf_flags, mp_obj_framebuf_t *o) {
static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
mp_arg_check_num(n_args, n_kw, 4, 5, false);
mp_int_t width = mp_obj_get_int(args_in[1]);
mp_int_t height = mp_obj_get_int(args_in[2]);
@@ -317,15 +318,13 @@ static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in,
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args_in[0], &bufinfo, buf_flags);
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
if ((strides_required * stride + (height_required - strides_required) * width_required) * bpp / 8 > bufinfo.len) {
mp_raise_ValueError(NULL);
}
if (o == NULL) {
o = mp_obj_malloc(mp_obj_framebuf_t, (const mp_obj_type_t *)&mp_type_framebuf);
}
mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, type);
o->buf_obj = args_in[0];
o->buf = bufinfo.buf;
o->width = width;
@@ -336,11 +335,6 @@ static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in,
return MP_OBJ_FROM_PTR(o);
}
static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
mp_arg_check_num(n_args, n_kw, 4, 5, false);
return framebuf_make_new_helper(n_args, args_in, MP_BUFFER_WRITE, NULL);
}
static void framebuf_args(const mp_obj_t *args_in, mp_int_t *args_out, int n) {
for (int i = 0; i < n; ++i) {
args_out[i] = mp_obj_get_int(args_in[i + 1]);
@@ -713,27 +707,13 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_poly_obj, 5, 6, framebuf_pol
#endif // MICROPY_PY_ARRAY
static void get_readonly_framebuffer(mp_obj_t arg, mp_obj_framebuf_t *rofb) {
mp_obj_t fb = mp_obj_cast_to_native_base(arg, MP_OBJ_FROM_PTR(&mp_type_framebuf));
if (fb != MP_OBJ_NULL) {
*rofb = *(mp_obj_framebuf_t *)MP_OBJ_TO_PTR(fb);
} else {
// A tuple/list of the form: (buffer, width, height, format[, stride]).
size_t len;
mp_obj_t *items;
mp_obj_get_array(arg, &len, &items);
if (len < 4 || len > 5) {
mp_raise_ValueError(NULL);
}
framebuf_make_new_helper(len, items, MP_BUFFER_READ, rofb);
}
}
static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args_in[0]);
mp_obj_framebuf_t source;
get_readonly_framebuffer(args_in[1], &source);
mp_obj_t source_in = mp_obj_cast_to_native_base(args_in[1], MP_OBJ_FROM_PTR(&mp_type_framebuf));
if (source_in == MP_OBJ_NULL) {
mp_raise_TypeError(NULL);
}
mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(source_in);
mp_int_t x = mp_obj_get_int(args_in[2]);
mp_int_t y = mp_obj_get_int(args_in[3]);
@@ -741,17 +721,16 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
if (n_args > 4) {
key = mp_obj_get_int(args_in[4]);
}
mp_obj_framebuf_t palette;
palette.buf = NULL;
mp_obj_framebuf_t *palette = NULL;
if (n_args > 5 && args_in[5] != mp_const_none) {
get_readonly_framebuffer(args_in[5], &palette);
palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args_in[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
}
if (
(x >= self->width) ||
(y >= self->height) ||
(-x >= source.width) ||
(-y >= source.height)
(-x >= source->width) ||
(-y >= source->height)
) {
// Out of bounds, no-op.
return mp_const_none;
@@ -762,15 +741,15 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
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);
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.buf) {
col = getpixel(&palette, col, 0);
uint32_t col = getpixel(source, cx1, y1);
if (palette) {
col = getpixel(palette, col, 0);
}
if (col != (uint32_t)key) {
setpixel(self, cx0, y0, col);

View File

@@ -160,8 +160,7 @@ static mp_obj_t mod_json_load(mp_obj_t stream_obj) {
for (;;) {
cont:
if (S_END(s)) {
// Input finished abruptly in the middle of a composite entity.
goto fail;
break;
}
mp_obj_t next = MP_OBJ_NULL;
bool enter = false;

View File

@@ -70,10 +70,6 @@
#define TCP_NODELAY TF_NODELAY
// Socket flags
#define MSG_PEEK 0x01
#define MSG_DONTWAIT 0x02
// For compatibilily with older lwIP versions.
#ifndef ip_set_option
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
@@ -290,15 +286,6 @@ static const int error_lookup_table[] = {
#define MOD_NETWORK_SOCK_DGRAM (2)
#define MOD_NETWORK_SOCK_RAW (3)
// Total queue length for buffered UDP/raw incoming packets.
#define LWIP_INCOMING_PACKET_QUEUE_LEN (4)
typedef struct _lwip_incoming_packet_t {
struct pbuf *pbuf;
ip_addr_t peer_addr;
uint16_t peer_port;
} lwip_incoming_packet_t;
typedef struct _lwip_socket_obj_t {
mp_obj_base_t base;
@@ -307,11 +294,8 @@ typedef struct _lwip_socket_obj_t {
struct udp_pcb *udp;
struct raw_pcb *raw;
} pcb;
// Data structure that holds incoming pbuf's.
// Each socket type has different state that it needs to keep track of.
volatile union {
// TCP listening sockets have a queue of incoming connections, implemented as a ringbuffer.
struct pbuf *pbuf;
struct {
uint8_t alloc;
uint8_t iget;
@@ -321,23 +305,10 @@ typedef struct _lwip_socket_obj_t {
struct tcp_pcb **array; // if alloc != 0
} tcp;
} connection;
// Connected TCP sockets have a single incoming pbuf that new data is appended to.
struct {
struct pbuf *pbuf;
} tcp;
// UDP and raw sockets have a queue of incoming pbuf's, implemented as a ringbuffer.
struct {
uint8_t iget; // ringbuffer read index
uint8_t iput; // ringbuffer write index
lwip_incoming_packet_t *array;
} udp_raw;
} incoming;
mp_obj_t callback;
ip_addr_t tcp_peer_addr;
mp_uint_t tcp_peer_port;
ip_addr_t peer;
mp_uint_t peer_port;
mp_uint_t timeout;
uint16_t recv_offset;
@@ -376,21 +347,9 @@ static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
&& socket->pcb.tcp->state == LISTEN;
if (!socket_is_listener) {
if (socket->type == MOD_NETWORK_SOCK_STREAM) {
if (socket->incoming.tcp.pbuf != NULL) {
pbuf_free(socket->incoming.tcp.pbuf);
socket->incoming.tcp.pbuf = NULL;
}
} else {
for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) {
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[i];
if (slot->pbuf != NULL) {
pbuf_free(slot->pbuf);
slot->pbuf = NULL;
}
}
socket->incoming.udp_raw.iget = 0;
socket->incoming.udp_raw.iput = 0;
if (socket->incoming.pbuf != NULL) {
pbuf_free(socket->incoming.pbuf);
socket->incoming.pbuf = NULL;
}
} else {
uint8_t alloc = socket->incoming.connection.alloc;
@@ -448,19 +407,6 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) {
}
}
static void udp_raw_incoming(lwip_socket_obj_t *socket, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iput];
if (slot->pbuf != NULL) {
// No room in the inn, drop the packet.
pbuf_free(p);
} else {
slot->pbuf = p;
slot->peer_addr = *addr;
slot->peer_port = port;
socket->incoming.udp_raw.iput = (socket->incoming.udp_raw.iput + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN;
}
}
#if MICROPY_PY_LWIP_SOCK_RAW
// Callback for incoming raw packets.
#if LWIP_VERSION_MAJOR < 2
@@ -470,7 +416,13 @@ static u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, c
#endif
{
lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
udp_raw_incoming(socket, p, addr, 0);
if (socket->incoming.pbuf != NULL) {
pbuf_free(p);
} else {
socket->incoming.pbuf = p;
memcpy(&socket->peer, addr, sizeof(socket->peer));
}
return 1; // we ate the packet
}
#endif
@@ -484,7 +436,15 @@ static void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p,
#endif
{
lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
udp_raw_incoming(socket, p, addr, port);
if (socket->incoming.pbuf != NULL) {
// That's why they call it "unreliable". No room in the inn, drop the packet.
pbuf_free(p);
} else {
socket->incoming.pbuf = p;
socket->peer_port = (mp_uint_t)port;
memcpy(&socket->peer, addr, sizeof(socket->peer));
}
}
// Callback for general tcp errors.
@@ -602,13 +562,13 @@ static err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
return ERR_OK;
}
if (socket->incoming.tcp.pbuf == NULL) {
socket->incoming.tcp.pbuf = p;
if (socket->incoming.pbuf == NULL) {
socket->incoming.pbuf = p;
} else {
#ifdef SOCKET_SINGLE_PBUF
return ERR_BUF;
#else
pbuf_cat(socket->incoming.tcp.pbuf, p);
pbuf_cat(socket->incoming.pbuf, p);
#endif
}
@@ -677,20 +637,18 @@ static mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, m
}
// Helper function for recv/recvfrom to handle raw/UDP packets
static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, ip_addr_t *ip, mp_uint_t *port, int *_errno) {
static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, ip_addr_t *ip, mp_uint_t *port, int *_errno) {
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget];
if (slot->pbuf == NULL) {
// Non-blocking socket or flag
if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) {
if (socket->incoming.pbuf == NULL) {
if (socket->timeout == 0) {
// Non-blocking socket.
*_errno = MP_EAGAIN;
return -1;
}
// Wait for data to arrive on UDP socket.
mp_uint_t start = mp_hal_ticks_ms();
while (slot->pbuf == NULL) {
while (socket->incoming.pbuf == NULL) {
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = MP_ETIMEDOUT;
return -1;
@@ -700,20 +658,17 @@ static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_u
}
if (ip != NULL) {
*ip = slot->peer_addr;
*port = slot->peer_port;
memcpy(ip, &socket->peer, sizeof(socket->peer));
*port = socket->peer_port;
}
struct pbuf *p = slot->pbuf;
struct pbuf *p = socket->incoming.pbuf;
MICROPY_PY_LWIP_ENTER
u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
if ((flags & MSG_PEEK) == 0) {
pbuf_free(p);
slot->pbuf = NULL;
socket->incoming.udp_raw.iget = (socket->incoming.udp_raw.iget + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN;
}
pbuf_free(p);
socket->incoming.pbuf = NULL;
MICROPY_PY_LWIP_EXIT
@@ -821,20 +776,14 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
}
// Helper function for recv/recvfrom to handle TCP packets
static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, int *_errno) {
static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
// Check for any pending errors
STREAM_ERROR_CHECK(socket);
if (socket->state == STATE_LISTENING) {
// original socket in listening state, not the accepted connection.
*_errno = MP_ENOTCONN;
return -1;
}
if (socket->incoming.pbuf == NULL) {
if (socket->incoming.tcp.pbuf == NULL) {
// Non-blocking socket or flag
if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) {
// Non-blocking socket
if (socket->timeout == 0) {
if (socket->state == STATE_PEER_CLOSED) {
return 0;
}
@@ -843,7 +792,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
mp_uint_t start = mp_hal_ticks_ms();
while (socket->state == STATE_CONNECTED && socket->incoming.tcp.pbuf == NULL) {
while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) {
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = MP_ETIMEDOUT;
return -1;
@@ -852,7 +801,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
if (socket->state == STATE_PEER_CLOSED) {
if (socket->incoming.tcp.pbuf == NULL) {
if (socket->incoming.pbuf == NULL) {
// socket closed and no data left in buffer
return 0;
}
@@ -870,7 +819,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
assert(socket->pcb.tcp != NULL);
struct pbuf *p = socket->incoming.tcp.pbuf;
struct pbuf *p = socket->incoming.pbuf;
mp_uint_t remaining = p->len - socket->recv_offset;
if (len > remaining) {
@@ -879,21 +828,19 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
memcpy(buf, (byte *)p->payload + socket->recv_offset, len);
if ((flags & MSG_PEEK) == 0) {
remaining -= len;
if (remaining == 0) {
socket->incoming.tcp.pbuf = p->next;
// If we don't ref here, free() will free the entire chain,
// if we ref, it does what we need: frees 1st buf, and decrements
// next buf's refcount back to 1.
pbuf_ref(p->next);
pbuf_free(p);
socket->recv_offset = 0;
} else {
socket->recv_offset += len;
}
tcp_recved(socket->pcb.tcp, len);
remaining -= len;
if (remaining == 0) {
socket->incoming.pbuf = p->next;
// If we don't ref here, free() will free the entire chain,
// if we ref, it does what we need: frees 1st buf, and decrements
// next buf's refcount back to 1.
pbuf_ref(p->next);
pbuf_free(p);
socket->recv_offset = 0;
} else {
socket->recv_offset += len;
}
tcp_recved(socket->pcb.tcp, len);
MICROPY_PY_LWIP_EXIT
@@ -907,18 +854,8 @@ static const mp_obj_type_t lwip_socket_type;
static void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
lwip_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<socket state=%d timeout=" UINT_FMT " incoming=", self->state, self->timeout);
if (self->type == MOD_NETWORK_SOCK_STREAM) {
mp_printf(print, "%p off=%d>", self->incoming.tcp.pbuf, self->recv_offset);
} else {
int num_in_queue = 0;
for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) {
if (self->incoming.udp_raw.array[i].pbuf != NULL) {
++num_in_queue;
}
}
mp_printf(print, "%d>", num_in_queue);
}
mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout,
self->incoming.pbuf, self->recv_offset);
}
// FIXME: Only supports two arguments at present
@@ -947,22 +884,16 @@ static mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s
socket->incoming.connection.tcp.item = NULL;
break;
case MOD_NETWORK_SOCK_DGRAM:
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
#endif
if (socket->type == MOD_NETWORK_SOCK_DGRAM) {
socket->pcb.udp = udp_new();
}
#if MICROPY_PY_LWIP_SOCK_RAW
else {
mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]);
socket->pcb.raw = raw_new(proto);
}
#endif
socket->incoming.udp_raw.iget = 0;
socket->incoming.udp_raw.iput = 0;
socket->incoming.udp_raw.array = m_new0(lwip_incoming_packet_t, LWIP_INCOMING_PACKET_QUEUE_LEN);
socket->pcb.udp = udp_new();
socket->incoming.pbuf = NULL;
break;
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW: {
mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]);
socket->pcb.raw = raw_new(proto);
break;
}
#endif
default:
mp_raise_OSError(MP_EINVAL);
}
@@ -1144,7 +1075,7 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
// ...and set up the new socket for it.
socket2->domain = MOD_NETWORK_AF_INET;
socket2->type = MOD_NETWORK_SOCK_STREAM;
socket2->incoming.tcp.pbuf = NULL;
socket2->incoming.pbuf = NULL;
socket2->timeout = socket->timeout;
socket2->state = STATE_CONNECTED;
socket2->recv_offset = 0;
@@ -1199,8 +1130,8 @@ static mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
socket->state = STATE_NEW;
mp_raise_OSError(error_lookup_table[-err]);
}
socket->tcp_peer_addr = dest;
socket->tcp_peer_port = (mp_uint_t)port;
socket->peer_port = (mp_uint_t)port;
memcpy(&socket->peer, &dest, sizeof(socket->peer));
MICROPY_PY_LWIP_EXIT
// And now we wait...
@@ -1285,58 +1216,40 @@ static mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send);
// Common implementation for recv & recvfrom
static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_addr_t *ip, mp_uint_t *port) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]);
mp_int_t len = mp_obj_get_int(args[1]);
mp_int_t flags = n_args > 2 ? mp_obj_get_int(args[2]) : 0;
static mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
int _errno;
vstr_t vstr;
mp_uint_t ret = 0;
lwip_socket_check_connected(socket);
mp_int_t len = mp_obj_get_int(len_in);
vstr_t vstr;
vstr_init_len(&vstr, len);
mp_uint_t ret = 0;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
if (ip != NULL) {
*ip = socket->tcp_peer_addr;
*port = (mp_uint_t)socket->tcp_peer_port;
}
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, flags, &_errno);
case MOD_NETWORK_SOCK_STREAM: {
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
break;
}
case MOD_NETWORK_SOCK_DGRAM:
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
#endif
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, flags, ip, port, &_errno);
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, NULL, NULL, &_errno);
break;
}
if (ret == -1) {
mp_raise_OSError(_errno);
}
if (ret == 0) {
return mp_const_empty_bytes;
}
vstr.len = ret;
return mp_obj_new_bytes_from_vstr(&vstr);
}
static mp_obj_t lwip_socket_recv(size_t n_args, const mp_obj_t *args) {
return lwip_socket_recv_common(n_args, args, NULL, NULL);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recv_obj, 2, 3, lwip_socket_recv);
static mp_obj_t lwip_socket_recvfrom(size_t n_args, const mp_obj_t *args) {
ip_addr_t ip;
mp_uint_t port;
mp_obj_t tuple[2];
tuple[0] = lwip_socket_recv_common(n_args, args, &ip, &port);
tuple[1] = lwip_format_inet_addr(&ip, port);
return mp_obj_new_tuple(2, tuple);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recvfrom_obj, 2, 3, lwip_socket_recvfrom);
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv);
static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
@@ -1371,6 +1284,50 @@ static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
}
static MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto);
static mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
int _errno;
lwip_socket_check_connected(socket);
mp_int_t len = mp_obj_get_int(len_in);
vstr_t vstr;
vstr_init_len(&vstr, len);
ip_addr_t ip;
mp_uint_t port;
mp_uint_t ret = 0;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
memcpy(&ip, &socket->peer, sizeof(socket->peer));
port = (mp_uint_t)socket->peer_port;
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
break;
}
case MOD_NETWORK_SOCK_DGRAM:
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
#endif
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, &ip, &port, &_errno);
break;
}
if (ret == -1) {
mp_raise_OSError(_errno);
}
mp_obj_t tuple[2];
if (ret == 0) {
tuple[0] = mp_const_empty_bytes;
} else {
vstr.len = ret;
tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
}
tuple[1] = lwip_format_inet_addr(&ip, port);
return mp_obj_new_tuple(2, tuple);
}
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom);
static mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
lwip_socket_check_connected(socket);
@@ -1530,12 +1487,12 @@ static mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, i
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
return lwip_tcp_receive(socket, buf, size, 0, errcode);
return lwip_tcp_receive(socket, buf, size, errcode);
case MOD_NETWORK_SOCK_DGRAM:
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
#endif
return lwip_raw_udp_receive(socket, buf, size, 0, NULL, NULL, errcode);
return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode);
}
// Unreachable
return MP_STREAM_ERROR;
@@ -1580,15 +1537,9 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
if (lwip_socket_incoming_array(socket)[socket->incoming.connection.iget] != NULL) {
ret |= MP_STREAM_POLL_RD;
}
} else if (socket->type == MOD_NETWORK_SOCK_STREAM) {
// For TCP sockets there is just one slot for incoming data
if (socket->incoming.tcp.pbuf != NULL) {
ret |= MP_STREAM_POLL_RD;
}
} else {
// Otherwise for UDP/raw there is a queue of incoming data
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget];
if (slot->pbuf != NULL) {
// Otherwise there is just one slot for incoming data
if (socket->incoming.pbuf != NULL) {
ret |= MP_STREAM_POLL_RD;
}
}
@@ -1907,8 +1858,6 @@ static const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IP_PROTO_TCP) },
{ MP_ROM_QSTR(MP_QSTR_TCP_NODELAY), MP_ROM_INT(TCP_NODELAY) },
{ MP_ROM_QSTR(MP_QSTR_MSG_PEEK), MP_ROM_INT(MSG_PEEK) },
{ MP_ROM_QSTR(MP_QSTR_MSG_DONTWAIT), MP_ROM_INT(MSG_DONTWAIT) },
};
static MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);

View File

@@ -45,11 +45,11 @@
static void mp_machine_idle(void);
#if MICROPY_PY_MACHINE_BOOTLOADER
MP_NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args);
NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args);
#endif
#if MICROPY_PY_MACHINE_RESET
MP_NORETURN static void mp_machine_reset(void);
NORETURN static void mp_machine_reset(void);
static mp_int_t mp_machine_reset_cause(void);
#endif
@@ -58,7 +58,7 @@ static mp_obj_t mp_machine_unique_id(void);
static mp_obj_t mp_machine_get_freq(void);
static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args);
static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args);
MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
#endif
// The port can provide additional machine-module implementation in this file.
@@ -67,7 +67,7 @@ MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args
#endif
#if MICROPY_PY_MACHINE_BOOTLOADER
MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
mp_machine_bootloader(n_args, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
@@ -81,7 +81,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
#if MICROPY_PY_MACHINE_RESET
MP_NORETURN static mp_obj_t machine_reset(void) {
NORETURN static mp_obj_t machine_reset(void) {
mp_machine_reset();
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
@@ -116,7 +116,7 @@ static mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep);
MP_NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
mp_machine_deepsleep(n_args, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep);
@@ -219,9 +219,6 @@ static const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_I2C
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
#endif
#if MICROPY_PY_MACHINE_I2C_TARGET
{ MP_ROM_QSTR(MP_QSTR_I2CTarget), MP_ROM_PTR(&machine_i2c_target_type) },
#endif
#if MICROPY_PY_MACHINE_I2S
{ MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
#endif

View File

@@ -129,7 +129,6 @@
// A port must provide these types, but they are otherwise opaque.
typedef struct _machine_adc_obj_t machine_adc_obj_t;
typedef struct _machine_adc_block_obj_t machine_adc_block_obj_t;
typedef struct _machine_i2c_target_obj_t machine_i2c_target_obj_t;
typedef struct _machine_i2s_obj_t machine_i2s_obj_t;
typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
typedef struct _machine_uart_obj_t machine_uart_obj_t;
@@ -204,7 +203,6 @@ extern const machine_mem_obj_t machine_mem32_obj;
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_adc_block_type;
extern const mp_obj_type_t machine_i2c_type;
extern const mp_obj_type_t machine_i2c_target_type;
extern const mp_obj_type_t machine_i2s_type;
extern const mp_obj_type_t machine_mem_type;
extern const mp_obj_type_t machine_pin_type;
@@ -244,7 +242,7 @@ uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align);
uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align);
#endif
MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len);
mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us);
@@ -263,10 +261,6 @@ int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n
int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
#endif
#if MICROPY_PY_MACHINE_I2C_TARGET
void mp_machine_i2c_target_deinit_all(void);
#endif
#if MICROPY_PY_MACHINE_SPI
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);

View File

@@ -40,19 +40,6 @@
#if MICROPY_PY_NETWORK_CYW43
// So that CYW43_LINK_xxx constants are available to MICROPY_PORT_NETWORK_INTERFACES.
#include "lib/cyw43-driver/src/cyw43.h"
extern const struct _mp_obj_type_t mp_network_cyw43_type;
#endif
#if MICROPY_PY_NETWORK_WIZNET5K
extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
#endif
#if MICROPY_PY_NETWORK_NINAW10
extern const struct _mp_obj_type_t mod_network_nic_type_nina;
#endif
#if MICROPY_PY_NETWORK_ESP_HOSTED
extern const struct _mp_obj_type_t mod_network_esp_hosted_type;
#endif
#ifdef MICROPY_PY_NETWORK_INCLUDEFILE
@@ -179,32 +166,6 @@ static const mp_rom_map_elem_t mp_module_network_globals_table[] = {
MICROPY_PORT_NETWORK_INTERFACES
#endif
#if MICROPY_PY_NETWORK_CYW43
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) },
// CYW43 status constants, currently for rp2 port only.
// TODO move these to WIFI module for all ports.
#if defined(PICO_PROGRAM_NAME) && defined(CYW43_LINK_DOWN)
{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(CYW43_LINK_DOWN) },
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(CYW43_LINK_JOIN) },
{ MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(CYW43_LINK_BADAUTH) },
{ MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(CYW43_LINK_NONET) },
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(CYW43_LINK_FAIL) },
{ MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(CYW43_LINK_UP) },
#endif
#endif
#if MICROPY_PY_NETWORK_WIZNET5K
{ MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
#endif
#if MICROPY_PY_NETWORK_NINAW10
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) },
#endif
#if MICROPY_PY_NETWORK_ESP_HOSTED
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_esp_hosted_type) },
#endif
// Allow a port to take mostly full control of the network module.
#ifdef MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE
#include MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE

View File

@@ -60,11 +60,6 @@ extern char mod_network_country_code[2];
#define MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN (32)
#endif
#if MICROPY_PY_NETWORK_NINAW10
// This Network interface requires the extended socket state.
#define MICROPY_PY_SOCKET_EXTENDED_STATE (1)
#endif
// This is a null-terminated string.
extern char mod_network_hostname_data[MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN + 1];
@@ -82,9 +77,6 @@ extern const struct _mp_obj_type_t mp_network_ppp_lwip_type;
#endif
struct netif;
void sys_untimeout_all_with_arg(void *arg);
void mod_network_lwip_init(void);
void mod_network_lwip_poll_wrapper(uint32_t ticks_ms);
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);

View File

@@ -427,9 +427,6 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
const char *re_str = mp_obj_str_get_str(args[0]);
int size = re1_5_sizecode(re_str);
if (size == -1) {
#if MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_NORMAL
mp_raise_ValueError(MP_ERROR_TEXT("regex too complex"));
#endif
goto error;
}
mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type);

View File

@@ -58,7 +58,7 @@ static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
return mp_time_localtime_get();
} else {
// Convert given seconds to tuple.
mp_timestamp_t seconds = timeutils_obj_get_timestamp(args[0]);
mp_int_t seconds = mp_obj_get_int(args[0]);
timeutils_struct_time_t tm;
timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
mp_obj_t tuple[8] = {
@@ -90,7 +90,7 @@ static mp_obj_t time_mktime(mp_obj_t tuple) {
mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
}
return timeutils_obj_from_timestamp(timeutils_mktime(mp_obj_get_int(elem[0]),
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
}

View File

@@ -105,7 +105,7 @@ static const char *const ssl_error_tab2[] = {
"NOT_SUPPORTED",
};
static MP_NORETURN void ssl_raise_error(int err) {
static NORETURN void ssl_raise_error(int err) {
MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN);
MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED);

View File

@@ -62,9 +62,6 @@
#include "mbedtls/ecdsa.h"
#include "mbedtls/asn1.h"
#endif
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
#include "mbedtls/ssl_cookie.h"
#endif
#ifndef MICROPY_MBEDTLS_CONFIG_BARE_METAL
#define MICROPY_MBEDTLS_CONFIG_BARE_METAL (0)
@@ -78,7 +75,7 @@
#define MP_PROTOCOL_TLS_CLIENT 0
#define MP_PROTOCOL_TLS_SERVER MP_ENDPOINT_IS_SERVER
#define MP_PROTOCOL_DTLS_CLIENT MP_TRANSPORT_IS_DTLS
#define MP_PROTOCOL_DTLS_SERVER (MP_ENDPOINT_IS_SERVER | MP_TRANSPORT_IS_DTLS)
#define MP_PROTOCOL_DTLS_SERVER MP_ENDPOINT_IS_SERVER | MP_TRANSPORT_IS_DTLS
// This corresponds to an SSLContext object.
typedef struct _mp_obj_ssl_context_t {
@@ -95,10 +92,6 @@ typedef struct _mp_obj_ssl_context_t {
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
mp_obj_t ecdsa_sign_callback;
#endif
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
bool is_dtls_server;
mbedtls_ssl_cookie_ctx cookie_ctx;
#endif
} mp_obj_ssl_context_t;
// This corresponds to an SSLSocket object.
@@ -124,8 +117,7 @@ static const mp_obj_type_t ssl_socket_type;
static const MP_DEFINE_STR_OBJ(mbedtls_version_obj, MBEDTLS_VERSION_STRING_FULL);
static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname,
mp_obj_t client_id);
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname);
/******************************************************************************/
// Helper functions.
@@ -155,7 +147,7 @@ static const unsigned char *asn1_get_data(mp_obj_t obj, size_t *out_len) {
return (const unsigned char *)str;
}
static MP_NORETURN void mbedtls_raise_error(int err) {
static NORETURN void mbedtls_raise_error(int err) {
// Handle special cases.
if (err == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
mp_raise_OSError(MP_ENOMEM);
@@ -328,19 +320,6 @@ static mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
mbedtls_ssl_conf_dbg(&self->conf, mbedtls_debug, NULL);
#endif
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
self->is_dtls_server = (protocol == MP_PROTOCOL_DTLS_SERVER);
if (self->is_dtls_server) {
mbedtls_ssl_cookie_init(&self->cookie_ctx);
ret = mbedtls_ssl_cookie_setup(&self->cookie_ctx, mbedtls_ctr_drbg_random, &self->ctr_drbg);
if (ret != 0) {
mbedtls_raise_error(ret);
}
mbedtls_ssl_conf_dtls_cookies(&self->conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check,
&self->cookie_ctx);
}
#endif // MBEDTLS_SSL_DTLS_HELLO_VERIFY
return MP_OBJ_FROM_PTR(self);
}
@@ -387,11 +366,6 @@ static mp_obj_t ssl_context___del__(mp_obj_t self_in) {
mbedtls_ctr_drbg_free(&self->ctr_drbg);
mbedtls_entropy_free(&self->entropy);
mbedtls_ssl_config_free(&self->conf);
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
if (self->is_dtls_server) {
mbedtls_ssl_cookie_free(&self->cookie_ctx);
}
#endif
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(ssl_context___del___obj, ssl_context___del__);
@@ -494,14 +468,11 @@ static mp_obj_t ssl_context_load_verify_locations(mp_obj_t self_in, mp_obj_t cad
static MP_DEFINE_CONST_FUN_OBJ_2(ssl_context_load_verify_locations_obj, ssl_context_load_verify_locations);
static mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname, ARG_client_id };
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_do_handshake_on_connect, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
{ MP_QSTR_client_id, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
#endif
};
// Parse arguments.
@@ -510,14 +481,9 @@ static mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args,
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t client_id = mp_const_none;
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
client_id = args[ARG_client_id].u_obj;
#endif
// Create and return the new SSLSocket object.
return ssl_socket_make_new(self, sock, args[ARG_server_side].u_bool,
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj, client_id);
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj);
}
static MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_wrap_socket_obj, 2, ssl_context_wrap_socket);
@@ -614,7 +580,7 @@ static int _mbedtls_timing_get_delay(void *ctx) {
#endif
static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname, mp_obj_t client_id) {
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname) {
// Store the current SSL context.
store_active_context(ssl_context);
@@ -639,7 +605,7 @@ static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
ret = mbedtls_ssl_setup(&o->ssl, &ssl_context->conf);
#if !MICROPY_MBEDTLS_CONFIG_BARE_METAL
if (ret != 0) {
if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
// If mbedTLS relies on platform libc heap for buffers (i.e. esp32
// port), then run a GC pass and then try again. This is useful because
// it may free a Python object (like an old SSL socket) whose finaliser
@@ -669,20 +635,6 @@ static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
mbedtls_ssl_set_timer_cb(&o->ssl, o, _mbedtls_timing_set_delay, _mbedtls_timing_get_delay);
#endif
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
if (ssl_context->is_dtls_server) {
// require the client_id parameter for DTLS (as per mbedTLS requirement)
ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
mp_buffer_info_t buf;
if (mp_get_buffer(client_id, &buf, MP_BUFFER_READ)) {
ret = mbedtls_ssl_set_client_transport_id(&o->ssl, buf.buf, buf.len);
}
if (ret != 0) {
goto cleanup;
}
}
#endif
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
if (do_handshake_on_connect) {

View File

@@ -89,7 +89,7 @@ typedef struct _mp_obj_uctypes_struct_t {
uint32_t flags;
} mp_obj_uctypes_struct_t;
static MP_NORETURN void syntax_error(void) {
static NORETURN void syntax_error(void) {
mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor"));
}

View File

@@ -27,10 +27,6 @@
#ifndef MICROPY_INCLUDED_EXTMOD_MPBTHCI_H
#define MICROPY_INCLUDED_EXTMOD_MPBTHCI_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#define MICROPY_PY_BLUETOOTH_HCI_READ_MODE_BYTE (0)
#define MICROPY_PY_BLUETOOTH_HCI_READ_MODE_PACKET (1)

View File

@@ -143,9 +143,6 @@ static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) {
return mp_obj_new_bool(if_active[self->itf]);
} else {
bool value = mp_obj_is_true(args[1]);
if (!value && self->itf == CYW43_ITF_STA) {
cyw43_wifi_leave(self->cyw, self->itf);
}
cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code());
if_active[self->itf] = value;
return mp_const_none;

View File

@@ -48,8 +48,6 @@
#include "esp_hosted_wifi.h"
#include "esp_hosted_hal.h"
extern const mp_obj_type_t mod_network_esp_hosted_type;
typedef struct _esp_hosted_obj_t {
mp_obj_base_t base;
uint32_t itf;

View File

@@ -52,19 +52,6 @@ int mp_mod_network_prefer_dns_use_ip_version = 4;
// Implementations of network methods that can be used by any interface.
// This follows sys_untimeout but removes all timeouts with the given argument.
void sys_untimeout_all_with_arg(void *arg) {
for (struct sys_timeo **t = sys_timeouts_get_next_timeout(); *t != NULL;) {
if ((*t)->arg == arg) {
struct sys_timeo *next = (*t)->next;
memp_free(MEMP_SYS_TIMEOUT, *t);
*t = next;
} else {
t = &(*t)->next;
}
}
}
// This function provides the implementation of nic.ifconfig, is deprecated and will be removed.
// Use network.ipconfig and nic.ipconfig instead.
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) {

View File

@@ -24,10 +24,6 @@
* THE SOFTWARE.
*/
// This file is intended to closely match ports/esp32/network_ppp.c. Changes can
// and should probably be applied to both files. Compare them directly by using:
// git diff --no-index extmod/network_ppp_lwip.c ports/esp32/network_ppp.c
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/stream.h"
@@ -84,6 +80,7 @@ static void network_ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
break;
case PPPERR_USER:
if (self->state >= STATE_ERROR) {
network_ppp_stream_uart_irq_disable(self);
// Indicate that we are no longer connected and thus
// only need to free the PPP PCB, not close it.
self->state = STATE_ACTIVE;
@@ -124,7 +121,6 @@ static mp_obj_t network_ppp___del__(mp_obj_t self_in) {
self->state = STATE_INACTIVE;
ppp_close(self->pcb, 1);
}
network_ppp_stream_uart_irq_disable(self);
// Free PPP PCB and reset state.
self->state = STATE_INACTIVE;
ppp_free(self->pcb);
@@ -299,8 +295,7 @@ static mp_obj_t network_ppp_connect(size_t n_args, const mp_obj_t *args, mp_map_
ppp_set_auth(self->pcb, parsed_args[ARG_security].u_int, user_str, key_str);
}
ppp_set_default(self->pcb);
netif_set_default(self->pcb->netif);
ppp_set_usepeerdns(self->pcb, true);
if (ppp_connect(self->pcb, 0) != ERR_OK) {

View File

@@ -78,8 +78,6 @@
#endif
extern const mp_obj_type_t mod_network_nic_type_wiznet5k;
#ifndef printf
#define printf(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__)
#endif

View File

@@ -60,7 +60,6 @@
static uint8_t nimble_address_mode = BLE_OWN_ADDR_RANDOM;
#define NIMBLE_STARTUP_TIMEOUT 2000
#define NIMBLE_SHUTDOWN_TIMEOUT 500
// Any BLE_HS_xxx code not in this table will default to MP_EIO.
static int8_t ble_hs_err_to_errno_table[] = {
@@ -555,7 +554,7 @@ static void ble_hs_shutdown_stop_cb(int status, void *arg) {
static struct ble_hs_stop_listener ble_hs_shutdown_stop_listener;
int mp_bluetooth_nimble_port_shutdown(void) {
void mp_bluetooth_nimble_port_shutdown(void) {
DEBUG_printf("mp_bluetooth_nimble_port_shutdown (nimble default)\n");
// By default, just call ble_hs_stop directly and wait for the stack to stop.
@@ -563,17 +562,9 @@ int mp_bluetooth_nimble_port_shutdown(void) {
ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, NULL);
mp_uint_t timeout_start_ticks_ms = mp_hal_ticks_ms();
while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
mp_uint_t elapsed = mp_hal_ticks_ms() - timeout_start_ticks_ms;
if (elapsed > NIMBLE_SHUTDOWN_TIMEOUT) {
// Stack had not responded (via ble_hs_shutdown_stop_cb)
return MP_ETIMEDOUT;
}
mp_event_wait_ms(NIMBLE_SHUTDOWN_TIMEOUT - elapsed);
mp_event_wait_indefinite();
}
return 0;
}
#endif // !MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY
@@ -668,11 +659,10 @@ int mp_bluetooth_init(void) {
return 0;
}
int mp_bluetooth_deinit(void) {
void mp_bluetooth_deinit(void) {
DEBUG_printf("mp_bluetooth_deinit %d\n", mp_bluetooth_nimble_ble_state);
int ret = 0;
if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
return 0;
return;
}
// Must call ble_hs_stop() in a port-specific way to stop the background
@@ -685,7 +675,7 @@ int mp_bluetooth_deinit(void) {
DEBUG_printf("mp_bluetooth_deinit: starting port shutdown\n");
ret = mp_bluetooth_nimble_port_shutdown();
mp_bluetooth_nimble_port_shutdown();
assert(mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF);
} else {
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF;
@@ -702,7 +692,6 @@ int mp_bluetooth_deinit(void) {
#endif
DEBUG_printf("mp_bluetooth_deinit: shut down\n");
return ret;
}
bool mp_bluetooth_is_active(void) {

View File

@@ -84,7 +84,7 @@ void mp_bluetooth_nimble_port_hci_deinit(void);
void mp_bluetooth_nimble_port_start(void);
// Tell the port to stop its background task.
int mp_bluetooth_nimble_port_shutdown(void);
void mp_bluetooth_nimble_port_shutdown(void);
// --- Called by the HCI UART layer to let us know when packets have been sent.
void mp_bluetooth_nimble_sent_hci_packet(void);

View File

@@ -326,7 +326,7 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
} else {
mode |= MP_S_IFREG;
}
mp_timestamp_t seconds = timeutils_seconds_since_epoch(
mp_int_t seconds = timeutils_seconds_since_epoch(
1980 + ((fno.fdate >> 9) & 0x7f),
(fno.fdate >> 5) & 0x0f,
fno.fdate & 0x1f,
@@ -341,9 +341,9 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size
t->items[7] = timeutils_obj_from_timestamp(seconds); // st_atime
t->items[8] = timeutils_obj_from_timestamp(seconds); // st_mtime
t->items[9] = timeutils_obj_from_timestamp(seconds); // st_ctime
t->items[7] = mp_obj_new_int_from_uint(seconds); // st_atime
t->items[8] = mp_obj_new_int_from_uint(seconds); // st_mtime
t->items[9] = mp_obj_new_int_from_uint(seconds); // st_ctime
return MP_OBJ_FROM_PTR(t);
}

View File

@@ -104,12 +104,6 @@ static void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx * self, mp_obj_t bdev, size
config->read_buffer = m_new(uint8_t, config->cache_size);
config->prog_buffer = m_new(uint8_t, config->cache_size);
config->lookahead_buffer = m_new(uint8_t, config->lookahead_size);
#ifdef LFS2_MULTIVERSION
// This can be set to override the on-disk lfs version.
// eg. for compat with lfs2 < v2.6 add the following to make:
// CFLAGS += '-DLFS2_MULTIVERSION=0x00020000'
config->disk_version = LFS2_MULTIVERSION;
#endif
#endif
}
@@ -306,7 +300,7 @@ static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
struct LFSx_API (info) info;
int ret = LFSx_API(stat)(&self->lfs, path, &info);
if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) {
mp_raise_OSError(MP_ENOENT);
mp_raise_OSError(-MP_ENOENT);
}
}
@@ -384,7 +378,7 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
mp_raise_OSError(-ret);
}
mp_timestamp_t mtime = 0;
mp_uint_t mtime = 0;
#if LFS_BUILD_VERSION == 2
uint8_t mtime_buf[8];
lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
@@ -406,9 +400,9 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
t->items[7] = timeutils_obj_from_timestamp(mtime); // st_atime
t->items[8] = timeutils_obj_from_timestamp(mtime); // st_mtime
t->items[9] = timeutils_obj_from_timestamp(mtime); // st_ctime
t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
return MP_OBJ_FROM_PTR(t);
}

View File

@@ -137,7 +137,7 @@ static mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, siz
vstr_add_char(&vfs->root, '/');
}
vfs->root_len = vfs->root.len;
vfs->readonly = !MICROPY_VFS_POSIX_WRITABLE;
vfs->readonly = false;
return MP_OBJ_FROM_PTR(vfs);
}
@@ -160,21 +160,10 @@ static mp_obj_t vfs_posix_umount(mp_obj_t self_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount);
static inline bool vfs_posix_is_readonly(mp_obj_vfs_posix_t *self) {
return !MICROPY_VFS_POSIX_WRITABLE || self->readonly;
}
static void vfs_posix_require_writable(mp_obj_t self_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
if (vfs_posix_is_readonly(self)) {
mp_raise_OSError(MP_EROFS);
}
}
static mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *mode = mp_obj_str_get_str(mode_in);
if (vfs_posix_is_readonly(self)
if (self->readonly
&& (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) {
mp_raise_OSError(MP_EROFS);
}
@@ -314,7 +303,6 @@ typedef struct _mp_obj_listdir_t {
} mp_obj_listdir_t;
static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
vfs_posix_require_writable(self_in);
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *path = vfs_posix_get_path_str(self, path_in);
MP_THREAD_GIL_EXIT();
@@ -332,13 +320,11 @@ static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir);
static mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) {
vfs_posix_require_writable(self_in);
return vfs_posix_fun1_helper(self_in, path_in, unlink);
}
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove);
static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
vfs_posix_require_writable(self_in);
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
@@ -353,7 +339,6 @@ static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_
static MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);
static mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) {
vfs_posix_require_writable(self_in);
return vfs_posix_fun1_helper(self_in, path_in, rmdir);
}
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);

View File

@@ -2,7 +2,7 @@
#include <math.h>
#include <stdint.h>
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 || FLT_EVAL_METHOD==16
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
#define EPS DBL_EPSILON
#elif FLT_EVAL_METHOD==2
#define EPS LDBL_EPSILON

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ extern "C"
// Software library version
// Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions
#define LFS2_VERSION 0x0002000b
#define LFS2_VERSION 0x00020008
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
@@ -52,15 +52,16 @@ typedef uint32_t lfs2_block_t;
#endif
// Maximum size of a file in bytes, may be redefined to limit to support other
// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be
// respected by other littlefs drivers.
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return
// incorrect values due to using signed integers. Stored in superblock and
// must be respected by other littlefs drivers.
#ifndef LFS2_FILE_MAX
#define LFS2_FILE_MAX 2147483647
#endif
// Maximum size of custom attributes in bytes, may be redefined, but there is
// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. Stored
// in superblock and must be respected by other littlefs drivers.
// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022.
#ifndef LFS2_ATTR_MAX
#define LFS2_ATTR_MAX 1022
#endif
@@ -204,8 +205,7 @@ struct lfs2_config {
// program sizes.
lfs2_size_t block_size;
// Number of erasable blocks on the device. Defaults to block_count stored
// on disk when zero.
// Number of erasable blocks on the device.
lfs2_size_t block_count;
// Number of erase cycles before littlefs evicts metadata logs and moves
@@ -226,20 +226,9 @@ struct lfs2_config {
// Size of the lookahead buffer in bytes. A larger lookahead buffer
// increases the number of blocks found during an allocation pass. The
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
// can track 8 blocks.
// can track 8 blocks. Must be a multiple of 8.
lfs2_size_t lookahead_size;
// Threshold for metadata compaction during lfs2_fs_gc in bytes. Metadata
// pairs that exceed this threshold will be compacted during lfs2_fs_gc.
// Defaults to ~88% block_size when zero, though the default may change
// in the future.
//
// Note this only affects lfs2_fs_gc. Normal compactions still only occur
// when full.
//
// Set to -1 to disable metadata compaction during lfs2_fs_gc.
lfs2_size_t compact_thresh;
// Optional statically allocated read buffer. Must be cache_size.
// By default lfs2_malloc is used to allocate this buffer.
void *read_buffer;
@@ -248,24 +237,25 @@ struct lfs2_config {
// By default lfs2_malloc is used to allocate this buffer.
void *prog_buffer;
// Optional statically allocated lookahead buffer. Must be lookahead_size.
// By default lfs2_malloc is used to allocate this buffer.
// Optional statically allocated lookahead buffer. Must be lookahead_size
// and aligned to a 32-bit boundary. By default lfs2_malloc is used to
// allocate this buffer.
void *lookahead_buffer;
// Optional upper limit on length of file names in bytes. No downside for
// larger names except the size of the info struct which is controlled by
// the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX or name_max stored on
// disk when zero.
// the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in
// superblock and must be respected by other littlefs drivers.
lfs2_size_t name_max;
// Optional upper limit on files in bytes. No downside for larger files
// but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX or file_max stored
// on disk when zero.
// but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored
// in superblock and must be respected by other littlefs drivers.
lfs2_size_t file_max;
// Optional upper limit on custom attributes in bytes. No downside for
// larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to
// LFS2_ATTR_MAX or attr_max stored on disk when zero.
// LFS2_ATTR_MAX when zero.
lfs2_size_t attr_max;
// Optional upper limit on total space given to metadata pairs in bytes. On
@@ -274,15 +264,6 @@ struct lfs2_config {
// Defaults to block_size when zero.
lfs2_size_t metadata_max;
// Optional upper limit on inlined files in bytes. Inlined files live in
// metadata and decrease storage requirements, but may be limited to
// improve metadata-related performance. Must be <= cache_size, <=
// attr_max, and <= block_size/8. Defaults to the largest possible
// inline_max when zero.
//
// Set to -1 to disable inlined files.
lfs2_size_t inline_max;
#ifdef LFS2_MULTIVERSION
// On-disk version to use when writing in the form of 16-bit major version
// + 16-bit minor version. This limiting metadata to what is supported by
@@ -449,20 +430,19 @@ typedef struct lfs2 {
lfs2_gstate_t gdisk;
lfs2_gstate_t gdelta;
struct lfs2_lookahead {
lfs2_block_t start;
struct lfs2_free {
lfs2_block_t off;
lfs2_block_t size;
lfs2_block_t next;
lfs2_block_t ckpoint;
uint8_t *buffer;
} lookahead;
lfs2_block_t i;
lfs2_block_t ack;
uint32_t *buffer;
} free;
const struct lfs2_config *cfg;
lfs2_size_t block_count;
lfs2_size_t name_max;
lfs2_size_t file_max;
lfs2_size_t attr_max;
lfs2_size_t inline_max;
#ifdef LFS2_MIGRATE
struct lfs21 *lfs21;
@@ -732,6 +712,18 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
// Returns a negative error code on failure.
int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
// Attempt to proactively find free blocks
//
// Calling this function is not required, but may allowing the offloading of
// the expensive block allocation scan to a less time-critical code path.
//
// Note: littlefs currently does not persist any found free blocks to disk.
// This may change in the future.
//
// Returns a negative error code on failure. Finding no free blocks is
// not an error.
int lfs2_fs_gc(lfs2_t *lfs2);
#ifndef LFS2_READONLY
// Attempt to make the filesystem consistent and ready for writing
//
@@ -744,33 +736,11 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
int lfs2_fs_mkconsistent(lfs2_t *lfs2);
#endif
#ifndef LFS2_READONLY
// Attempt any janitorial work
//
// This currently:
// 1. Calls mkconsistent if not already consistent
// 2. Compacts metadata > compact_thresh
// 3. Populates the block allocator
//
// Though additional janitorial work may be added in the future.
//
// Calling this function is not required, but may allow the offloading of
// expensive janitorial work to a less time-critical code path.
//
// Returns a negative error code on failure. Accomplishing nothing is not
// an error.
int lfs2_fs_gc(lfs2_t *lfs2);
#endif
#ifndef LFS2_READONLY
// Grows the filesystem to a new size, updating the superblock with the new
// block count.
//
// If LFS2_SHRINKNONRELOCATING is defined, this function will also accept
// block_counts smaller than the current configuration, after checking
// that none of the blocks that are being removed are in use.
// Note that littlefs's pseudorandom block allocation means that
// this is very unlikely to work in the general case.
// Note: This is irreversible.
//
// Returns a negative error code on failure.
int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count);

View File

@@ -11,8 +11,6 @@
#ifndef LFS2_CONFIG
// If user provides their own CRC impl we don't need this
#ifndef LFS2_CRC
// Software CRC implementation with small lookup table
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
@@ -31,7 +29,6 @@ uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
return crc;
}
#endif
#endif

View File

@@ -8,9 +8,6 @@
#ifndef LFS2_UTIL_H
#define LFS2_UTIL_H
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
#define LFS2_STRINGIZE2(x) #x
// Users can override lfs2_util.h with their own configuration by defining
// LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h).
//
@@ -18,26 +15,11 @@
// provided by the config file. To start, I would suggest copying lfs2_util.h
// and modifying as needed.
#ifdef LFS2_CONFIG
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
#define LFS2_STRINGIZE2(x) #x
#include LFS2_STRINGIZE(LFS2_CONFIG)
#else
// Alternatively, users can provide a header file which defines
// macros and other things consumed by littlefs.
//
// For example, provide my_defines.h, which contains
// something like:
//
// #include <stddef.h>
// extern void *my_malloc(size_t sz);
// #define LFS2_MALLOC(sz) my_malloc(sz)
//
// And build littlefs with the header by defining LFS2_DEFINES.
// (-DLFS2_DEFINES=my_defines.h)
#ifdef LFS2_DEFINES
#include LFS2_STRINGIZE(LFS2_DEFINES)
#endif
// System includes
#include <stdint.h>
#include <stdbool.h>
@@ -195,10 +177,10 @@ static inline uint32_t lfs2_fromle32(uint32_t a) {
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
return __builtin_bswap32(a);
#else
return ((uint32_t)((uint8_t*)&a)[0] << 0) |
((uint32_t)((uint8_t*)&a)[1] << 8) |
((uint32_t)((uint8_t*)&a)[2] << 16) |
((uint32_t)((uint8_t*)&a)[3] << 24);
return (((uint8_t*)&a)[0] << 0) |
(((uint8_t*)&a)[1] << 8) |
(((uint8_t*)&a)[2] << 16) |
(((uint8_t*)&a)[3] << 24);
#endif
}
@@ -218,10 +200,10 @@ static inline uint32_t lfs2_frombe32(uint32_t a) {
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return a;
#else
return ((uint32_t)((uint8_t*)&a)[0] << 24) |
((uint32_t)((uint8_t*)&a)[1] << 16) |
((uint32_t)((uint8_t*)&a)[2] << 8) |
((uint32_t)((uint8_t*)&a)[3] << 0);
return (((uint8_t*)&a)[0] << 24) |
(((uint8_t*)&a)[1] << 16) |
(((uint8_t*)&a)[2] << 8) |
(((uint8_t*)&a)[3] << 0);
#endif
}
@@ -230,22 +212,12 @@ static inline uint32_t lfs2_tobe32(uint32_t a) {
}
// Calculate CRC-32 with polynomial = 0x04c11db7
#ifdef LFS2_CRC
static inline uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
return LFS2_CRC(crc, buffer, size);
}
#else
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size);
#endif
// Allocate memory, only used if buffers are not provided to littlefs
//
// littlefs current has no alignment requirements, as it only allocates
// byte-level buffers.
// Note, memory must be 64-bit aligned
static inline void *lfs2_malloc(size_t size) {
#if defined(LFS2_MALLOC)
return LFS2_MALLOC(size);
#elif !defined(LFS2_NO_MALLOC)
#ifndef LFS2_NO_MALLOC
return malloc(size);
#else
(void)size;
@@ -255,9 +227,7 @@ static inline void *lfs2_malloc(size_t size) {
// Deallocate memory, only used if buffers are not provided to littlefs
static inline void lfs2_free(void *p) {
#if defined(LFS2_FREE)
LFS2_FREE(p);
#elif !defined(LFS2_NO_MALLOC)
#ifndef LFS2_NO_MALLOC
free(p);
#else
(void)p;

Some files were not shown because too many files have changed in this diff Show More