Merge tag 'v1.16'
This commit is contained in:
commit
87d3740c64
|
@ -1,3 +1,6 @@
|
|||
# tools/gen-cpydiff.py: Fix formatting of doc strings for new Black.
|
||||
0f78c36c5aa458a954eed39a46942209107a553e
|
||||
|
||||
# tests/run-tests.py: Reformat with Black.
|
||||
2a38d7103672580882fb621a5b76e8d26805d593
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
name: mimxrt port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/mimxrt/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_mimxrt_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_mimxrt_build
|
|
@ -0,0 +1,93 @@
|
|||
.. _ssd1306:
|
||||
|
||||
Using a SSD1306 OLED display
|
||||
============================
|
||||
|
||||
The SSD1306 OLED display uses either a SPI or I2C interface and comes in a variety of
|
||||
sizes (128x64, 128x32, 72x40, 64x48) and colours (white, yellow, blue, yellow + blue).
|
||||
|
||||
Hardware SPI interface::
|
||||
|
||||
from machine import Pin, SPI
|
||||
import ssd1306
|
||||
|
||||
hspi = SPI(1) # sck=14 (scl), mosi=13 (sda), miso=12 (unused)
|
||||
|
||||
dc = Pin(4) # data/command
|
||||
rst = Pin(5) # reset
|
||||
cs = Pin(15) # chip select, some modules do not have a pin for this
|
||||
|
||||
display = ssd1306.SSD1306_SPI(128, 64, hspi, dc, rst, cs)
|
||||
|
||||
Software SPI interface::
|
||||
|
||||
from machine import Pin, SoftSPI
|
||||
import ssd1306
|
||||
|
||||
spi = SoftSPI(baudrate=500000, polarity=1, phase=0, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
|
||||
|
||||
dc = Pin(4) # data/command
|
||||
rst = Pin(5) # reset
|
||||
cs = Pin(15) # chip select, some modules do not have a pin for this
|
||||
|
||||
display = ssd1306.SSD1306_SPI(128, 64, spi, dc, rst, cs)
|
||||
|
||||
I2C interface::
|
||||
|
||||
from machine import Pin, I2C
|
||||
import ssd1306
|
||||
|
||||
# using default address 0x3C
|
||||
i2c = I2C(sda=Pin(4), scl=Pin(5))
|
||||
display = ssd1306.SSD1306_I2C(128, 64, i2c)
|
||||
|
||||
Print Hello World on the first line::
|
||||
|
||||
display.text('Hello, World!', 0, 0, 1)
|
||||
display.show()
|
||||
|
||||
Basic functions::
|
||||
|
||||
display.poweroff() # power off the display, pixels persist in memory
|
||||
display.poweron() # power on the display, pixels redrawn
|
||||
display.contrast(0) # dim
|
||||
display.contrast(255) # bright
|
||||
display.invert(1) # display inverted
|
||||
display.invert(0) # display normal
|
||||
display.rotate(True) # rotate 180 degrees
|
||||
display.rotate(False) # rotate 0 degrees
|
||||
display.show() # write the contents of the FrameBuffer to display memory
|
||||
|
||||
Subclassing FrameBuffer provides support for graphics primitives::
|
||||
|
||||
display.fill(0) # fill entire screen with colour=0
|
||||
display.pixel(0, 10) # get pixel at x=0, y=10
|
||||
display.pixel(0, 10, 1) # set pixel at x=0, y=10 to colour=1
|
||||
display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1
|
||||
display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1
|
||||
display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63
|
||||
display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 107,43, colour=1
|
||||
display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 107,43, colour=1
|
||||
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1
|
||||
display.scroll(20, 0) # scroll 20 pixels to the right
|
||||
|
||||
# draw another FrameBuffer on top of the current one at the given coordinates
|
||||
import framebuf
|
||||
fbuf = framebuf.FrameBuffer(bytearray(8 * 8 * 1), 8, 8, framebuf.MONO_VLSB)
|
||||
fbuf.line(0, 0, 7, 7, 1)
|
||||
display.blit(fbuf, 10, 10, 0) # draw on top at x=10, y=10, key=0
|
||||
display.show()
|
||||
|
||||
Draw the MicroPython logo and print some text::
|
||||
|
||||
display.fill(0)
|
||||
display.fill_rect(0, 0, 32, 32, 1)
|
||||
display.fill_rect(2, 2, 28, 28, 0)
|
||||
display.vline(9, 8, 22, 1)
|
||||
display.vline(16, 2, 22, 1)
|
||||
display.vline(23, 8, 22, 1)
|
||||
display.fill_rect(26, 24, 2, 4, 1)
|
||||
display.text('MicroPython', 40, 0, 1)
|
||||
display.text('SSD1306', 40, 12, 1)
|
||||
display.text('OLED 128x64', 40, 24, 1)
|
||||
display.show()
|
|
@ -182,10 +182,6 @@ Exceptions
|
|||
|
||||
.. exception:: OSError
|
||||
|
||||
|see_cpython| :py:class:`cpython:OSError`. CircuitPython doesn't implement the ``errno``
|
||||
attribute, instead use the standard way to access exception arguments:
|
||||
``exc.args[0]``.
|
||||
|
||||
.. exception:: RuntimeError
|
||||
|
||||
.. exception:: ReloadException
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
.. currentmodule:: machine
|
||||
.. _machine.PWM:
|
||||
|
||||
class PWM -- pulse width modulation
|
||||
===================================
|
||||
|
||||
This class provides pulse width modulation output.
|
||||
|
||||
Example usage::
|
||||
|
||||
from machine import PWM
|
||||
|
||||
pwm = PWM(pin) # create a PWM object on a pin
|
||||
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.deinit()
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: PWM(dest, \*, freq, duty_u16, duty_ns)
|
||||
|
||||
Construct and return a new PWM object using the following parameters:
|
||||
|
||||
- *dest* is the entity on which the PWM is output, which is usually a
|
||||
:ref:`machine.Pin <machine.Pin>` object, but a port may allow other values,
|
||||
like integers.
|
||||
- *freq* should be an integer which sets the frequency in Hz for the
|
||||
PWM cycle.
|
||||
- *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``.
|
||||
- *duty_ns* sets the pulse width in nanoseconds.
|
||||
|
||||
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.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: PWM.init(\*, freq, duty_u16, duty_ns)
|
||||
|
||||
Modify settings for the PWM object. See the above constructor for details
|
||||
about the parameters.
|
||||
|
||||
.. method:: PWM.deinit()
|
||||
|
||||
Disable the PWM output.
|
||||
|
||||
.. method:: PWM.freq([value])
|
||||
|
||||
Get or set the current frequency of the PWM output.
|
||||
|
||||
With no arguments the frequency in Hz is returned.
|
||||
|
||||
With a single *value* argument the frequency is set to that value in Hz. The
|
||||
method may raise a ``ValueError`` if the frequency is outside the valid range.
|
||||
|
||||
.. method:: PWM.duty_u16([value])
|
||||
|
||||
Get or set the current duty cycle of the PWM output, as an unsigned 16-bit
|
||||
value in the range 0 to 65535 inclusive.
|
||||
|
||||
With no arguments the duty cycle is returned.
|
||||
|
||||
With a single *value* argument the duty cycle is set to that value, measured
|
||||
as the ratio ``value / 65535``.
|
||||
|
||||
.. method:: PWM.duty_ns([value])
|
||||
|
||||
Get or set the current pulse width of the PWM output, as a value in nanoseconds.
|
||||
|
||||
With no arguments the pulse width in nanoseconds is returned.
|
||||
|
||||
With a single *value* argument the pulse width is set to that value.
|
|
@ -0,0 +1,36 @@
|
|||
.. currentmodule:: rp2
|
||||
.. _rp2.Flash:
|
||||
|
||||
class Flash -- access to built-in flash storage
|
||||
===============================================
|
||||
|
||||
This class gives access to the SPI flash memory.
|
||||
|
||||
In most cases, to store persistent data on the device, you'll want to use a
|
||||
higher-level abstraction, for example the filesystem via Python's standard file
|
||||
API, but this interface is useful to :ref:`customise the filesystem
|
||||
configuration <filesystem>` or implement a low-level storage system for your
|
||||
application.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: Flash()
|
||||
|
||||
Gets the singleton object for accessing the SPI flash memory.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Flash.readblocks(block_num, buf)
|
||||
Flash.readblocks(block_num, buf, offset)
|
||||
.. method:: Flash.writeblocks(block_num, buf)
|
||||
Flash.writeblocks(block_num, buf, offset)
|
||||
.. method:: Flash.ioctl(cmd, arg)
|
||||
|
||||
These methods implement the simple and extended
|
||||
:ref:`block protocol <block-device-interface>` defined by
|
||||
:class:`uos.AbstractBlockDev`.
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
.. currentmodule:: rp2
|
||||
.. _rp2.PIO:
|
||||
|
||||
class PIO -- advanced PIO usage
|
||||
===============================
|
||||
|
||||
The :class:`PIO` class gives access to an instance of the RP2040's PIO
|
||||
(programmable I/O) interface.
|
||||
|
||||
The preferred way to interact with PIO is using :class:`rp2.StateMachine`, the
|
||||
PIO class is for advanced use.
|
||||
|
||||
For assembling PIO programs, see :func:`rp2.asm_pio`.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: PIO(id)
|
||||
|
||||
Gets the PIO instance numbered *id*. The RP2040 has two PIO instances,
|
||||
numbered 0 and 1.
|
||||
|
||||
Raises a ``ValueError`` if any other argument is provided.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: PIO.add_program(program)
|
||||
|
||||
Add the *program* to the instruction memory of this PIO instance.
|
||||
|
||||
The amount of memory available for programs on each PIO instance is
|
||||
limited. If there isn't enough space left in the PIO's program memory
|
||||
this method will raise ``OSError(ENOMEM)``.
|
||||
|
||||
.. method:: PIO.remove_program([program])
|
||||
|
||||
Remove *program* from the instruction memory of this PIO instance.
|
||||
|
||||
If no program is provided, it removes all programs.
|
||||
|
||||
It is not an error to remove a program which has already been removed.
|
||||
|
||||
.. method:: PIO.state_machine(id, [program, ...])
|
||||
|
||||
Gets the state machine numbered *id*. On the RP2040, each PIO instance has
|
||||
four state machines, numbered 0 to 3.
|
||||
|
||||
Optionally initialize it with a *program*: see `StateMachine.init`.
|
||||
|
||||
>>> rp2.PIO(1).state_machine(3)
|
||||
StateMachine(7)
|
||||
|
||||
.. method:: PIO.irq(handler=None, trigger=IRQ_SM0|IRQ_SM1|IRQ_SM2|IRQ_SM3, hard=False)
|
||||
|
||||
Returns the IRQ object for this PIO instance.
|
||||
|
||||
MicroPython only uses IRQ 0 on each PIO instance. IRQ 1 is not available.
|
||||
|
||||
Optionally configure it.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: PIO.IN_LOW
|
||||
PIO.IN_HIGH
|
||||
PIO.OUT_LOW
|
||||
PIO.OUT_HIGH
|
||||
|
||||
These constants are used for the *out_init*, *set_init*, and *sideset_init*
|
||||
arguments to `asm_pio`.
|
||||
|
||||
.. data:: PIO.SHIFT_LEFT
|
||||
PIO.SHIFT_RIGHT
|
||||
|
||||
These constants are used for the *in_shiftdir* and *out_shiftdir* arguments
|
||||
to `asm_pio` or `StateMachine.init`.
|
||||
|
||||
.. data:: PIO.JOIN_NONE
|
||||
PIO.JOIN_TX
|
||||
PIO.JOIN_RX
|
||||
|
||||
These constants are used for the *fifo_join* argument to `asm_pio`.
|
||||
|
||||
.. data:: PIO.IRQ_SM0
|
||||
PIO.IRQ_SM1
|
||||
PIO.IRQ_SM2
|
||||
PIO.IRQ_SM3
|
||||
|
||||
These constants are used for the *trigger* argument to `PIO.irq`.
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
.. currentmodule:: rp2
|
||||
.. _rp2.StateMachine:
|
||||
|
||||
class StateMachine -- access to the RP2040's programmable I/O interface
|
||||
=======================================================================
|
||||
|
||||
The :class:`StateMachine` class gives access to the RP2040's PIO (programmable
|
||||
I/O) interface.
|
||||
|
||||
For assembling PIO programs, see :func:`rp2.asm_pio`.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: StateMachine(id, [program, ...])
|
||||
|
||||
Get the state machine numbered *id*. The RP2040 has two identical PIO
|
||||
instances, each with 4 state machines: so there are 8 state machines in
|
||||
total, numbered 0 to 7.
|
||||
|
||||
Optionally initialize it with the given program *program*: see
|
||||
`StateMachine.init`.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: StateMachine.init(program, freq=-1, *, in_base=None, out_base=None, set_base=None, jmp_pin=None, sideset_base=None, in_shiftdir=None, out_shiftdir=None, push_thresh=None, pull_thresh=None)
|
||||
|
||||
Configure the state machine instance to run the given *program*.
|
||||
|
||||
The program is added to the instruction memory of this PIO instance. If the
|
||||
instruction memory already contains this program, then its offset is
|
||||
re-used so as to save on instruction memory.
|
||||
|
||||
- *freq* is the frequency in Hz to run the state machine at. Defaults to
|
||||
the system clock frequency.
|
||||
|
||||
The clock divider is computed as ``system clock frequency / freq``, so
|
||||
there can be slight rounding errors.
|
||||
|
||||
The minimum possible clock divider is one 65536th of the system clock: so
|
||||
at the default system clock frequency of 125MHz, the minimum value of
|
||||
*freq* is ``1908``. To run state machines at slower frequencies, you'll
|
||||
need to reduce the system clock speed with `machine.freq()`.
|
||||
- *in_base* is the first pin to use for ``in()`` instructions.
|
||||
- *out_base* is the first pin to use for ``out()`` instructions.
|
||||
- *set_base* is the first pin to use for ``set()`` instructions.
|
||||
- *jmp_pin* is the first pin to use for ``jmp(pin, ...)`` instructions.
|
||||
- *sideset_base* is the first pin to use for side-setting.
|
||||
- *in_shiftdir* is the direction the ISR will shift, either
|
||||
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||
- *out_shiftdir* is the direction the OSR will shift, either
|
||||
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||
- *push_thresh* is the threshold in bits before auto-push or conditional
|
||||
re-pushing is triggered.
|
||||
- *pull_thresh* is the threshold in bits before auto-push or conditional
|
||||
re-pushing is triggered.
|
||||
|
||||
.. method:: StateMachine.active([value])
|
||||
|
||||
Gets or sets whether the state machine is currently running.
|
||||
|
||||
>>> sm.active()
|
||||
True
|
||||
>>> sm.active(0)
|
||||
False
|
||||
|
||||
.. method:: StateMachine.restart()
|
||||
|
||||
Restarts the state machine and jumps to the beginning of the program.
|
||||
|
||||
This method clears the state machine's internal state using the RP2040's
|
||||
``SM_RESTART`` register. This includes:
|
||||
|
||||
- input and output shift counters
|
||||
- the contents of the input shift register
|
||||
- the delay counter
|
||||
- the waiting-on-IRQ state
|
||||
- a stalled instruction run using `StateMachine.exec()`
|
||||
|
||||
.. method:: StateMachine.exec(instr)
|
||||
|
||||
Execute a single PIO instruction. Uses `asm_pio_encode` to encode the
|
||||
instruction from the given string *instr*.
|
||||
|
||||
>>> sm.exec("set(0, 1)")
|
||||
|
||||
.. method:: StateMachine.get(buf=None, shift=0)
|
||||
|
||||
Pull a word from the state machine's RX FIFO.
|
||||
|
||||
If the FIFO is empty, it blocks until data arrives (i.e. the state machine
|
||||
pushes a word).
|
||||
|
||||
The value is shifted right by *shift* bits before returning, i.e. the
|
||||
return value is ``word >> shift``.
|
||||
|
||||
.. method:: StateMachine.put(value, shift=0)
|
||||
|
||||
Push a word onto the state machine's TX FIFO.
|
||||
|
||||
If the FIFO is full, it blocks until there is space (i.e. the state machine
|
||||
pulls a word).
|
||||
|
||||
The value is first shifted left by *shift* bits, i.e. the state machine
|
||||
receives ``value << shift``.
|
||||
|
||||
.. method:: StateMachine.rx_fifo()
|
||||
|
||||
Returns the number of words in the state machine's RX FIFO. A value of 0
|
||||
indicates the FIFO is empty.
|
||||
|
||||
Useful for checking if data is waiting to be read, before calling
|
||||
`StateMachine.get()`.
|
||||
|
||||
.. method:: StateMachine.tx_fifo()
|
||||
|
||||
Returns the number of words in the state machine's TX FIFO. A value of 0
|
||||
indicates the FIFO is empty.
|
||||
|
||||
Useful for checking if there is space to push another word using
|
||||
`StateMachine.put()`.
|
||||
|
||||
.. method:: StateMachine.irq(handler=None, trigger=0|1, hard=False)
|
||||
|
||||
Returns the IRQ object for the given StateMachine.
|
||||
|
||||
Optionally configure it.
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
.. currentmodule:: rp2
|
||||
|
||||
:mod:`rp2` --- functionality specific to the RP2040
|
||||
===================================================
|
||||
|
||||
.. module:: rp2
|
||||
:synopsis: functionality specific to the RP2
|
||||
|
||||
The ``rp2`` module contains functions and classes specific to the RP2040, as
|
||||
used in the Raspberry Pi Pico.
|
||||
|
||||
See the `RP2040 Python datasheet
|
||||
<https://datasheets.raspberrypi.org/pico/raspberry-pi-pico-python-sdk.pdf>`_
|
||||
for more information, and `pico-micropython-examples
|
||||
<https://github.com/raspberrypi/pico-micropython-examples/tree/master/pio>`_
|
||||
for example code.
|
||||
|
||||
|
||||
PIO related functions
|
||||
---------------------
|
||||
|
||||
The ``rp2`` module includes functions for assembling PIO programs.
|
||||
|
||||
For running PIO programs, see :class:`rp2.StateMachine`.
|
||||
|
||||
.. function:: asm_pio(*, out_init=None, set_init=None, sideset_init=None, in_shiftdir=0, out_shiftdir=0, autopush=False, autopull=False, push_thresh=32, pull_thresh=32, fifo_join=PIO.JOIN_NONE)
|
||||
|
||||
Assemble a PIO program.
|
||||
|
||||
The following parameters control the initial state of the GPIO pins, as one
|
||||
of `PIO.IN_LOW`, `PIO.IN_HIGH`, `PIO.OUT_LOW` or `PIO.OUT_HIGH`. If the
|
||||
program uses more than one pin, provide a tuple, e.g.
|
||||
``out_init=(PIO.OUT_LOW, PIO.OUT_LOW)``.
|
||||
|
||||
- *out_init* configures the pins used for ``out()`` instructions.
|
||||
- *set_init* configures the pins used for ``set()`` instructions. There can
|
||||
be at most 5.
|
||||
- *sideset_init* configures the pins used side-setting. There can be at
|
||||
most 5.
|
||||
|
||||
The following parameters are used by default, but can be overridden in
|
||||
`StateMachine.init()`:
|
||||
|
||||
- *in_shiftdir* is the default direction the ISR will shift, either
|
||||
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||
- *out_shiftdir* is the default direction the OSR will shift, either
|
||||
`PIO.SHIFT_LEFT` or `PIO.SHIFT_RIGHT`.
|
||||
- *push_thresh* is the threshold in bits before auto-push or conditional
|
||||
re-pushing is triggered.
|
||||
- *pull_thresh* is the threshold in bits before auto-push or conditional
|
||||
re-pushing is triggered.
|
||||
|
||||
The remaining parameters are:
|
||||
|
||||
- *autopush* configures whether auto-push is enabled.
|
||||
- *autopull* configures whether auto-pull is enabled.
|
||||
- *fifo_join* configures whether the 4-word TX and RX FIFOs should be
|
||||
combined into a single 8-word FIFO for one direction only. The options
|
||||
are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
|
||||
|
||||
.. function:: asm_pio_encode(instr, sideset_count)
|
||||
|
||||
Assemble a single PIO instruction. You usually want to use `asm_pio()`
|
||||
instead.
|
||||
|
||||
>>> rp2.asm_pio_encode("set(0, 1)", 0)
|
||||
57345
|
||||
|
||||
.. class:: PIOASMError
|
||||
|
||||
This exception is raised from `asm_pio()` or `asm_pio_encode()` if there is
|
||||
an error assembling a PIO program.
|
||||
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
rp2.Flash.rst
|
||||
rp2.PIO.rst
|
||||
rp2.StateMachine.rst
|
|
@ -214,6 +214,14 @@ TCP stream connections
|
|||
|
||||
This is a coroutine.
|
||||
|
||||
.. method:: Stream.readinto(buf)
|
||||
|
||||
Read up to n bytes into *buf* with n being equal to the length of *buf*.
|
||||
|
||||
Return the number of bytes read into *buf*.
|
||||
|
||||
This is a coroutine, and a MicroPython extension.
|
||||
|
||||
.. method:: Stream.readline()
|
||||
|
||||
Read a line and return it.
|
||||
|
|
|
@ -247,7 +247,7 @@ Module contents
|
|||
|
||||
.. data:: VOID
|
||||
|
||||
``VOID`` is an alias for ``UINT8``, and is provided to conviniently define
|
||||
``VOID`` is an alias for ``UINT8``, and is provided to conveniently define
|
||||
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
|
||||
|
||||
.. data:: PTR
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
|
||||
|see_cpython_module| :mod:`cpython:heapq`.
|
||||
|
||||
This module implements the heap queue algorithm.
|
||||
This module implements the
|
||||
`min heap queue algorithm <https://en.wikipedia.org/wiki/Heap_%28data_structure%29>`_.
|
||||
|
||||
A heap queue is simply a list that has its elements stored in a certain way.
|
||||
A heap queue is essentially a list that has its elements stored in such a way
|
||||
that the first item of the list is always the smallest.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
@ -21,8 +23,10 @@ Functions
|
|||
|
||||
.. function:: heappop(heap)
|
||||
|
||||
Pop the first item from the ``heap``, and return it. Raises IndexError if
|
||||
heap is empty.
|
||||
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
|
||||
``heap`` is empty.
|
||||
|
||||
The returned item will be the smallest item in the ``heap``.
|
||||
|
||||
.. function:: heapify(x)
|
||||
|
||||
|
|
|
@ -89,11 +89,11 @@ Methods
|
|||
``callee-owned tuples``. This function provides efficient, allocation-free
|
||||
way to poll on streams.
|
||||
|
||||
If *flags* is 1, one-shot behavior for events is employed: streams for
|
||||
If *flags* is 1, one-shot behaviour for events is employed: streams for
|
||||
which events happened will have their event masks automatically reset
|
||||
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
|
||||
won't be processed until new mask is set with `poll.modify()`. This
|
||||
behavior is useful for asynchronous I/O schedulers.
|
||||
behaviour is useful for asynchronous I/O schedulers.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
.. _rp2_general:
|
||||
|
||||
General information about the RP2xxx port
|
||||
=========================================
|
||||
|
||||
The rp2 port supports boards powered by the Raspberry Pi Foundation's RP2xxx
|
||||
family of microcontrollers, most notably the Raspberry Pi Pico that employs
|
||||
the RP2040.
|
||||
|
||||
Technical specifications and SoC datasheets
|
||||
-------------------------------------------
|
||||
|
||||
Datasheets!
|
||||
|
||||
Short summary of tech specs!
|
||||
|
||||
Description of general structure of the port (it's built on top of the APIs
|
||||
provided by the Raspberry Pi SDK).
|
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
|
@ -0,0 +1,288 @@
|
|||
.. _rp2_quickref:
|
||||
|
||||
Quick reference for the RP2
|
||||
===========================
|
||||
|
||||
.. image:: img/rpipico.jpg
|
||||
:alt: Raspberry Pi Pico
|
||||
:width: 640px
|
||||
|
||||
The Raspberry Pi Pico Development Board (image attribution: Raspberry Pi Foundation).
|
||||
|
||||
Below is a quick reference for Raspberry Pi RP2xxx boards. If it is your first time
|
||||
working with this board it may be useful to get an overview of the microcontroller:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
general.rst
|
||||
tutorial/intro.rst
|
||||
|
||||
Installing MicroPython
|
||||
----------------------
|
||||
|
||||
See the corresponding section of tutorial: :ref:`rp2_intro`. It also includes
|
||||
a troubleshooting subsection.
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
|
||||
The MicroPython REPL is on the USB serial port.
|
||||
Tab-completion is useful to find out what methods an object has.
|
||||
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
|
||||
the REPL.
|
||||
|
||||
The :mod:`machine` module::
|
||||
|
||||
import machine
|
||||
|
||||
machine.freq() # get the current frequency of the CPU
|
||||
machine.freq(240000000) # set the CPU frequency to 240 MHz
|
||||
|
||||
The :mod:`rp2` module::
|
||||
|
||||
import rp2
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the :mod:`time <utime>` module::
|
||||
|
||||
import time
|
||||
|
||||
time.sleep(1) # sleep for 1 second
|
||||
time.sleep_ms(500) # sleep for 500 milliseconds
|
||||
time.sleep_us(10) # sleep for 10 microseconds
|
||||
start = time.ticks_ms() # get millisecond counter
|
||||
delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
|
||||
|
||||
Timers
|
||||
------
|
||||
|
||||
How do they work?
|
||||
|
||||
.. _rp2_Pins_and_GPIO:
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
|
||||
p0.on() # set pin to "on" (high) level
|
||||
p0.off() # set pin to "off" (low) level
|
||||
p0.value(1) # set pin to on/high
|
||||
|
||||
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
|
||||
print(p2.value()) # get value, 0 or 1
|
||||
|
||||
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
||||
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
||||
|
||||
UART (serial bus)
|
||||
-----------------
|
||||
|
||||
See :ref:`machine.UART <machine.UART>`. ::
|
||||
|
||||
from machine import UART
|
||||
|
||||
uart1 = UART(1, baudrate=9600, tx=33, rx=32)
|
||||
uart1.write('hello') # write 5 bytes
|
||||
uart1.read(5) # read up to 5 bytes
|
||||
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
How does PWM work on the RPi RP2xxx?
|
||||
|
||||
Use the ``machine.PWM`` class::
|
||||
|
||||
from machine import Pin, PWM
|
||||
|
||||
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
||||
pwm0.freq() # get current frequency
|
||||
pwm0.freq(1000) # set frequency
|
||||
pwm0.duty_u16() # get current duty cycle, range 0-65535
|
||||
pwm0.duty_u16(200) # set duty cycle, range 0-65535
|
||||
pwm0.deinit() # turn off PWM on the pin
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
How does the ADC module work?
|
||||
|
||||
Use the :ref:`machine.ADC <machine.ADC>` class::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC(Pin(32)) # create ADC object on ADC pin
|
||||
adc.read_u16() # read value, 0-65535 across voltage range 0.0v - 3.3v
|
||||
|
||||
Software SPI bus
|
||||
----------------
|
||||
|
||||
Software SPI (using bit-banging) works on all pins, and is accessed via the
|
||||
:ref:`machine.SoftSPI <machine.SoftSPI>` class::
|
||||
|
||||
from machine import Pin, SoftSPI
|
||||
|
||||
# construct a SoftSPI bus on the given pins
|
||||
# polarity is the idle state of SCK
|
||||
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
spi.read(10) # read 10 bytes on MISO
|
||||
spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI
|
||||
|
||||
buf = bytearray(50) # create a buffer
|
||||
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
|
||||
spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI
|
||||
|
||||
spi.write(b'12345') # write 5 bytes on MOSI
|
||||
|
||||
buf = bytearray(4) # create a buffer
|
||||
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
|
||||
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
|
||||
|
||||
.. Warning::
|
||||
Currently *all* of ``sck``, ``mosi`` and ``miso`` *must* be specified when
|
||||
initialising Software SPI.
|
||||
|
||||
Hardware SPI bus
|
||||
----------------
|
||||
|
||||
Hardware SPI is accessed via the :ref:`machine.SPI <machine.SPI>` class and
|
||||
has the same methods as software SPI above::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
spi = SPI(1, 10000000)
|
||||
spi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
|
||||
spi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))
|
||||
|
||||
Software I2C bus
|
||||
----------------
|
||||
|
||||
Software I2C (using bit-banging) works on all output-capable pins, and is
|
||||
accessed via the :ref:`machine.SoftI2C <machine.SoftI2C>` class::
|
||||
|
||||
from machine import Pin, SoftI2C
|
||||
|
||||
i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||
|
||||
i2c.scan() # scan for devices
|
||||
|
||||
i2c.readfrom(0x3a, 4) # read 4 bytes from device with address 0x3a
|
||||
i2c.writeto(0x3a, '12') # write '12' to device with address 0x3a
|
||||
|
||||
buf = bytearray(10) # create a buffer with 10 bytes
|
||||
i2c.writeto(0x3a, buf) # write the given buffer to the slave
|
||||
|
||||
Hardware I2C bus
|
||||
----------------
|
||||
|
||||
The driver is accessed via the :ref:`machine.I2C <machine.I2C>` class and
|
||||
has the same methods as software I2C above::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
i2c = I2C(0)
|
||||
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)
|
||||
|
||||
Real time clock (RTC)
|
||||
---------------------
|
||||
|
||||
See :ref:`machine.RTC <machine.RTC>` ::
|
||||
|
||||
from machine import RTC
|
||||
|
||||
rtc = RTC()
|
||||
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||
rtc.datetime() # get date and time
|
||||
|
||||
WDT (Watchdog timer)
|
||||
--------------------
|
||||
|
||||
Is there a watchdog timer?
|
||||
|
||||
See :ref:`machine.WDT <machine.WDT>`. ::
|
||||
|
||||
from machine import WDT
|
||||
|
||||
# enable the WDT with a timeout of 5s (1s is the minimum)
|
||||
wdt = WDT(timeout=5000)
|
||||
wdt.feed()
|
||||
|
||||
Deep-sleep mode
|
||||
---------------
|
||||
|
||||
Is there deep-sleep support for the rp2?
|
||||
|
||||
The following code can be used to sleep, wake and check the reset cause::
|
||||
|
||||
import machine
|
||||
|
||||
# check if the device woke from a deep sleep
|
||||
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
|
||||
print('woke from a deep sleep')
|
||||
|
||||
# put the device to sleep for 10 seconds
|
||||
machine.deepsleep(10000)
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
||||
The OneWire driver is implemented in software and works on all pins::
|
||||
|
||||
from machine import Pin
|
||||
import onewire
|
||||
|
||||
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.readbyte() # read a byte
|
||||
ow.writebyte(0x12) # write a byte on the bus
|
||||
ow.write('123') # write bytes on the bus
|
||||
ow.select_rom(b'12345678') # select a specific device by its ROM code
|
||||
|
||||
There is a specific driver for DS18S20 and DS18B20 devices::
|
||||
|
||||
import time, ds18x20
|
||||
ds = ds18x20.DS18X20(ow)
|
||||
roms = ds.scan()
|
||||
ds.convert_temp()
|
||||
time.sleep_ms(750)
|
||||
for rom in roms:
|
||||
print(ds.read_temp(rom))
|
||||
|
||||
Be sure to put a 4.7k pull-up resistor on the data line. Note that
|
||||
the ``convert_temp()`` method must be called each time you want to
|
||||
sample the temperature.
|
||||
|
||||
NeoPixel and APA106 driver
|
||||
--------------------------
|
||||
|
||||
Use the ``neopixel`` and ``apa106`` modules::
|
||||
|
||||
from machine import Pin
|
||||
from neopixel import NeoPixel
|
||||
|
||||
pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
|
||||
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
|
||||
np[0] = (255, 255, 255) # set the first pixel to white
|
||||
np.write() # write data to all pixels
|
||||
r, g, b = np[0] # get first pixel colour
|
||||
|
||||
|
||||
The APA106 driver extends NeoPixel, but internally uses a different colour order::
|
||||
|
||||
from apa106 import APA106
|
||||
ap = APA106(pin, 8)
|
||||
r, g, b = ap[0]
|
||||
|
||||
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
|
@ -0,0 +1,6 @@
|
|||
.. _rp2_intro:
|
||||
|
||||
Getting started with MicroPython on the RP2xxx
|
||||
==============================================
|
||||
|
||||
Let's get started!
|
|
@ -31,12 +31,19 @@
|
|||
|
||||
#if MICROPY_PY_UASYNCIO
|
||||
|
||||
#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
|
||||
#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
|
||||
#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
|
||||
|
||||
#define TASK_IS_DONE(task) ( \
|
||||
(task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
|
||||
|| (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
|
||||
|
||||
typedef struct _mp_obj_task_t {
|
||||
mp_pairheap_t pairheap;
|
||||
mp_obj_t coro;
|
||||
mp_obj_t data;
|
||||
mp_obj_t waiting;
|
||||
|
||||
mp_obj_t state;
|
||||
mp_obj_t ph_key;
|
||||
} mp_obj_task_t;
|
||||
|
||||
|
@ -146,9 +153,6 @@ STATIC const mp_obj_type_t task_queue_type = {
|
|||
/******************************************************************************/
|
||||
// Task class
|
||||
|
||||
// For efficiency, the task object is stored to the coro entry when the task is done.
|
||||
#define TASK_IS_DONE(task) ((task)->coro == MP_OBJ_FROM_PTR(task))
|
||||
|
||||
// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
|
||||
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
|
||||
|
||||
|
@ -159,7 +163,7 @@ STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, const mp
|
|||
mp_pairheap_init_node(task_lt, &self->pairheap);
|
||||
self->coro = args[0];
|
||||
self->data = mp_const_none;
|
||||
self->waiting = mp_const_none;
|
||||
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
|
||||
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
|
||||
if (n_args == 2) {
|
||||
uasyncio_context = args[1];
|
||||
|
@ -218,24 +222,6 @@ STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
|
||||
|
||||
STATIC mp_obj_t task_throw(mp_obj_t self_in, mp_obj_t value_in) {
|
||||
// This task raised an exception which was uncaught; handle that now.
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
// Set the data because it was cleared by the main scheduling loop.
|
||||
self->data = value_in;
|
||||
if (self->waiting == mp_const_none) {
|
||||
// Nothing await'ed on the task so call the exception handler.
|
||||
mp_obj_t _exc_context = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__exc_context));
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_exception), value_in);
|
||||
mp_obj_dict_store(_exc_context, MP_OBJ_NEW_QSTR(MP_QSTR_future), self_in);
|
||||
mp_obj_t Loop = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_Loop));
|
||||
mp_obj_t call_exception_handler = mp_load_attr(Loop, MP_QSTR_call_exception_handler);
|
||||
mp_call_function_1(call_exception_handler, _exc_context);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_throw_obj, task_throw);
|
||||
|
||||
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
|
@ -244,32 +230,24 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
dest[0] = self->coro;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
dest[0] = self->data;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
if (self->waiting != mp_const_none && self->waiting != mp_const_false) {
|
||||
dest[0] = self->waiting;
|
||||
}
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
dest[0] = self->state;
|
||||
} else if (attr == MP_QSTR_done) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_cancel) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_throw) {
|
||||
dest[0] = MP_OBJ_FROM_PTR(&task_throw_obj);
|
||||
dest[1] = self_in;
|
||||
} else if (attr == MP_QSTR_ph_key) {
|
||||
dest[0] = self->ph_key;
|
||||
}
|
||||
} else if (dest[1] != MP_OBJ_NULL) {
|
||||
// Store
|
||||
if (attr == MP_QSTR_coro) {
|
||||
self->coro = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_data) {
|
||||
if (attr == MP_QSTR_data) {
|
||||
self->data = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
} else if (attr == MP_QSTR_waiting) {
|
||||
self->waiting = dest[1];
|
||||
} else if (attr == MP_QSTR_state) {
|
||||
self->state = dest[1];
|
||||
dest[0] = MP_OBJ_NULL;
|
||||
}
|
||||
}
|
||||
|
@ -278,15 +256,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
(void)iter_buf;
|
||||
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->waiting == mp_const_none) {
|
||||
// The is the first access of the "waiting" entry.
|
||||
if (TASK_IS_DONE(self)) {
|
||||
// Signal that the completed-task has been await'ed on.
|
||||
self->waiting = mp_const_false;
|
||||
} else {
|
||||
// Lazily allocate the waiting queue.
|
||||
self->waiting = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
self->state = TASK_STATE_DONE_WAS_WAITED_ON;
|
||||
} else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
|
||||
// Allocate the waiting queue.
|
||||
self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
|
||||
}
|
||||
return self_in;
|
||||
}
|
||||
|
@ -299,7 +274,7 @@ STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
|
|||
} else {
|
||||
// Put calling task on waiting queue.
|
||||
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
|
||||
mp_obj_t args[2] = { self->waiting, cur_task };
|
||||
mp_obj_t args[2] = { self->state, cur_task };
|
||||
task_queue_push_sorted(2, args);
|
||||
// Set calling task's data to this task that it waits on, to double-link it.
|
||||
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
|
||||
|
|
|
@ -15,38 +15,10 @@
|
|||
|
||||
#if MICROPY_PY_UCTYPES
|
||||
|
||||
/// \module uctypes - Access data structures in memory
|
||||
///
|
||||
/// The module allows to define layout of raw data structure (using terms
|
||||
/// of C language), and then access memory buffers using this definition.
|
||||
/// The module also provides convenience functions to access memory buffers
|
||||
/// contained in Python objects or wrap memory buffers in Python objects.
|
||||
/// \constant UINT8_1 - uint8_t value type
|
||||
|
||||
/// \class struct - C-like structure
|
||||
///
|
||||
/// Encapsulalation of in-memory data structure. This class doesn't define
|
||||
/// any methods, only attribute access (for structure fields) and
|
||||
/// indexing (for pointer and array fields).
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// # Define layout of a structure with 2 fields
|
||||
/// # 0 and 4 are byte offsets of fields from the beginning of struct
|
||||
/// # they are logically ORed with field type
|
||||
/// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8}
|
||||
///
|
||||
/// # Example memory buffer to access (contained in bytes object)
|
||||
/// buf = b"\x64\0\0\0\0x14"
|
||||
///
|
||||
/// # Create structure object referring to address of
|
||||
/// # the data in the buffer above
|
||||
/// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf))
|
||||
///
|
||||
/// # Access fields
|
||||
/// print(s.a, s.b)
|
||||
/// # Result:
|
||||
/// # 100, 20
|
||||
// The uctypes module allows defining the layout of a raw data structure (using
|
||||
// terms of the C language), and then access memory buffers using this definition.
|
||||
// The module also provides convenience functions to access memory buffers
|
||||
// contained in Python objects or wrap memory buffers in Python objects.
|
||||
|
||||
#define LAYOUT_LITTLE_ENDIAN (0)
|
||||
#define LAYOUT_BIG_ENDIAN (1)
|
||||
|
@ -56,6 +28,7 @@
|
|||
#define BITF_LEN_BITS 5
|
||||
#define BITF_OFF_BITS 5
|
||||
#define OFFSET_BITS 17
|
||||
#define LEN_BITS (OFFSET_BITS + BITF_OFF_BITS)
|
||||
#if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31
|
||||
#error Invalid encoding field length
|
||||
#endif
|
||||
|
@ -172,7 +145,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
|
|||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
// Elements of array are scalar
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
item_s = uctypes_struct_scalar_size(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
|
@ -400,10 +373,8 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref);
|
||||
mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS);
|
||||
offset &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
// printf("scalar type=%d offset=%x\n", val_type, offset);
|
||||
|
||||
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
|
||||
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
if (set_val == MP_OBJ_NULL) {
|
||||
return get_aligned(val_type, self->addr + offset, 0);
|
||||
|
@ -420,9 +391,9 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||
}
|
||||
}
|
||||
} else if (val_type >= BFUINT8 && val_type <= BFINT32) {
|
||||
uint bit_offset = (offset >> 17) & 31;
|
||||
uint bit_len = (offset >> 22) & 31;
|
||||
offset &= (1 << 17) - 1;
|
||||
uint bit_offset = (offset >> OFFSET_BITS) & 31;
|
||||
uint bit_len = (offset >> LEN_BITS) & 31;
|
||||
offset &= (1 << OFFSET_BITS) - 1;
|
||||
mp_uint_t val;
|
||||
if (self->flags == LAYOUT_NATIVE) {
|
||||
val = get_aligned_basic(val_type & 6, self->addr + offset);
|
||||
|
@ -470,7 +441,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
// printf("agg type=%d offset=%x\n", agg_type, offset);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
|
@ -495,7 +465,6 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
|||
o->desc = MP_OBJ_FROM_PTR(sub);
|
||||
o->addr = self->addr + offset;
|
||||
o->flags = self->flags;
|
||||
// printf("PTR/ARR base addr=%p\n", o->addr);
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
}
|
||||
|
@ -553,7 +522,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
|
|||
return value; // just !MP_OBJ_NULL
|
||||
}
|
||||
} else {
|
||||
byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index;
|
||||
byte *p = self->addr + uctypes_struct_scalar_size(val_type) * index;
|
||||
if (value == MP_OBJ_SENTINEL) {
|
||||
return get_unaligned(val_type, p, self->flags);
|
||||
} else {
|
||||
|
@ -628,9 +597,8 @@ STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/// \function addressof()
|
||||
/// Return address of object's data (applies to object providing buffer
|
||||
/// interface).
|
||||
// addressof()
|
||||
// Return address of object's data (applies to objects providing the buffer interface).
|
||||
STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
|
@ -638,25 +606,20 @@ STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof);
|
||||
|
||||
/// \function bytearray_at()
|
||||
/// Capture memory at given address of given size as bytearray. Memory is
|
||||
/// captured by reference (and thus memory pointed by bytearray may change
|
||||
/// or become invalid at later time). Use bytes_at() to capture by value.
|
||||
// bytearray_at()
|
||||
// Capture memory at given address of given size as bytearray.
|
||||
STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at);
|
||||
|
||||
/// \function bytes_at()
|
||||
/// Capture memory at given address of given size as bytes. Memory is
|
||||
/// captured by value, i.e. copied. Use bytearray_at() to capture by reference
|
||||
/// ("zero copy").
|
||||
// bytes_at()
|
||||
// Capture memory at given address of given size as bytes.
|
||||
STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) {
|
||||
return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at);
|
||||
|
||||
|
||||
STATIC const mp_obj_type_t uctypes_struct_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_struct,
|
||||
|
@ -676,81 +639,63 @@ STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) },
|
||||
|
||||
/// \moduleref uctypes
|
||||
|
||||
/// \constant NATIVE - Native structure layout - native endianness,
|
||||
/// platform-specific field alignment
|
||||
{ MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) },
|
||||
/// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) },
|
||||
/// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed
|
||||
/// (no alignment constraints)
|
||||
{ MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) },
|
||||
|
||||
/// \constant VOID - void value type, may be used only as pointer target type.
|
||||
{ MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
|
||||
/// \constant UINT8 - uint8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) },
|
||||
/// \constant INT8 - int8_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) },
|
||||
/// \constant UINT16 - uint16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
/// \constant INT16 - int16_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
/// \constant UINT32 - uint32_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
/// \constant INT32 - int32_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
/// \constant UINT64 - uint64_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
/// \constant INT64 - int64_t value type
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, VAL_TYPE_BITS)) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(OFFSET_BITS) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(LEN_BITS) },
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||
// C native type aliases. These depend on GCC-compatible predefined
|
||||
// preprocessor macros.
|
||||
#if __SIZEOF_SHORT__ == 2
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_INT__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG__ == 4
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, VAL_TYPE_BITS)) },
|
||||
#elif __SIZEOF_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#if __SIZEOF_LONG_LONG__ == 8
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, VAL_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, VAL_TYPE_BITS)) },
|
||||
#endif
|
||||
#endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uctypes = {
|
||||
|
|
|
@ -42,9 +42,16 @@
|
|||
|
||||
typedef struct _mp_obj_hash_t {
|
||||
mp_obj_base_t base;
|
||||
char state[0];
|
||||
bool final; // if set, update and digest raise an exception
|
||||
uintptr_t state[0]; // must be aligned to a machine word
|
||||
} mp_obj_hash_t;
|
||||
|
||||
static void uhashlib_ensure_not_final(mp_obj_hash_t *self) {
|
||||
if (self->final) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_UHASHLIB_SHA256
|
||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
|
||||
|
||||
|
@ -60,6 +67,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
|
||||
mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
|
||||
if (n_args == 1) {
|
||||
|
@ -70,6 +78,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -78,6 +87,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 32);
|
||||
mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
|
||||
|
@ -102,6 +113,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
mp_arg_check_num(n_args, kw_args, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
sha256_init((CRYAL_SHA256_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
|
@ -112,6 +124,7 @@ STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_arg
|
|||
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
check_not_unicode(arg);
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -120,6 +133,8 @@ STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
|
||||
sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
|
||||
|
@ -153,6 +168,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
mp_arg_check_num(n_args, kw_args, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
SHA1_Init((SHA1_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
|
@ -163,6 +179,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
check_not_unicode(arg);
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -171,6 +188,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, SHA1_SIZE);
|
||||
SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
|
||||
|
@ -190,6 +209,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
|
||||
mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
|
@ -200,6 +220,7 @@ STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -208,6 +229,8 @@ STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 20);
|
||||
mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
|
||||
|
@ -241,6 +264,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(MD5_CTX));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
MD5_Init((MD5_CTX *)o->state);
|
||||
if (n_args == 1) {
|
||||
uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
|
||||
|
@ -250,6 +274,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
|
||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -258,6 +283,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, MD5_SIZE);
|
||||
MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
|
||||
|
@ -277,6 +304,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context));
|
||||
o->base.type = type;
|
||||
o->final = false;
|
||||
mbedtls_md5_init((mbedtls_md5_context *)o->state);
|
||||
mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
|
||||
if (n_args == 1) {
|
||||
|
@ -287,6 +315,7 @@ STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args,
|
|||
|
||||
STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
|
||||
mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
|
||||
|
@ -295,6 +324,8 @@ STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
|
|||
|
||||
STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
|
||||
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uhashlib_ensure_not_final(self);
|
||||
self->final = true;
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, 16);
|
||||
mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
|
||||
|
|
|
@ -66,8 +66,11 @@ STATIC uint32_t yasmarang_randbelow(uint32_t n) {
|
|||
|
||||
STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
|
||||
int n = mp_obj_get_int(num_in);
|
||||
if (n > 32 || n == 0) {
|
||||
mp_raise_ValueError(NULL);
|
||||
if (n > 32 || n < 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
|
||||
}
|
||||
if (n == 0) {
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
}
|
||||
uint32_t mask = ~0;
|
||||
// Beware of C undefined behavior when shifting by >= than bit size
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
// Flags for poll()
|
||||
#define FLAG_ONESHOT (1)
|
||||
|
||||
/// \module select - Provides select function to wait for events on a stream
|
||||
///
|
||||
/// This module provides the select function.
|
||||
|
||||
typedef struct _poll_obj_t {
|
||||
mp_obj_t obj;
|
||||
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||
|
@ -91,7 +87,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
|||
return n_ready;
|
||||
}
|
||||
|
||||
/// \function select(rlist, wlist, xlist[, timeout])
|
||||
// select(rlist, wlist, xlist[, timeout])
|
||||
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||
// get array data from tuple/list arguments
|
||||
size_t rwx_len[3];
|
||||
|
@ -158,8 +154,6 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
||||
|
||||
/// \class Poll - poll class
|
||||
|
||||
typedef struct _mp_obj_poll_t {
|
||||
mp_obj_base_t base;
|
||||
mp_map_t poll_map;
|
||||
|
@ -170,7 +164,7 @@ typedef struct _mp_obj_poll_t {
|
|||
mp_obj_t ret_tuple;
|
||||
} mp_obj_poll_t;
|
||||
|
||||
/// \method register(obj[, eventmask])
|
||||
// register(obj[, eventmask])
|
||||
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_uint_t flags;
|
||||
|
@ -184,7 +178,7 @@ STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
||||
|
||||
/// \method unregister(obj)
|
||||
// unregister(obj)
|
||||
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
||||
|
@ -193,7 +187,7 @@ STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
|
||||
|
||||
/// \method modify(obj, eventmask)
|
||||
// modify(obj, eventmask)
|
||||
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
||||
|
@ -328,7 +322,7 @@ STATIC const mp_obj_type_t mp_type_poll = {
|
|||
.locals_dict = (void *)&poll_locals_dict,
|
||||
};
|
||||
|
||||
/// \function poll()
|
||||
// poll()
|
||||
STATIC mp_obj_t select_poll(void) {
|
||||
mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
|
||||
poll->base.type = &mp_type_poll;
|
||||
|
|
|
@ -175,6 +175,10 @@ def run_until_complete(main_task=None):
|
|||
if not exc:
|
||||
t.coro.send(None)
|
||||
else:
|
||||
# If the task is finished and on the run queue and gets here, then it
|
||||
# had an exception and was not await'ed on. Throwing into it now will
|
||||
# raise StopIteration and the code below will catch this and run the
|
||||
# call_exception_handler function.
|
||||
t.data = None
|
||||
t.coro.throw(exc)
|
||||
except excs_all as er:
|
||||
|
@ -185,22 +189,32 @@ def run_until_complete(main_task=None):
|
|||
if isinstance(er, StopIteration):
|
||||
return er.value
|
||||
raise er
|
||||
# Schedule any other tasks waiting on the completion of this task
|
||||
if t.state:
|
||||
# Task was running but is now finished.
|
||||
waiting = False
|
||||
if hasattr(t, "waiting"):
|
||||
while t.waiting.peek():
|
||||
_task_queue.push_head(t.waiting.pop_head())
|
||||
if t.state is True:
|
||||
# "None" indicates that the task is complete and not await'ed on (yet).
|
||||
t.state = None
|
||||
else:
|
||||
# Schedule any other tasks waiting on the completion of this task.
|
||||
while t.state.peek():
|
||||
_task_queue.push_head(t.state.pop_head())
|
||||
waiting = True
|
||||
t.waiting = None # Free waiting queue head
|
||||
# "False" indicates that the task is complete and has been await'ed on.
|
||||
t.state = False
|
||||
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).
|
||||
_task_queue.push_head(t)
|
||||
# Indicate task is done by setting coro to the task object itself
|
||||
t.coro = t
|
||||
# Save return value of coro to pass up to caller
|
||||
# Save return value of coro to pass up to caller.
|
||||
t.data = er
|
||||
elif t.state is None:
|
||||
# Task is already finished and nothing await'ed on the task,
|
||||
# so call the exception handler.
|
||||
_exc_context["exception"] = exc
|
||||
_exc_context["future"] = t
|
||||
Loop.call_exception_handler(_exc_context)
|
||||
|
||||
|
||||
# Create a new task from a coroutine and run it until it finishes
|
||||
|
|
|
@ -30,6 +30,10 @@ class Stream:
|
|||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.read(n)
|
||||
|
||||
async def readinto(self, buf):
|
||||
yield core._io_queue.queue_read(self.s)
|
||||
return self.s.readinto(buf)
|
||||
|
||||
async def readexactly(self, n):
|
||||
r = b""
|
||||
while n:
|
||||
|
@ -82,7 +86,7 @@ async def open_connection(host, port):
|
|||
try:
|
||||
s.connect(ai[-1])
|
||||
except OSError as er:
|
||||
if er.args[0] != EINPROGRESS:
|
||||
if er.errno != EINPROGRESS:
|
||||
raise er
|
||||
yield core._io_queue.queue_write(s)
|
||||
return ss, ss
|
||||
|
@ -112,7 +116,6 @@ class Server:
|
|||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(ai[-1])
|
||||
s.listen(backlog)
|
||||
self.task = core.cur_task
|
||||
# Accept incoming connections
|
||||
while True:
|
||||
try:
|
||||
|
@ -135,7 +138,7 @@ class Server:
|
|||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||
async def start_server(cb, host, port, backlog=5):
|
||||
s = Server()
|
||||
core.create_task(s._serve(cb, host, port, backlog))
|
||||
s.task = core.create_task(s._serve(cb, host, port, backlog))
|
||||
return s
|
||||
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@ class Task:
|
|||
def __init__(self, coro, globals=None):
|
||||
self.coro = coro # Coroutine of this Task
|
||||
self.data = None # General data for queue it is waiting on
|
||||
self.state = True # None, False, True or a TaskQueue instance
|
||||
self.ph_key = 0 # Pairing heap
|
||||
self.ph_child = None # Paring heap
|
||||
self.ph_child_last = None # Paring heap
|
||||
|
@ -130,30 +131,30 @@ class Task:
|
|||
self.ph_rightmost_parent = None # Paring heap
|
||||
|
||||
def __iter__(self):
|
||||
if self.coro is self:
|
||||
# Signal that the completed-task has been await'ed on.
|
||||
self.waiting = None
|
||||
elif not hasattr(self, "waiting"):
|
||||
# Lazily allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.waiting = TaskQueue()
|
||||
if not self.state:
|
||||
# Task finished, signal that is has been await'ed on.
|
||||
self.state = False
|
||||
elif self.state is True:
|
||||
# Allocated head of linked list of Tasks waiting on completion of this task.
|
||||
self.state = TaskQueue()
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
# Task finished, raise return value to caller so it can continue.
|
||||
raise self.data
|
||||
else:
|
||||
# Put calling task on waiting queue.
|
||||
self.waiting.push_head(core.cur_task)
|
||||
self.state.push_head(core.cur_task)
|
||||
# Set calling task's data to this task that it waits on, to double-link it.
|
||||
core.cur_task.data = self
|
||||
|
||||
def done(self):
|
||||
return self.coro is self
|
||||
return not self.state
|
||||
|
||||
def cancel(self):
|
||||
# Check if task is already finished.
|
||||
if self.coro is self:
|
||||
if not self.state:
|
||||
return False
|
||||
# Can't cancel self (not supported yet).
|
||||
if self is core.cur_task:
|
||||
|
@ -172,13 +173,3 @@ class Task:
|
|||
core._task_queue.push_head(self)
|
||||
self.data = core.CancelledError
|
||||
return True
|
||||
|
||||
def throw(self, value):
|
||||
# This task raised an exception which was uncaught; handle that now.
|
||||
# Set the data because it was cleared by the main scheduling loop.
|
||||
self.data = value
|
||||
if not hasattr(self, "waiting"):
|
||||
# Nothing await'ed on the task so call the exception handler.
|
||||
core._exc_context["exception"] = value
|
||||
core._exc_context["future"] = self
|
||||
core.Loop.call_exception_handler(core._exc_context)
|
||||
|
|
|
@ -264,7 +264,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir);
|
||||
|
||||
/// Change current directory.
|
||||
// Change current directory.
|
||||
STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
const char *path;
|
||||
|
@ -280,7 +280,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir);
|
||||
|
||||
/// Get the current directory.
|
||||
// Get the current directory.
|
||||
STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
char buf[MICROPY_ALLOC_PATH_MAX + 1];
|
||||
|
@ -292,8 +292,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
|
||||
|
||||
/// \function stat(path)
|
||||
/// Get the status of a file or directory.
|
||||
// Get the status of a file or directory.
|
||||
STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in);
|
||||
const char *path = mp_obj_str_get_str(path_in);
|
||||
|
|
|
@ -622,8 +622,8 @@ friendly_repl_reset:
|
|||
|
||||
// If the GC is locked at this point there is no way out except a reset,
|
||||
// so force the GC to be unlocked to help the user debug what went wrong.
|
||||
if (MP_STATE_MEM(gc_lock_depth) != 0) {
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
if (MP_STATE_THREAD(gc_lock_depth) != 0) {
|
||||
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||
}
|
||||
|
||||
vstr_reset(&line);
|
||||
|
|
|
@ -47,9 +47,8 @@ extern pyexec_mode_kind_t pyexec_mode_kind;
|
|||
extern int pyexec_system_exit;
|
||||
|
||||
#define PYEXEC_FORCED_EXIT (0x100)
|
||||
#define PYEXEC_SWITCH_MODE (0x200)
|
||||
#define PYEXEC_EXCEPTION (0x400)
|
||||
#define PYEXEC_DEEP_SLEEP (0x800)
|
||||
#define PYEXEC_EXCEPTION (0x200)
|
||||
#define PYEXEC_DEEP_SLEEP (0x400)
|
||||
|
||||
int pyexec_raw_repl(void);
|
||||
int pyexec_friendly_repl(void);
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 Ayke van Laethem
|
||||
*
|
||||
* 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 "semihosting.h"
|
||||
|
||||
// Resources:
|
||||
// http://embed.rs/articles/2016/semi-hosting-rust/
|
||||
// https://wiki.dlang.org/Minimal_semihosted_ARM_Cortex-M_%22Hello_World%22
|
||||
// https://github.com/arduino/OpenOCD/blob/master/src/target/arm_semihosting.c
|
||||
|
||||
#define SYS_OPEN 0x01
|
||||
#define SYS_WRITEC 0x03
|
||||
#define SYS_WRITE 0x05
|
||||
#define SYS_READC 0x07
|
||||
|
||||
// Constants:
|
||||
#define OPEN_MODE_READ (0) // mode "r"
|
||||
#define OPEN_MODE_WRITE (4) // mode "w"
|
||||
|
||||
#ifndef __thumb__
|
||||
#error Semihosting is only implemented for ARM microcontrollers.
|
||||
#endif
|
||||
|
||||
static int mp_semihosting_stdout;
|
||||
|
||||
static uint32_t mp_semihosting_call(uint32_t num, const void *arg) {
|
||||
// A semihosting call works as follows, similar to a SVCall:
|
||||
// * the call is invoked by a special breakpoint: 0xAB
|
||||
// * the command is placed in r0
|
||||
// * a pointer to the arguments is placed in r1
|
||||
// * the return value is placed in r0
|
||||
// Note that because it uses the breakpoint instruction, applications
|
||||
// will hang if they're not connected to a debugger. And they'll be
|
||||
// stuck in a breakpoint if semihosting is not specifically enabled in
|
||||
// the debugger.
|
||||
// Also note that semihosting is extremely slow (sometimes >100ms per
|
||||
// call).
|
||||
register uint32_t num_reg __asm__ ("r0") = num;
|
||||
register const void *args_reg __asm__ ("r1") = arg;
|
||||
__asm__ __volatile__ (
|
||||
"bkpt 0xAB\n" // invoke semihosting call
|
||||
: "+r" (num_reg) // call number and result
|
||||
: "r" (args_reg) // arguments
|
||||
: "memory"); // make sure args aren't optimized away
|
||||
return num_reg; // r0, which became the result
|
||||
}
|
||||
|
||||
static int mp_semihosting_open_console(uint32_t mode) {
|
||||
struct {
|
||||
char *name;
|
||||
uint32_t mode;
|
||||
uint32_t name_len;
|
||||
} args = {
|
||||
.name = ":tt", // magic path to console
|
||||
.mode = mode, // e.g. "r", "w" (see OPEN_MODE_* constants)
|
||||
.name_len = 3, // strlen(":tt")
|
||||
};
|
||||
return mp_semihosting_call(SYS_OPEN, &args);
|
||||
}
|
||||
|
||||
void mp_semihosting_init() {
|
||||
mp_semihosting_stdout = mp_semihosting_open_console(OPEN_MODE_WRITE);
|
||||
}
|
||||
|
||||
int mp_semihosting_rx_char() {
|
||||
return mp_semihosting_call(SYS_READC, NULL);
|
||||
}
|
||||
|
||||
static void mp_semihosting_tx_char(char c) {
|
||||
mp_semihosting_call(SYS_WRITEC, &c);
|
||||
}
|
||||
|
||||
uint32_t mp_semihosting_tx_strn(const char *str, size_t len) {
|
||||
if (len == 0) {
|
||||
return 0; // nothing to do
|
||||
}
|
||||
if (len == 1) {
|
||||
mp_semihosting_tx_char(*str); // maybe faster?
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t fd;
|
||||
const char *str;
|
||||
uint32_t len;
|
||||
} args = {
|
||||
.fd = mp_semihosting_stdout,
|
||||
.str = str,
|
||||
.len = len,
|
||||
};
|
||||
return mp_semihosting_call(SYS_WRITE, &args);
|
||||
}
|
||||
|
||||
uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len) {
|
||||
// Write chunks of data until (excluding) the first '\n' character,
|
||||
// insert a '\r' character, and then continue with the next chunk
|
||||
// (starting with '\n').
|
||||
// Doing byte-by-byte writes would be easier to implement but is far
|
||||
// too slow.
|
||||
size_t start = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
mp_semihosting_tx_strn(str + start, i - start);
|
||||
mp_semihosting_tx_char('\r');
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
return mp_semihosting_tx_strn(str + start, len - start);
|
||||
}
|
|
@ -2537,6 +2537,10 @@ msgstr ""
|
|||
msgid "binary op %q not implemented"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/modurandom.c
|
||||
msgid "bits must be 32 or less"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/busio/UART.c
|
||||
msgid "bits must be in range 5 to 9"
|
||||
msgstr ""
|
||||
|
@ -3148,6 +3152,10 @@ msgstr ""
|
|||
msgid "graphic must be 2048 bytes long"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/moduhashlib.c
|
||||
msgid "hash is final"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/moduheapq.c
|
||||
msgid "heap must be a list"
|
||||
msgstr ""
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
# M5Stack ATOM MicroPython Helper Library
|
||||
# MIT license; Copyright (c) 2021 IAMLIUBO work for M5STACK
|
||||
#
|
||||
# Hardware details:
|
||||
# ATOM Lite https://docs.m5stack.com/en/core/atom_lite
|
||||
# ATOM Matrix https://docs.m5stack.com/en/core/atom_matrix
|
||||
|
||||
from micropython import const
|
||||
from machine import Pin
|
||||
import neopixel
|
||||
|
||||
# M5STACK ATOM Hardware Pin Assignments
|
||||
"""
|
||||
FRONT
|
||||
|3V3|
|
||||
|G21| IR G12 |G22|
|
||||
|G25| BTN G39 |G19|
|
||||
| 5V| WS2812 G27 |G23|
|
||||
|GNG| MPU G21 G25 |G33|
|
||||
G32 G26 5V GND
|
||||
Grove Port
|
||||
"""
|
||||
|
||||
# WS2812
|
||||
WS2812_PIN = const(27)
|
||||
|
||||
# Button
|
||||
BUTTON_PIN = const(39)
|
||||
|
||||
# IR
|
||||
IR_PIN = const(12)
|
||||
|
||||
# I2C
|
||||
I2C0_SCL_PIN = const(21)
|
||||
I2C0_SDA_PIN = const(25)
|
||||
|
||||
# Grove port
|
||||
GROVE_PORT_PIN = (const(26), const(32))
|
||||
|
||||
|
||||
class ATOM:
|
||||
def __init__(self, np_n):
|
||||
self._np = neopixel.NeoPixel(pin=Pin(WS2812_PIN), n=np_n)
|
||||
self._btn = Pin(BUTTON_PIN, Pin.IN, Pin.PULL_UP)
|
||||
|
||||
def get_button_status(self):
|
||||
return self._btn.value()
|
||||
|
||||
def set_button_callback(self, cb):
|
||||
self._btn.irq(trigger=Pin.IRQ_FALLING, handler=cb)
|
||||
|
||||
def set_pixel_color(self, num, r, g, b):
|
||||
if num <= self._np.n:
|
||||
self._np[num] = [r, g, b]
|
||||
self._np.write()
|
||||
|
||||
def get_pixel_color(self, num):
|
||||
if num <= self._np.n:
|
||||
return self._np[num]
|
||||
|
||||
def set_pixels_color(self, r, g, b):
|
||||
self._np.fill([r, g, b])
|
||||
self._np.write()
|
||||
|
||||
|
||||
class Lite(ATOM):
|
||||
# WS2812 number: 1
|
||||
def __init__(self):
|
||||
super(Lite, self).__init__(np_n=1)
|
||||
|
||||
|
||||
class Matrix(ATOM):
|
||||
# WS2812 number: 25
|
||||
def __init__(self):
|
||||
super(Matrix, self).__init__(np_n=25)
|
|
@ -0,0 +1,10 @@
|
|||
set(SDKCONFIG_DEFAULTS
|
||||
boards/sdkconfig.base
|
||||
boards/sdkconfig.ble
|
||||
boards/sdkconfig.240mhz
|
||||
boards/M5STACK_ATOM/sdkconfig.board
|
||||
)
|
||||
|
||||
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||
endif()
|
|
@ -0,0 +1,2 @@
|
|||
#define MICROPY_HW_BOARD_NAME "M5Stack ATOM"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
|
@ -0,0 +1,5 @@
|
|||
CONFIG_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_ESP32_REV_MIN_1=y
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="M5StackATOM"
|
|
@ -0,0 +1,3 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
freeze("$(PORT_DIR)/boards/UM_TINYPICO/modules", "dotstar.py")
|
||||
freeze("modules")
|
|
@ -0,0 +1,101 @@
|
|||
# FeatherS2 MicroPython Helper Library
|
||||
# 2021 Seon Rozenblum - Unexpected Maker
|
||||
#
|
||||
# Project home:
|
||||
# https://feathers2.io
|
||||
#
|
||||
# 2021-Mar-21 - v0.1 - Initial implementation
|
||||
|
||||
# Import required libraries
|
||||
from micropython import const
|
||||
from machine import Pin, SPI, ADC
|
||||
import machine, time
|
||||
|
||||
# FeatherS2 Hardware Pin Assignments
|
||||
|
||||
# LDO
|
||||
LDO2 = const(21)
|
||||
|
||||
# APA102 Dotstar pins
|
||||
DOTSTAR_CLK = const(45)
|
||||
DOTSTAR_DATA = const(40)
|
||||
|
||||
# SPI
|
||||
SPI_MOSI = const(35)
|
||||
SPI_MISO = const(37)
|
||||
SPI_CLK = const(36)
|
||||
|
||||
# I2C
|
||||
I2C_SDA = const(8)
|
||||
I2C_SCL = const(9)
|
||||
|
||||
# DAC
|
||||
DAC1 = const(17)
|
||||
DAC2 = const(18)
|
||||
|
||||
# LED & Ambient Light Sensor
|
||||
LED = const(13)
|
||||
AMB_LIGHT = const(4)
|
||||
|
||||
# Helper functions
|
||||
|
||||
# LED & Ambient Light Sensor control
|
||||
def set_led(state):
|
||||
l = Pin(LED, Pin.OUT)
|
||||
l.value(state)
|
||||
|
||||
|
||||
def toggle_led(state):
|
||||
l = Pin(LED, Pin.OUT)
|
||||
l.value(not l.value())
|
||||
|
||||
|
||||
# Create ADC and set attenuation and return the ambient light value from the onboard sensor
|
||||
def get_amb_light():
|
||||
adc = ADC(Pin(AMB_LIGHT))
|
||||
adc.atten(ADC.ATTN_11DB)
|
||||
return adc.read()
|
||||
|
||||
|
||||
# LDO2 power control
|
||||
# When we manually turn off the second LDO we also set the DotStar DATA and CLK pins to input to
|
||||
# prevent parasitic power from lighting the LED even with the LDO off, causing current use.
|
||||
# The DotStar is a beautiful LED, but parasitic power makes it a terrible choice for battery use :(
|
||||
def set_ldo2_power(state):
|
||||
"""Set the power for the on-board Dotstar to allow no current draw when not needed."""
|
||||
# Set the power pin to the inverse of state
|
||||
ldo2 = Pin(LDO2, Pin.OUT)
|
||||
ldo2.value(state)
|
||||
|
||||
if state:
|
||||
Pin(DOTSTAR_CLK, Pin.OUT)
|
||||
Pin(DOTSTAR_DATA, Pin.OUT) # If power is on, set CLK to be output, otherwise input
|
||||
else:
|
||||
Pin(DOTSTAR_CLK, Pin.IN)
|
||||
Pin(DOTSTAR_DATA, Pin.IN) # If power is on, set CLK to be output, otherwise input
|
||||
|
||||
# A small delay to let the IO change state
|
||||
time.sleep(0.035)
|
||||
|
||||
|
||||
# Dotstar rainbow colour wheel
|
||||
def dotstar_color_wheel(wheel_pos):
|
||||
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||
wheel_pos = wheel_pos % 255
|
||||
|
||||
if wheel_pos < 85:
|
||||
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||
elif wheel_pos < 170:
|
||||
wheel_pos -= 85
|
||||
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||
else:
|
||||
wheel_pos -= 170
|
||||
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||
|
||||
|
||||
# Go into deep sleep but shut down the APA first to save power
|
||||
# Use this if you want lowest deep sleep current
|
||||
def go_deepsleep(t):
|
||||
"""Deep sleep helper that also powers down the on-board Dotstar."""
|
||||
set_ldo2_power(False)
|
||||
machine.deepsleep(t)
|
|
@ -0,0 +1,9 @@
|
|||
set(IDF_TARGET esp32s2)
|
||||
set(SDKCONFIG_DEFAULTS
|
||||
boards/sdkconfig.base
|
||||
boards/sdkconfig.spiram_sx
|
||||
boards/sdkconfig.usb
|
||||
boards/UM_FEATHERS2/sdkconfig.board
|
||||
)
|
||||
|
||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
|
@ -0,0 +1,12 @@
|
|||
#define MICROPY_HW_BOARD_NAME "FeatherS2"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-S2"
|
||||
|
||||
#define MICROPY_PY_BLUETOOTH (0)
|
||||
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||
|
||||
#define MICROPY_HW_I2C0_SCL (9)
|
||||
#define MICROPY_HW_I2C0_SDA (8)
|
||||
|
||||
#define MICROPY_HW_SPI1_MOSI (35) // SDO
|
||||
#define MICROPY_HW_SPI1_MISO (37) // SDI
|
||||
#define MICROPY_HW_SPI1_SCK (36)
|
|
@ -0,0 +1,16 @@
|
|||
CONFIG_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
||||
CONFIG_ESPTOOLPY_AFTER_NORESET=y
|
||||
|
||||
CONFIG_SPIRAM_MEMTEST=
|
||||
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"
|
||||
#CONFIG_USB_AND_UART=y
|
||||
|
||||
# LWIP
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2"
|
||||
# end of LWIP
|
|
@ -0,0 +1,2 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
freeze("modules")
|
|
@ -0,0 +1,11 @@
|
|||
set(SDKCONFIG_DEFAULTS
|
||||
boards/sdkconfig.base
|
||||
boards/sdkconfig.ble
|
||||
boards/sdkconfig.240mhz
|
||||
boards/sdkconfig.spiram
|
||||
boards/UM_TINYPICO/sdkconfig.board
|
||||
)
|
||||
|
||||
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
|
||||
endif()
|
|
@ -0,0 +1,9 @@
|
|||
#define MICROPY_HW_BOARD_NAME "TinyPICO"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
||||
|
||||
#define MICROPY_HW_I2C0_SCL (22)
|
||||
#define MICROPY_HW_I2C0_SDA (21)
|
||||
|
||||
#define MICROPY_HW_SPI1_SCK (18)
|
||||
#define MICROPY_HW_SPI1_MOSI (23)
|
||||
#define MICROPY_HW_SPI1_MISO (19)
|
|
@ -0,0 +1,2 @@
|
|||
include("$(PORT_DIR)/boards/manifest.py")
|
||||
freeze("modules")
|
|
@ -0,0 +1,82 @@
|
|||
# TinyS2 MicroPython Helper Library
|
||||
# 2021 Seon Rozenblum - Unexpected Maker
|
||||
#
|
||||
# Project home:
|
||||
# https://tinys2.io
|
||||
#
|
||||
# 2021-Apr-10 - v0.1 - Initial implementation
|
||||
|
||||
# Import required libraries
|
||||
from micropython import const
|
||||
from machine import Pin, SPI, ADC
|
||||
import machine, time
|
||||
|
||||
# TinyS2 Hardware Pin Assignments
|
||||
|
||||
# Sense Pins
|
||||
VBUS_SENSE = const(21)
|
||||
VBAT_SENSE = const(3)
|
||||
|
||||
|
||||
# RGB LED Pins
|
||||
RGB_DATA = const(1)
|
||||
RGB_PWR = const(2)
|
||||
|
||||
# SPI
|
||||
SPI_MOSI = const(35)
|
||||
SPI_MISO = const(36)
|
||||
SPI_CLK = const(37)
|
||||
|
||||
# I2C
|
||||
I2C_SDA = const(8)
|
||||
I2C_SCL = const(9)
|
||||
|
||||
# DAC
|
||||
DAC1 = const(17)
|
||||
DAC2 = const(18)
|
||||
|
||||
|
||||
# Helper functions
|
||||
def set_pixel_power(state):
|
||||
"""Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep."""
|
||||
Pin(RGB_PWR, Pin.OUT).value(state)
|
||||
|
||||
|
||||
def get_battery_voltage():
|
||||
"""
|
||||
Returns the current battery voltage. If no battery is connected, returns 4.2V which is the charge voltage
|
||||
This is an approximation only, but useful to detect if the charge state of the battery is getting low.
|
||||
"""
|
||||
adc = ADC(Pin(VBAT_SENSE)) # Assign the ADC pin to read
|
||||
measuredvbat = adc.read() # Read the value
|
||||
measuredvbat /= 8192 # divide by 8192 as we are using the default ADC voltage range of 0-1V
|
||||
measuredvbat *= 4.2 # Multiply by 4.2V, our reference voltage
|
||||
return round(measuredvbat, 2)
|
||||
|
||||
|
||||
def get_vbus_present():
|
||||
"""Detect if VBUS (5V) power source is present"""
|
||||
return Pin(VBUS_SENSE, Pin.IN).value() == 1
|
||||
|
||||
|
||||
# NeoPixel rainbow colour wheel
|
||||
def rgb_color_wheel(wheel_pos):
|
||||
"""Color wheel to allow for cycling through the rainbow of RGB colors."""
|
||||
wheel_pos = wheel_pos % 255
|
||||
|
||||
if wheel_pos < 85:
|
||||
return 255 - wheel_pos * 3, 0, wheel_pos * 3
|
||||
elif wheel_pos < 170:
|
||||
wheel_pos -= 85
|
||||
return 0, wheel_pos * 3, 255 - wheel_pos * 3
|
||||
else:
|
||||
wheel_pos -= 170
|
||||
return wheel_pos * 3, 255 - wheel_pos * 3, 0
|
||||
|
||||
|
||||
# Go into deep sleep but shut down the RGB LED first to save power
|
||||
# Use this if you want lowest deep sleep current
|
||||
def go_deepsleep(t):
|
||||
"""Deep sleep helper that also powers down the on-board NeoPixel."""
|
||||
set_pixel_power(False)
|
||||
machine.deepsleep(t)
|
|
@ -0,0 +1,8 @@
|
|||
set(IDF_TARGET esp32s2)
|
||||
set(SDKCONFIG_DEFAULTS
|
||||
boards/sdkconfig.base
|
||||
boards/sdkconfig.spiram_sx
|
||||
boards/sdkconfig.usb
|
||||
)
|
||||
|
||||
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
|
@ -0,0 +1,12 @@
|
|||
#define MICROPY_HW_BOARD_NAME "TinyS2"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
|
||||
|
||||
#define MICROPY_PY_BLUETOOTH (0)
|
||||
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||
|
||||
#define MICROPY_HW_I2C0_SCL (9)
|
||||
#define MICROPY_HW_I2C0_SDA (8)
|
||||
|
||||
#define MICROPY_HW_SPI1_MOSI (35)
|
||||
#define MICROPY_HW_SPI1_MISO (36)
|
||||
#define MICROPY_HW_SPI1_SCK (37)
|
|
@ -0,0 +1,6 @@
|
|||
CONFIG_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_USB_AND_UART=y
|
||||
# LWIP
|
||||
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS2"
|
||||
# end of LWIP
|
|
@ -0,0 +1,11 @@
|
|||
# MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support
|
||||
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||
CONFIG_DEFAULT_PSRAM_CLK_IO=30
|
||||
CONFIG_DEFAULT_PSRAM_CS_IO=26
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||
CONFIG_SPIRAM_USE_MEMMAP=y
|
||||
CONFIG_SPIRAM_MEMTEST=y
|
|
@ -0,0 +1,7 @@
|
|||
# Notes: the offset of the partition table itself is set in
|
||||
# $IDF_PATH/components/partition_table/Kconfig.projbuild.
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x180000,
|
||||
vfs, data, fat, 0x200000, 0xD59F80,
|
|
|
@ -0,0 +1,3 @@
|
|||
import gc
|
||||
|
||||
gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)
|
|
@ -0,0 +1,5 @@
|
|||
freeze("$(BOARD_DIR)", "_boot.py", opt=3)
|
||||
freeze("$(PORT_DIR)/modules", ("apa102.py", "neopixel.py", "ntptime.py", "port_diag.py"))
|
||||
freeze("$(MPY_DIR)/drivers/dht", "dht.py")
|
||||
freeze("$(MPY_DIR)/drivers/onewire")
|
||||
include("$(MPY_DIR)/extmod/webrepl/manifest.py")
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Glenn Ruben Bakke
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Pin numbering scheme for nrf52840-based boards
|
||||
//
|
||||
// Software Pins 0-31 correspond to physical pins
|
||||
// 0.x and software Pins 32-47 correspond to physical pins 1.x.
|
||||
//
|
||||
// Example: Pin(47) would be 1.15 on the PCA10059
|
||||
|
||||
// Board data
|
||||
#define MICROPY_HW_BOARD_NAME "EVK_NINA_B3"
|
||||
#define MICROPY_HW_MCU_NAME "NRF52840"
|
||||
#define MICROPY_PY_SYS_PLATFORM "nrf52"
|
||||
|
||||
// Enable @viper and @native
|
||||
#define MICROPY_EMIT_THUMB (1)
|
||||
#define MICROPY_EMIT_INLINE_THUMB (1)
|
||||
|
||||
// Enable optional modules
|
||||
#define MICROPY_PY_UERRNO (1)
|
||||
#define MICROPY_PY_UHASHLIB (1)
|
||||
|
||||
// Peripherals Config
|
||||
#define MICROPY_PY_MACHINE_UART (1)
|
||||
#define MICROPY_PY_MACHINE_HW_PWM (1)
|
||||
#define MICROPY_PY_MACHINE_HW_SPI (1)
|
||||
#define MICROPY_PY_MACHINE_TIMER (1)
|
||||
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
|
||||
#define MICROPY_PY_MACHINE_I2C (1)
|
||||
#define MICROPY_PY_MACHINE_ADC (1)
|
||||
#define MICROPY_PY_MACHINE_TEMP (1)
|
||||
#define MICROPY_HW_ENABLE_RNG (1)
|
||||
|
||||
// Configure LEDS
|
||||
#define MICROPY_HW_HAS_LED (1)
|
||||
#define MICROPY_HW_LED_COUNT (3)
|
||||
#define MICROPY_HW_LED_PULLUP (1)
|
||||
#define MICROPY_HW_LED1 (13) // LED1 RED
|
||||
#define MICROPY_HW_LED2 (25) // LED2 GREEN
|
||||
#define MICROPY_HW_LED3 (32) // LED3 BLUE
|
||||
|
||||
// UART config
|
||||
#define MICROPY_HW_UART1_RX (29)
|
||||
#define MICROPY_HW_UART1_TX (45)
|
||||
#define MICROPY_HW_UART1_CTS (44)
|
||||
#define MICROPY_HW_UART1_RTS (31)
|
||||
#define MICROPY_HW_UART1_HWFC (1)
|
||||
|
||||
// SPI config
|
||||
#define MICROPY_HW_SPI0_NAME "SPI0"
|
||||
#define MICROPY_HW_SPI0_SCK (12)
|
||||
#define MICROPY_HW_SPI0_MOSI (14)
|
||||
#define MICROPY_HW_SPI0_MISO (15)
|
||||
|
||||
// PWM Names
|
||||
#define MICROPY_HW_PWM0_NAME "PWM0"
|
||||
#define MICROPY_HW_PWM1_NAME "PWM1"
|
||||
#define MICROPY_HW_PWM2_NAME "PWM2"
|
||||
|
||||
// How Many LED indexes appear in the help() message
|
||||
#define HELP_TEXT_BOARD_LED "1,2,3"
|
|
@ -0,0 +1,7 @@
|
|||
MCU_SERIES = m4
|
||||
MCU_VARIANT = nrf52
|
||||
MCU_SUB_VARIANT = nrf52840
|
||||
SOFTDEV_VERSION = 6.1.1
|
||||
LD_FILES += boards/nrf52840_1M_256k.ld
|
||||
|
||||
NRF_DEFINES += -DNRF52840_XXAA
|
|
@ -0,0 +1,48 @@
|
|||
P0,P0
|
||||
P1,P1
|
||||
P2,P2,ADC0_IN0
|
||||
P3,P3,ADC0_IN1
|
||||
P4,P4,ADC0_IN2
|
||||
P5,P5,ADC0_IN3
|
||||
P6,P6
|
||||
P7,P7
|
||||
P8,P8
|
||||
P9,P9
|
||||
P10,P10
|
||||
P11,P11
|
||||
P12,P12
|
||||
P13,P13
|
||||
P14,P14
|
||||
P15,P15
|
||||
P16,P16
|
||||
P17,P17
|
||||
P18,P18
|
||||
P19,P19
|
||||
P20,P20
|
||||
P21,P21
|
||||
P22,P22
|
||||
P23,P23
|
||||
P24,P24
|
||||
P25,P25
|
||||
P26,P26
|
||||
P27,P27
|
||||
P28,P28,ADC0_IN4
|
||||
P29,P29,ADC0_IN5
|
||||
P30,P30,ADC0_IN6
|
||||
P31,P31,ADC0_IN7
|
||||
P32,P32
|
||||
P33,P33
|
||||
P34,P34
|
||||
P35,P35
|
||||
P36,P36
|
||||
P37,P37
|
||||
P38,P38
|
||||
P39,P39
|
||||
P40,P40
|
||||
P41,P41
|
||||
P42,P42
|
||||
P43,P43
|
||||
P44,P44
|
||||
P45,P45
|
||||
P46,P46
|
||||
P47,P47
|
|
|
@ -0,0 +1,47 @@
|
|||
/* Vector table is at 0x00000000, entry point is 0x10000000. */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ROM : ORIGIN = 0x00000000, LENGTH = 96K
|
||||
RAM : ORIGIN = 0x10000000, LENGTH = 128M
|
||||
}
|
||||
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.rom : {
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector))
|
||||
. = ALIGN(4);
|
||||
} > ROM
|
||||
|
||||
.text : {
|
||||
. = ALIGN(4);
|
||||
*(.text.Reset_Handler)
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_sidata = _etext;
|
||||
} > RAM
|
||||
|
||||
.data : AT ( _sidata )
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > RAM
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
# cmake file for SparkFun Pro Micro RP2040
|
|
@ -0,0 +1,3 @@
|
|||
// Board and hardware specific configuration
|
||||
#define MICROPY_HW_BOARD_NAME "SparkFun Pro Micro RP2040"
|
||||
#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
|
|
@ -0,0 +1 @@
|
|||
# cmake file for SparkFun Thing Plus RP2040
|
|
@ -0,0 +1,3 @@
|
|||
// Board and hardware specific configuration
|
||||
#define MICROPY_HW_BOARD_NAME "SparkFun Thing Plus RP2040"
|
||||
#define MICROPY_HW_FLASH_STORAGE_BYTES (15 * 1024 * 1024)
|
|
@ -0,0 +1,3 @@
|
|||
freeze("$(PORT_DIR)/modules")
|
||||
freeze("$(MPY_DIR)/drivers/onewire")
|
||||
include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 "Krzysztof Adamski" <k@japko.eu>
|
||||
*
|
||||
* 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 <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/timeutils/timeutils.h"
|
||||
#include "hardware/rtc.h"
|
||||
#include "pico/util/datetime.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
typedef struct _machine_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
} machine_rtc_obj_t;
|
||||
|
||||
// singleton RTC object
|
||||
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
|
||||
|
||||
STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
bool r = rtc_running();
|
||||
|
||||
if (!r) {
|
||||
// This shouldn't happen as rtc_init() is already called in main so
|
||||
// it's here just in case
|
||||
rtc_init();
|
||||
datetime_t t = { .month = 1, .day = 1 };
|
||||
rtc_set_datetime(&t);
|
||||
}
|
||||
// return constant object
|
||||
return (mp_obj_t)&machine_rtc_obj;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 1) {
|
||||
bool ret;
|
||||
datetime_t t;
|
||||
|
||||
ret = rtc_get_datetime(&t);
|
||||
if (!ret) {
|
||||
mp_raise_OSError(MP_EIO);
|
||||
}
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(t.year),
|
||||
mp_obj_new_int(t.month),
|
||||
mp_obj_new_int(t.day),
|
||||
mp_obj_new_int(t.dotw),
|
||||
mp_obj_new_int(t.hour),
|
||||
mp_obj_new_int(t.min),
|
||||
mp_obj_new_int(t.sec),
|
||||
mp_obj_new_int(0)
|
||||
};
|
||||
|
||||
return mp_obj_new_tuple(8, tuple);
|
||||
} else {
|
||||
mp_obj_t *items;
|
||||
|
||||
mp_obj_get_array_fixed_n(args[1], 8, &items);
|
||||
|
||||
datetime_t t = {
|
||||
.year = mp_obj_get_int(items[0]),
|
||||
.month = mp_obj_get_int(items[1]),
|
||||
.day = mp_obj_get_int(items[2]),
|
||||
.dotw = mp_obj_get_int(items[3]),
|
||||
.hour = mp_obj_get_int(items[4]),
|
||||
.min = mp_obj_get_int(items[5]),
|
||||
.sec = mp_obj_get_int(items[6]),
|
||||
};
|
||||
|
||||
if (!rtc_set_datetime(&t)) {
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t machine_rtc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_RTC,
|
||||
.make_new = machine_rtc_make_new,
|
||||
.locals_dict = (mp_obj_t)&machine_rtc_locals_dict,
|
||||
};
|
|
@ -270,6 +270,13 @@ STATIC mp_obj_t extra_coverage(void) {
|
|||
size_t len = mp_repl_autocomplete("__n", 3, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
|
||||
len = mp_repl_autocomplete("i", 1, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
mp_repl_autocomplete("import ", 7, &mp_plat_print, &str);
|
||||
len = mp_repl_autocomplete("import ut", 9, &mp_plat_print, &str);
|
||||
mp_printf(&mp_plat_print, "%.*s\n", (int)len, str);
|
||||
mp_repl_autocomplete("import utime", 12, &mp_plat_print, &str);
|
||||
|
||||
mp_store_global(MP_QSTR_sys, mp_import_name(MP_QSTR_sys, mp_const_none, MP_OBJ_NEW_SMALL_INT(0)));
|
||||
mp_repl_autocomplete("sys.", 4, &mp_plat_print, &str);
|
||||
len = mp_repl_autocomplete("sys.impl", 8, &mp_plat_print, &str);
|
||||
|
@ -485,7 +492,7 @@ STATIC mp_obj_t extra_coverage(void) {
|
|||
}
|
||||
|
||||
// setting the keyboard interrupt and raising it during mp_handle_pending
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_handle_pending(true);
|
||||
|
@ -495,13 +502,13 @@ STATIC mp_obj_t extra_coverage(void) {
|
|||
}
|
||||
|
||||
// setting the keyboard interrupt (twice) and cancelling it during mp_handle_pending
|
||||
mp_keyboard_interrupt();
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
mp_handle_pending(false);
|
||||
|
||||
// setting keyboard interrupt and a pending event (intr should be handled first)
|
||||
mp_sched_schedule(MP_OBJ_FROM_PTR(&mp_builtin_print_obj), MP_OBJ_NEW_SMALL_INT(10));
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_handle_pending(true);
|
||||
nlr_pop();
|
||||
|
|
|
@ -450,7 +450,13 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
|||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
mp_stack_set_limit(40000 * (sizeof(void *) / 4));
|
||||
// Define a reasonable stack limit to detect stack overflow.
|
||||
mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
|
||||
#if defined(__arm__) && !defined(__thumb2__)
|
||||
// ARM (non-Thumb) architectures require more stack.
|
||||
stack_limit *= 2;
|
||||
#endif
|
||||
mp_stack_set_limit(stack_limit);
|
||||
|
||||
pre_process_options(argc, argv);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/objint.h"
|
||||
|
||||
#include "supervisor/shared/translate.h"
|
||||
|
||||
|
@ -58,6 +59,18 @@
|
|||
* but may be later.
|
||||
*/
|
||||
|
||||
// This union is large enough to hold any supported argument/return value.
|
||||
typedef union _ffi_union_t {
|
||||
ffi_arg ffi;
|
||||
unsigned char B;
|
||||
unsigned short int H;
|
||||
unsigned int I;
|
||||
unsigned long int L;
|
||||
unsigned long long int Q;
|
||||
float flt;
|
||||
double dbl;
|
||||
} ffi_union_t;
|
||||
|
||||
typedef struct _mp_obj_opaque_t {
|
||||
mp_obj_base_t base;
|
||||
void *val;
|
||||
|
@ -153,10 +166,10 @@ STATIC ffi_type *get_ffi_type(mp_obj_t o_in) {
|
|||
mp_raise_TypeError(MP_ERROR_TEXT("unknown type"));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
|
||||
STATIC mp_obj_t return_ffi_value(ffi_union_t *val, char type) {
|
||||
switch (type) {
|
||||
case 's': {
|
||||
const char *s = (const char *)(intptr_t)val;
|
||||
const char *s = (const char *)(intptr_t)val->ffi;
|
||||
if (!s) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
@ -166,20 +179,30 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
|
|||
return mp_const_none;
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f': {
|
||||
union { ffi_arg ffi;
|
||||
float flt;
|
||||
} val_union = { .ffi = val };
|
||||
return mp_obj_new_float_from_f(val_union.flt);
|
||||
return mp_obj_new_float_from_f(val->flt);
|
||||
}
|
||||
case 'd': {
|
||||
double *p = (double *)&val;
|
||||
return mp_obj_new_float_from_d(*p);
|
||||
return mp_obj_new_float_from_d(val->dbl);
|
||||
}
|
||||
#endif
|
||||
case 'b':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'l':
|
||||
return mp_obj_new_int((signed)val->ffi);
|
||||
case 'B':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'L':
|
||||
return mp_obj_new_int_from_uint(val->ffi);
|
||||
case 'q':
|
||||
return mp_obj_new_int_from_ll(val->Q);
|
||||
case 'Q':
|
||||
return mp_obj_new_int_from_ull(val->Q);
|
||||
case 'O':
|
||||
return (mp_obj_t)(intptr_t)val;
|
||||
return (mp_obj_t)(intptr_t)val->ffi;
|
||||
default:
|
||||
return mp_obj_new_int(val);
|
||||
return mp_obj_new_int(val->ffi);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,34 +387,74 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
|
|||
mp_printf(print, "<ffifunc %p>", self->func);
|
||||
}
|
||||
|
||||
STATIC unsigned long long ffi_get_int_value(mp_obj_t o) {
|
||||
if (mp_obj_is_small_int(o)) {
|
||||
return MP_OBJ_SMALL_INT_VALUE(o);
|
||||
} else {
|
||||
unsigned long long res;
|
||||
mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
|
||||
ffi_union_t ret;
|
||||
if ((argtype | 0x20) == 'q') {
|
||||
ret.Q = ffi_get_int_value(o);
|
||||
return ret;
|
||||
} else {
|
||||
mp_uint_t val = mp_obj_int_get_truncated(o);
|
||||
switch (argtype) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
ret.B = val;
|
||||
break;
|
||||
case 'h':
|
||||
case 'H':
|
||||
ret.H = val;
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
ret.I = val;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
ret.L = val;
|
||||
break;
|
||||
default:
|
||||
ret.ffi = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
(void)n_kw;
|
||||
mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
assert(n_kw == 0);
|
||||
assert(n_args == self->cif.nargs);
|
||||
|
||||
ffi_arg values[n_args];
|
||||
ffi_union_t values[n_args];
|
||||
void *valueptrs[n_args];
|
||||
const char *argtype = self->argtypes;
|
||||
for (uint i = 0; i < n_args; i++, argtype++) {
|
||||
mp_obj_t a = args[i];
|
||||
if (*argtype == 'O') {
|
||||
values[i] = (ffi_arg)(intptr_t)a;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)a;
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (*argtype == 'f') {
|
||||
float *p = (float *)&values[i];
|
||||
*p = mp_obj_get_float_to_f(a);
|
||||
values[i].flt = mp_obj_get_float_to_f(a);
|
||||
} else if (*argtype == 'd') {
|
||||
double *p = (double *)&values[i];
|
||||
*p = mp_obj_get_float_to_d(a);
|
||||
values[i].dbl = mp_obj_get_float_to_d(a);
|
||||
#endif
|
||||
} else if (a == mp_const_none) {
|
||||
values[i] = 0;
|
||||
values[i].ffi = 0;
|
||||
} else if (mp_obj_is_int(a)) {
|
||||
values[i] = mp_obj_int_get_truncated(a);
|
||||
values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
|
||||
} else if (mp_obj_is_str(a)) {
|
||||
const char *s = mp_obj_str_get_str(a);
|
||||
values[i] = (ffi_arg)(intptr_t)s;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)s;
|
||||
} else if (((mp_obj_base_t *)MP_OBJ_TO_PTR(a))->type->buffer_p.get_buffer != NULL) {
|
||||
mp_obj_base_t *o = (mp_obj_base_t *)MP_OBJ_TO_PTR(a);
|
||||
mp_buffer_info_t bufinfo;
|
||||
|
@ -399,32 +462,19 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
|||
if (ret != 0) {
|
||||
goto error;
|
||||
}
|
||||
values[i] = (ffi_arg)(intptr_t)bufinfo.buf;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)bufinfo.buf;
|
||||
} else if (mp_obj_is_type(a, &fficallback_type)) {
|
||||
mp_obj_fficallback_t *p = MP_OBJ_TO_PTR(a);
|
||||
values[i] = (ffi_arg)(intptr_t)p->func;
|
||||
values[i].ffi = (ffi_arg)(intptr_t)p->func;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
valueptrs[i] = &values[i];
|
||||
}
|
||||
|
||||
// If ffi_arg is not big enough to hold a double, then we must pass along a
|
||||
// pointer to a memory location of the correct size.
|
||||
// TODO check if this needs to be done for other types which don't fit into
|
||||
// ffi_arg.
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
if (sizeof(ffi_arg) == 4 && self->rettype == 'd') {
|
||||
double retval;
|
||||
ffi_union_t retval;
|
||||
ffi_call(&self->cif, self->func, &retval, valueptrs);
|
||||
return mp_obj_new_float_from_d(retval);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ffi_arg retval;
|
||||
ffi_call(&self->cif, self->func, &retval, valueptrs);
|
||||
return return_ffi_value(retval, self->rettype);
|
||||
}
|
||||
return return_ffi_value(&retval, self->rettype);
|
||||
|
||||
error:
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("Don't know how to pass object to native function"));
|
||||
|
|
|
@ -126,7 +126,7 @@ void mp_thread_init(void) {
|
|||
thread->next = NULL;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%d", (int)thread->id);
|
||||
snprintf(thread_signal_done_name, sizeof(thread_signal_done_name), "micropython_sem_%ld", (long)thread->id);
|
||||
thread_signal_done_p = sem_open(thread_signal_done_name, O_CREAT | O_EXCL, 0666, 0);
|
||||
#else
|
||||
sem_init(&thread_signal_done, 0, 0);
|
||||
|
|
|
@ -57,7 +57,7 @@ STATIC void sighandler(int signum) {
|
|||
// this is the second time we are called, so die straight away
|
||||
exit(1);
|
||||
}
|
||||
mp_keyboard_interrupt();
|
||||
mp_sched_keyboard_interrupt();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
CONFIG_CONSOLE_SUBSYS=n
|
||||
CONFIG_NETWORKING=n
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
|
||||
CONFIG_BT_PERIPHERAL=y
|
||||
CONFIG_BT_CENTRAL=y
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Damien P. George
|
||||
* Copyright (c) 2019-2020 Jim Mussared
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include "extmod/modbluetooth.h"
|
||||
|
||||
#define DEBUG_printf(...) // printk("BLE: " __VA_ARGS__)
|
||||
|
||||
#define BLE_HCI_SCAN_ITVL_MIN 0x10
|
||||
#define BLE_HCI_SCAN_ITVL_MAX 0xffff
|
||||
#define BLE_HCI_SCAN_WINDOW_MIN 0x10
|
||||
#define BLE_HCI_SCAN_WINDOW_MAX 0xffff
|
||||
|
||||
#define ERRNO_BLUETOOTH_NOT_ACTIVE MP_ENODEV
|
||||
|
||||
enum {
|
||||
MP_BLUETOOTH_ZEPHYR_BLE_STATE_OFF,
|
||||
MP_BLUETOOTH_ZEPHYR_BLE_STATE_ACTIVE,
|
||||
MP_BLUETOOTH_ZEPHYR_BLE_STATE_SUSPENDED,
|
||||
};
|
||||
|
||||
enum {
|
||||
MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_INACTIVE,
|
||||
MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_DEACTIVATING,
|
||||
MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_ACTIVE,
|
||||
};
|
||||
|
||||
typedef struct _mp_bluetooth_zephyr_root_pointers_t {
|
||||
// Characteristic (and descriptor) value storage.
|
||||
mp_gatts_db_t gatts_db;
|
||||
} mp_bluetooth_zephyr_root_pointers_t;
|
||||
|
||||
STATIC int mp_bluetooth_zephyr_ble_state;
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
STATIC int mp_bluetooth_zephyr_gap_scan_state;
|
||||
STATIC struct k_timer mp_bluetooth_zephyr_gap_scan_timer;
|
||||
STATIC struct bt_le_scan_cb mp_bluetooth_zephyr_gap_scan_cb_struct;
|
||||
#endif
|
||||
|
||||
STATIC int bt_err_to_errno(int err) {
|
||||
// Zephyr uses errno codes directly, but they are negative.
|
||||
return -err;
|
||||
}
|
||||
|
||||
// modbluetooth (and the layers above it) work in BE for addresses, Zephyr works in LE.
|
||||
STATIC void reverse_addr_byte_order(uint8_t *addr_out, const bt_addr_le_t *addr_in) {
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
addr_out[i] = addr_in->a.val[5 - i];
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
void gap_scan_cb_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) {
|
||||
DEBUG_printf("gap_scan_cb_recv: adv_type=%d\n", info->adv_type);
|
||||
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp_bluetooth_zephyr_gap_scan_state != MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t addr[6];
|
||||
reverse_addr_byte_order(addr, info->addr);
|
||||
mp_bluetooth_gap_on_scan_result(info->addr->type, addr, info->adv_type, info->rssi, buf->data, buf->len);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t gap_scan_stop(mp_obj_t unused) {
|
||||
(void)unused;
|
||||
mp_bluetooth_gap_scan_stop();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gap_scan_stop_obj, gap_scan_stop);
|
||||
|
||||
void gap_scan_cb_timeout(struct k_timer *timer_id) {
|
||||
DEBUG_printf("gap_scan_cb_timeout\n");
|
||||
// Cannot call bt_le_scan_stop from a timer callback because this callback may be
|
||||
// preempting the BT stack. So schedule it to be called from the main thread.
|
||||
while (!mp_sched_schedule(MP_OBJ_FROM_PTR(&gap_scan_stop_obj), mp_const_none)) {
|
||||
k_yield();
|
||||
}
|
||||
// Indicate scanning has stopped so that no more scan result events are generated
|
||||
// (they may still come in until bt_le_scan_stop is called by gap_scan_stop).
|
||||
mp_bluetooth_zephyr_gap_scan_state = MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_DEACTIVATING;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mp_bluetooth_init(void) {
|
||||
DEBUG_printf("mp_bluetooth_init\n");
|
||||
|
||||
// Clean up if necessary.
|
||||
mp_bluetooth_deinit();
|
||||
|
||||
// Allocate memory for state.
|
||||
MP_STATE_PORT(bluetooth_zephyr_root_pointers) = m_new0(mp_bluetooth_zephyr_root_pointers_t, 1);
|
||||
mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db);
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
mp_bluetooth_zephyr_gap_scan_state = MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_INACTIVE;
|
||||
k_timer_init(&mp_bluetooth_zephyr_gap_scan_timer, gap_scan_cb_timeout, NULL);
|
||||
mp_bluetooth_zephyr_gap_scan_cb_struct.recv = gap_scan_cb_recv;
|
||||
mp_bluetooth_zephyr_gap_scan_cb_struct.timeout = NULL; // currently not implemented in Zephyr
|
||||
bt_le_scan_cb_register(&mp_bluetooth_zephyr_gap_scan_cb_struct);
|
||||
#endif
|
||||
|
||||
if (mp_bluetooth_zephyr_ble_state == MP_BLUETOOTH_ZEPHYR_BLE_STATE_OFF) {
|
||||
// bt_enable can only be called once.
|
||||
int ret = bt_enable(NULL);
|
||||
if (ret) {
|
||||
return bt_err_to_errno(ret);
|
||||
}
|
||||
}
|
||||
|
||||
mp_bluetooth_zephyr_ble_state = MP_BLUETOOTH_ZEPHYR_BLE_STATE_ACTIVE;
|
||||
|
||||
DEBUG_printf("mp_bluetooth_init: ready\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mp_bluetooth_deinit(void) {
|
||||
DEBUG_printf("mp_bluetooth_deinit %d\n", mp_bluetooth_zephyr_ble_state);
|
||||
if (mp_bluetooth_zephyr_ble_state == MP_BLUETOOTH_ZEPHYR_BLE_STATE_OFF
|
||||
|| mp_bluetooth_zephyr_ble_state == MP_BLUETOOTH_ZEPHYR_BLE_STATE_SUSPENDED) {
|
||||
return;
|
||||
}
|
||||
|
||||
mp_bluetooth_gap_advertise_stop();
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
mp_bluetooth_gap_scan_stop();
|
||||
bt_le_scan_cb_unregister(&mp_bluetooth_zephyr_gap_scan_cb_struct);
|
||||
#endif
|
||||
|
||||
// There is no way to turn off the BT stack in Zephyr, so just set the
|
||||
// state as suspended so it can be correctly reactivated later.
|
||||
mp_bluetooth_zephyr_ble_state = MP_BLUETOOTH_ZEPHYR_BLE_STATE_SUSPENDED;
|
||||
|
||||
MP_STATE_PORT(bluetooth_zephyr_root_pointers) = NULL;
|
||||
}
|
||||
|
||||
bool mp_bluetooth_is_active(void) {
|
||||
return mp_bluetooth_zephyr_ble_state == MP_BLUETOOTH_ZEPHYR_BLE_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
void mp_bluetooth_get_current_address(uint8_t *addr_type, uint8_t *addr) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
|
||||
}
|
||||
bt_addr_le_t le_addr;
|
||||
size_t count = 1;
|
||||
bt_id_get(&le_addr, &count);
|
||||
if (count == 0) {
|
||||
mp_raise_OSError(EIO);
|
||||
}
|
||||
reverse_addr_byte_order(addr, &le_addr);
|
||||
*addr_type = le_addr.type;
|
||||
}
|
||||
|
||||
void mp_bluetooth_set_address_mode(uint8_t addr_mode) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
|
||||
const char *name = bt_get_name();
|
||||
*buf = (const uint8_t *)name;
|
||||
return strlen(name);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_set_device_name(const uint8_t *buf, size_t len) {
|
||||
char tmp_buf[CONFIG_BT_DEVICE_NAME_MAX + 1];
|
||||
if (len + 1 > sizeof(tmp_buf)) {
|
||||
return MP_EINVAL;
|
||||
}
|
||||
memcpy(tmp_buf, buf, len);
|
||||
tmp_buf[len] = '\0';
|
||||
return bt_err_to_errno(bt_set_name(tmp_buf));
|
||||
}
|
||||
|
||||
// Zephyr takes advertising/scan data as an array of (type, len, payload) packets,
|
||||
// and this function constructs such an array from raw advertising/scan data.
|
||||
STATIC void mp_bluetooth_prepare_bt_data(const uint8_t *data, size_t len, struct bt_data *bt_data, size_t *bt_len) {
|
||||
size_t i = 0;
|
||||
const uint8_t *d = data;
|
||||
while (d < data + len && i < *bt_len) {
|
||||
bt_data[i].type = d[1];
|
||||
bt_data[i].data_len = d[0] - 1;
|
||||
bt_data[i].data = &d[2];
|
||||
i += 1;
|
||||
d += 1 + d[0];
|
||||
}
|
||||
*bt_len = i;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_advertise_start(bool connectable, int32_t interval_us, const uint8_t *adv_data, size_t adv_data_len, const uint8_t *sr_data, size_t sr_data_len) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
mp_bluetooth_gap_advertise_stop();
|
||||
|
||||
struct bt_data bt_ad_data[8];
|
||||
size_t bt_ad_len = 0;
|
||||
if (adv_data) {
|
||||
bt_ad_len = MP_ARRAY_SIZE(bt_ad_data);
|
||||
mp_bluetooth_prepare_bt_data(adv_data, adv_data_len, bt_ad_data, &bt_ad_len);
|
||||
}
|
||||
|
||||
struct bt_data bt_sd_data[8];
|
||||
size_t bt_sd_len = 0;
|
||||
if (sr_data) {
|
||||
bt_sd_len = MP_ARRAY_SIZE(bt_sd_data);
|
||||
mp_bluetooth_prepare_bt_data(sr_data, sr_data_len, bt_sd_data, &bt_sd_len);
|
||||
}
|
||||
|
||||
struct bt_le_adv_param param = {
|
||||
.id = 0,
|
||||
.sid = 0,
|
||||
.secondary_max_skip = 0,
|
||||
.options = (connectable ? BT_LE_ADV_OPT_CONNECTABLE : 0)
|
||||
| BT_LE_ADV_OPT_ONE_TIME
|
||||
| BT_LE_ADV_OPT_USE_IDENTITY
|
||||
| BT_LE_ADV_OPT_SCANNABLE,
|
||||
.interval_min = interval_us / 625,
|
||||
.interval_max = interval_us / 625 + 1, // min/max cannot be the same value
|
||||
.peer = NULL,
|
||||
};
|
||||
|
||||
return bt_err_to_errno(bt_le_adv_start(¶m, bt_ad_data, bt_ad_len, bt_sd_data, bt_sd_len));
|
||||
}
|
||||
|
||||
void mp_bluetooth_gap_advertise_stop(void) {
|
||||
// Note: bt_le_adv_stop returns 0 if adv is already stopped.
|
||||
int ret = bt_le_adv_stop();
|
||||
if (ret != 0) {
|
||||
mp_raise_OSError(bt_err_to_errno(ret));
|
||||
}
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_register_service_begin(bool append) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
|
||||
if (append) {
|
||||
// Don't support append yet (modbluetooth.c doesn't support it yet anyway).
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
// Reset the gatt characteristic value db.
|
||||
mp_bluetooth_gatts_db_reset(MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db);
|
||||
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_register_service_end(void) {
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, mp_obj_bluetooth_uuid_t **characteristic_uuids, uint16_t *characteristic_flags, mp_obj_bluetooth_uuid_t **descriptor_uuids, uint16_t *descriptor_flags, uint8_t *num_descriptors, uint16_t *handles, size_t num_characteristics) {
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_disconnect(uint16_t conn_handle) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db, value_handle, value, value_len);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_zephyr_root_pointers)->gatts_db, value_handle, value, value_len);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mp_bluetooth_get_preferred_mtu(void) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
mp_raise_OSError(ERRNO_BLUETOOTH_NOT_ACTIVE);
|
||||
}
|
||||
mp_raise_OSError(MP_EOPNOTSUPP);
|
||||
}
|
||||
|
||||
int mp_bluetooth_set_preferred_mtu(uint16_t mtu) {
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
|
||||
int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_t window_us, bool active_scan) {
|
||||
// Stop any ongoing GAP scan.
|
||||
int ret = mp_bluetooth_gap_scan_stop();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct bt_le_scan_param param = {
|
||||
.type = active_scan ? BT_HCI_LE_SCAN_ACTIVE : BT_HCI_LE_SCAN_PASSIVE,
|
||||
.options = BT_LE_SCAN_OPT_NONE,
|
||||
.interval = MAX(BLE_HCI_SCAN_ITVL_MIN, MIN(BLE_HCI_SCAN_ITVL_MAX, interval_us / 625)),
|
||||
.window = MAX(BLE_HCI_SCAN_WINDOW_MIN, MIN(BLE_HCI_SCAN_WINDOW_MAX, window_us / 625)),
|
||||
};
|
||||
k_timer_start(&mp_bluetooth_zephyr_gap_scan_timer, K_MSEC(duration_ms), K_NO_WAIT);
|
||||
mp_bluetooth_zephyr_gap_scan_state = MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_ACTIVE;
|
||||
int err = bt_le_scan_start(¶m, NULL);
|
||||
return bt_err_to_errno(err);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_scan_stop(void) {
|
||||
DEBUG_printf("mp_bluetooth_gap_scan_stop\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
if (mp_bluetooth_zephyr_gap_scan_state == MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_INACTIVE) {
|
||||
// Already stopped.
|
||||
return 0;
|
||||
}
|
||||
mp_bluetooth_zephyr_gap_scan_state = MP_BLUETOOTH_ZEPHYR_GAP_SCAN_STATE_INACTIVE;
|
||||
k_timer_stop(&mp_bluetooth_zephyr_gap_scan_timer);
|
||||
int err = bt_le_scan_stop();
|
||||
if (err == 0) {
|
||||
mp_bluetooth_gap_on_scan_complete();
|
||||
return 0;
|
||||
}
|
||||
return bt_err_to_errno(err);
|
||||
}
|
||||
|
||||
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
|
||||
DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
|
||||
if (!mp_bluetooth_is_active()) {
|
||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||
}
|
||||
return MP_EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||
|
||||
#endif // MICROPY_PY_BLUETOOTH
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
static struct k_poll_signal wait_signal;
|
||||
static struct k_poll_event wait_events[2] = {
|
||||
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
&wait_signal),
|
||||
K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
|
||||
K_POLL_MODE_NOTIFY_ONLY,
|
||||
NULL, 0),
|
||||
};
|
||||
|
||||
void mp_hal_init(void) {
|
||||
k_poll_signal_init(&wait_signal);
|
||||
}
|
||||
|
||||
void mp_hal_signal_event(void) {
|
||||
k_poll_signal_raise(&wait_signal, 0);
|
||||
}
|
||||
|
||||
void mp_hal_wait_sem(struct k_sem *sem, uint32_t timeout_ms) {
|
||||
mp_uint_t t0 = mp_hal_ticks_ms();
|
||||
if (sem) {
|
||||
k_poll_event_init(&wait_events[1], K_POLL_TYPE_SEM_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, sem);
|
||||
}
|
||||
for (;;) {
|
||||
k_timeout_t wait;
|
||||
if (timeout_ms == (uint32_t)-1) {
|
||||
wait = K_FOREVER;
|
||||
} else {
|
||||
uint32_t dt = mp_hal_ticks_ms() - t0;
|
||||
if (dt >= timeout_ms) {
|
||||
return;
|
||||
}
|
||||
wait = K_MSEC(timeout_ms - dt);
|
||||
}
|
||||
k_poll(wait_events, sem ? 2 : 1, wait);
|
||||
if (wait_events[0].state == K_POLL_STATE_SIGNALED) {
|
||||
wait_events[0].signal->signaled = 0;
|
||||
wait_events[0].state = K_POLL_STATE_NOT_READY;
|
||||
mp_handle_pending(true);
|
||||
} else if (sem && wait_events[1].state == K_POLL_STATE_SEM_AVAILABLE) {
|
||||
wait_events[1].state = K_POLL_STATE_NOT_READY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
|||
size_t n_args_max = (sig >> 1) & 0xffff;
|
||||
|
||||
if (n_kw && !takes_kw) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("function doesn't take keyword arguments"));
|
||||
|
@ -49,7 +49,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
|||
|
||||
if (n_args_min == n_args_max) {
|
||||
if (n_args != n_args_min) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("function takes %d positional arguments but %d were given"),
|
||||
|
@ -58,7 +58,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
|||
}
|
||||
} else {
|
||||
if (n_args < n_args_min) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -66,7 +66,7 @@ void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
|||
n_args_min - n_args);
|
||||
#endif
|
||||
} else if (n_args > n_args_max) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -106,7 +106,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
|||
}
|
||||
if (kw == NULL) {
|
||||
if (allowed[i].flags & MP_ARG_REQUIRED) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' argument required"), allowed[i].qst);
|
||||
|
@ -130,7 +130,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
|||
}
|
||||
if (pos_found < n_pos) {
|
||||
extra_positional:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
// TODO better error message
|
||||
|
@ -138,7 +138,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n
|
|||
#endif
|
||||
}
|
||||
if (kws != NULL && kws_found < kws->used) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
// TODO better error message
|
||||
|
|
19
py/asmarm.c
19
py/asmarm.c
|
@ -38,25 +38,6 @@
|
|||
|
||||
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as) {
|
||||
if (as->base.pass == MP_ASM_PASS_EMIT) {
|
||||
#if defined(__linux__) && defined(__GNUC__)
|
||||
char *start = mp_asm_base_get_code(&as->base);
|
||||
char *end = start + mp_asm_base_get_code_size(&as->base);
|
||||
__builtin___clear_cache(start, end);
|
||||
#elif defined(__arm__)
|
||||
// flush I- and D-cache
|
||||
asm volatile (
|
||||
"0:"
|
||||
"mrc p15, 0, r15, c7, c10, 3\n"
|
||||
"bne 0b\n"
|
||||
"mov r0, #0\n"
|
||||
"mcr p15, 0, r0, c7, c7, 0\n"
|
||||
: : : "r0", "cc");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Insert word into instruction flow
|
||||
STATIC void emit(asm_arm_t *as, uint op) {
|
||||
uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
|
||||
|
|
|
@ -72,7 +72,9 @@ typedef struct _asm_arm_t {
|
|||
uint stack_adjust;
|
||||
} asm_arm_t;
|
||||
|
||||
void asm_arm_end_pass(asm_arm_t *as);
|
||||
static inline void asm_arm_end_pass(asm_arm_t *as) {
|
||||
(void)as;
|
||||
}
|
||||
|
||||
void asm_arm_entry(asm_arm_t *as, int num_locals);
|
||||
void asm_arm_exit(asm_arm_t *as);
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
|
||||
#include "py/mpstate.h"
|
||||
#include "py/persistentcode.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/asmthumb.h"
|
||||
|
||||
#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32)
|
||||
|
@ -62,20 +61,6 @@ static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
|
|||
return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
|
||||
}
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
(void)as;
|
||||
// could check labels are resolved...
|
||||
|
||||
#if defined(__ICACHE_PRESENT) && __ICACHE_PRESENT == 1
|
||||
if (as->base.pass == MP_ASM_PASS_EMIT) {
|
||||
// flush D-cache, so the code emitted is stored in memory
|
||||
MP_HAL_CLEAN_DCACHE(as->base.code_base, as->base.code_size);
|
||||
// invalidate I-cache
|
||||
SCB_InvalidateICache();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {
|
||||
byte *c = asm_thumb_get_cur_to_write_bytes(as, 1);
|
||||
|
|
|
@ -70,7 +70,9 @@ typedef struct _asm_thumb_t {
|
|||
uint32_t stack_adjust;
|
||||
} asm_thumb_t;
|
||||
|
||||
void asm_thumb_end_pass(asm_thumb_t *as);
|
||||
static inline void asm_thumb_end_pass(asm_thumb_t *as) {
|
||||
(void)as;
|
||||
}
|
||||
|
||||
void asm_thumb_entry(asm_thumb_t *as, int num_locals);
|
||||
void asm_thumb_exit(asm_thumb_t *as);
|
||||
|
|
15
py/asmx64.c
15
py/asmx64.c
|
@ -285,31 +285,28 @@ void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest
|
|||
}
|
||||
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem32_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
if (src_r64 < 8 && dest_r64 < 8) {
|
||||
asm_x64_write_byte_1(as, OPCODE_MOV_RM64_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_R, OPCODE_MOV_RM64_TO_R64);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_R_FROM_R64(dest_r64) | REX_B_FROM_R64(src_r64), OPCODE_MOV_RM64_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
|
4
py/bc.c
4
py/bc.c
|
@ -77,7 +77,7 @@ const byte *mp_decode_uint_skip(const byte *ptr) {
|
|||
#endif
|
||||
|
||||
STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
// generic message, used also for other argument issues
|
||||
(void)f;
|
||||
(void)expected;
|
||||
|
@ -221,7 +221,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw
|
|||
}
|
||||
// Didn't find name match with positional args
|
||||
if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("unexpected keyword argument"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
|
|
@ -332,7 +332,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
|||
|
||||
// We must have some component left over to import from
|
||||
if (p == this_name) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("cannot perform relative import"));
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("cannot perform relative import"));
|
||||
}
|
||||
|
||||
uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len);
|
||||
|
@ -421,7 +421,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
|||
mp_module_call_init(mod_name, module_obj);
|
||||
} else {
|
||||
// couldn't find the file, so fail
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ImportError(MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError,
|
||||
|
@ -533,7 +533,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) {
|
|||
#endif
|
||||
|
||||
// Couldn't find the module, so fail
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_msg(&mp_type_ImportError, MP_ERROR_TEXT("module not found"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("no module named '%q'"), module_name_qstr);
|
||||
|
|
35
py/compile.c
35
py/compile.c
|
@ -1795,16 +1795,6 @@ STATIC void compile_yield_from(compiler_t *comp) {
|
|||
}
|
||||
|
||||
#if MICROPY_PY_ASYNC_AWAIT
|
||||
STATIC bool compile_require_async_context(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
int scope_flags = comp->scope_cur->scope_flags;
|
||||
if ((scope_flags & MP_SCOPE_FLAG_ASYNC) != 0) {
|
||||
return true;
|
||||
}
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns,
|
||||
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
|
||||
EMIT_ARG(load_method, method, false);
|
||||
EMIT_ARG(call_method, 0, 0, 0);
|
||||
|
@ -1813,11 +1803,6 @@ STATIC void compile_await_object_method(compiler_t *comp, qstr method) {
|
|||
|
||||
STATIC void compile_async_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||
|
||||
if (!compile_require_async_context(comp, pns)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qstr context = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
|
||||
uint while_else_label = comp_next_label(comp);
|
||||
uint try_exception_label = comp_next_label(comp);
|
||||
|
@ -1980,9 +1965,6 @@ STATIC void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_
|
|||
}
|
||||
|
||||
STATIC void compile_async_with_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (!compile_require_async_context(comp, pns)) {
|
||||
return;
|
||||
}
|
||||
// get the nodes for the pre-bit of the with (the a as b, c as d, ... bit)
|
||||
mp_parse_node_t *nodes;
|
||||
size_t n = mp_parse_node_extract_list(&pns->nodes[0], PN_with_stmt_list, &nodes);
|
||||
|
@ -2000,7 +1982,16 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
compile_funcdef(comp, pns0);
|
||||
scope_t *fscope = (scope_t *)pns0->nodes[4];
|
||||
fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR | MP_SCOPE_FLAG_ASYNC;
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
|
||||
} else {
|
||||
// async for/with; first verify the scope is a generator
|
||||
int scope_flags = comp->scope_cur->scope_flags;
|
||||
if (!(scope_flags & MP_SCOPE_FLAG_GENERATOR)) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns0,
|
||||
MP_ERROR_TEXT("'await', 'async for' or 'async with' outside async function"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns0) == PN_for_stmt) {
|
||||
// async for
|
||||
compile_async_for_stmt(comp, pns0);
|
||||
} else {
|
||||
|
@ -2009,6 +2000,7 @@ STATIC void compile_async_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
compile_async_with_stmt(comp, pns0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
@ -2627,7 +2619,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
|
|||
compile_node(comp, pn_i);
|
||||
if (is_dict) {
|
||||
if (!is_key_value) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
|
||||
#else
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting key:value for dict"));
|
||||
|
@ -2637,7 +2629,7 @@ STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *
|
|||
EMIT(store_map);
|
||||
} else {
|
||||
if (is_key_value) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("invalid syntax"));
|
||||
#else
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("expecting just a value for set"));
|
||||
|
@ -2799,7 +2791,6 @@ STATIC void compile_atom_expr_await(compiler_t *comp, mp_parse_node_struct_t *pn
|
|||
compile_syntax_error(comp, (mp_parse_node_t)pns, MP_ERROR_TEXT("'await' outside function"));
|
||||
return;
|
||||
}
|
||||
compile_require_async_context(comp, pns);
|
||||
compile_atom_expr_normal(comp, pns);
|
||||
|
||||
// If it's an awaitable thing, need to reach for the __await__ method for the coroutine.
|
||||
|
|
|
@ -81,6 +81,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
|
|||
|
||||
#define mp_type_type (*mp_fun_table.type_type)
|
||||
#define mp_type_str (*mp_fun_table.type_str)
|
||||
#define mp_type_tuple (*((mp_obj_base_t *)mp_const_empty_tuple)->type)
|
||||
#define mp_type_list (*mp_fun_table.type_list)
|
||||
#define mp_type_EOFError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_EOFError)))
|
||||
#define mp_type_IndexError (*(mp_obj_type_t *)(mp_load_global(MP_QSTR_IndexError)))
|
||||
|
@ -121,6 +122,7 @@ static inline void *m_realloc_dyn(void *ptr, size_t new_num_bytes) {
|
|||
|
||||
#define mp_obj_len(o) (mp_obj_len_dyn(o))
|
||||
#define mp_obj_subscr(base, index, val) (mp_fun_table.obj_subscr((base), (index), (val)))
|
||||
#define mp_obj_get_array(o, len, items) (mp_obj_get_array_dyn((o), (len), (items)))
|
||||
#define mp_obj_list_append(list, item) (mp_fun_table.list_append((list), (item)))
|
||||
|
||||
#define mp_obj_assert_native_inited(o) (mp_fun_table.assert_native_inited((o)))
|
||||
|
@ -264,4 +266,23 @@ static inline void mp_raise_OSError_dyn(int er) {
|
|||
#define mp_obj_get_float(o) (mp_obj_get_float_to_d((o)))
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
// Inline function definitions.
|
||||
|
||||
// *items may point inside a GC block
|
||||
static inline void mp_obj_get_array_dyn(mp_obj_t o, size_t *len, mp_obj_t **items) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(o);
|
||||
if (type == &mp_type_tuple) {
|
||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(o);
|
||||
*len = t->len;
|
||||
*items = &t->items[0];
|
||||
} else if (type == &mp_type_list) {
|
||||
mp_obj_list_t *l = MP_OBJ_TO_PTR(o);
|
||||
*len = l->len;
|
||||
*items = l->items;
|
||||
} else {
|
||||
mp_raise_TypeError("expected tuple/list");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MICROPY_INCLUDED_PY_DYNRUNTIME_H
|
||||
|
|
|
@ -108,6 +108,31 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void
|
|||
|
||||
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
|
||||
|
||||
// Some architectures require flushing/invalidation of the I/D caches,
|
||||
// so that the generated native code which was created in data RAM will
|
||||
// be available for execution from instruction RAM.
|
||||
#if MICROPY_EMIT_THUMB || MICROPY_EMIT_INLINE_THUMB
|
||||
#if __ICACHE_PRESENT == 1
|
||||
// Flush D-cache, so the code emitted is stored in RAM.
|
||||
MP_HAL_CLEAN_DCACHE(fun_data, fun_len);
|
||||
// Invalidate I-cache, so the newly-created code is reloaded from RAM.
|
||||
SCB_InvalidateICache();
|
||||
#endif
|
||||
#elif MICROPY_EMIT_ARM
|
||||
#if (defined(__linux__) && defined(__GNUC__)) || __ARM_ARCH == 7
|
||||
__builtin___clear_cache(fun_data, (uint8_t *)fun_data + fun_len);
|
||||
#elif defined(__arm__)
|
||||
// Flush I-cache and D-cache.
|
||||
asm volatile (
|
||||
"0:"
|
||||
"mrc p15, 0, r15, c7, c10, 3\n" // test and clean D-cache
|
||||
"bne 0b\n"
|
||||
"mov r0, #0\n"
|
||||
"mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache
|
||||
: : : "r0", "cc");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rc->kind = kind;
|
||||
rc->scope_flags = scope_flags;
|
||||
rc->n_pos_args = n_pos_args;
|
||||
|
|
|
@ -1797,7 +1797,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
|||
int reg_index = REG_ARG_2;
|
||||
int reg_value = REG_ARG_3;
|
||||
emit_pre_pop_reg_flexible(emit, &vtype_base, ®_base, reg_index, reg_value);
|
||||
#if N_X86
|
||||
#if N_X64 || N_X86
|
||||
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
|
||||
emit_pre_pop_reg(emit, &vtype_value, reg_value);
|
||||
#else
|
||||
|
@ -1884,7 +1884,7 @@ STATIC void emit_native_store_subscr(emit_t *emit) {
|
|||
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
|
||||
MP_ERROR_TEXT("can't store with '%q' index"), vtype_to_qstr(vtype_index));
|
||||
}
|
||||
#if N_X86
|
||||
#if N_X64 || N_X86
|
||||
// special case: x86 needs byte stores to be from lower 4 regs (REG_ARG_3 is EDX)
|
||||
emit_pre_pop_reg(emit, &vtype_value, reg_value);
|
||||
#else
|
||||
|
|
61
py/gc.c
61
py/gc.c
|
@ -167,7 +167,7 @@ void gc_init(void *start, void *end) {
|
|||
MP_STATE_MEM(gc_lowest_long_lived_ptr) = (void *)PTR_FROM_BLOCK(MP_STATE_MEM(gc_alloc_table_byte_len * BLOCKS_PER_ATB));
|
||||
|
||||
// unlock the GC
|
||||
MP_STATE_MEM(gc_lock_depth) = 0;
|
||||
MP_STATE_THREAD(gc_lock_depth) = 0;
|
||||
|
||||
// allow auto collection
|
||||
MP_STATE_MEM(gc_auto_collect_enabled) = true;
|
||||
|
@ -200,19 +200,20 @@ void gc_deinit(void) {
|
|||
}
|
||||
|
||||
void gc_lock(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
GC_EXIT();
|
||||
// This does not need to be atomic or have the GC mutex because:
|
||||
// - each thread has its own gc_lock_depth so there are no races between threads;
|
||||
// - a hard interrupt will only change gc_lock_depth during its execution, and
|
||||
// upon return will restore the value of gc_lock_depth.
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
}
|
||||
|
||||
void gc_unlock(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)--;
|
||||
GC_EXIT();
|
||||
// This does not need to be atomic, See comment above in gc_lock.
|
||||
MP_STATE_THREAD(gc_lock_depth)--;
|
||||
}
|
||||
|
||||
bool gc_is_locked(void) {
|
||||
return MP_STATE_MEM(gc_lock_depth) != 0;
|
||||
return MP_STATE_THREAD(gc_lock_depth) != 0;
|
||||
}
|
||||
|
||||
#ifndef TRACE_MARK
|
||||
|
@ -356,7 +357,7 @@ STATIC void gc_mark(void *ptr) {
|
|||
|
||||
void gc_collect_start(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
#if MICROPY_GC_ALLOC_THRESHOLD
|
||||
MP_STATE_MEM(gc_alloc_amount) = 0;
|
||||
#endif
|
||||
|
@ -383,9 +384,19 @@ void gc_collect_ptr(void *ptr) {
|
|||
gc_mark(ptr);
|
||||
}
|
||||
|
||||
// Address sanitizer needs to know that the access to ptrs[i] must always be
|
||||
// considered OK, even if it's a load from an address that would normally be
|
||||
// prohibited (due to being undefined, in a red zone, etc).
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
__attribute__((no_sanitize_address))
|
||||
#endif
|
||||
static void *gc_get_ptr(void **ptrs, int i) {
|
||||
return ptrs[i];
|
||||
}
|
||||
|
||||
void gc_collect_root(void **ptrs, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
void *ptr = ptrs[i];
|
||||
void *ptr = gc_get_ptr(ptrs, i);
|
||||
gc_mark(ptr);
|
||||
}
|
||||
}
|
||||
|
@ -397,13 +408,13 @@ void gc_collect_end(void) {
|
|||
MP_STATE_MEM(gc_first_free_atb_index)[i] = 0;
|
||||
}
|
||||
MP_STATE_MEM(gc_last_free_atb_index) = MP_STATE_MEM(gc_alloc_table_byte_len) - 1;
|
||||
MP_STATE_MEM(gc_lock_depth)--;
|
||||
MP_STATE_THREAD(gc_lock_depth)--;
|
||||
GC_EXIT();
|
||||
}
|
||||
|
||||
void gc_sweep_all(void) {
|
||||
GC_ENTER();
|
||||
MP_STATE_MEM(gc_lock_depth)++;
|
||||
MP_STATE_THREAD(gc_lock_depth)++;
|
||||
MP_STATE_MEM(gc_stack_overflow) = 0;
|
||||
gc_collect_end();
|
||||
}
|
||||
|
@ -488,18 +499,17 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags, bool long_lived) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// check if GC is locked
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (MP_STATE_MEM(gc_pool_start) == 0) {
|
||||
reset_into_safe_mode(GC_ALLOC_OUTSIDE_VM);
|
||||
}
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
// check if GC is locked
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
GC_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t found_block = 0xffffffff;
|
||||
size_t end_block;
|
||||
size_t start_block;
|
||||
|
@ -676,13 +686,13 @@ void *gc_alloc_with_finaliser(mp_uint_t n_bytes) {
|
|||
// force the freeing of a piece of memory
|
||||
// TODO: freeing here does not call finaliser
|
||||
void gc_free(void *ptr) {
|
||||
GC_ENTER();
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
// TODO how to deal with this error?
|
||||
GC_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
DEBUG_printf("gc_free(%p)\n", ptr);
|
||||
|
||||
if (ptr == NULL) {
|
||||
|
@ -837,15 +847,14 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (MP_STATE_THREAD(gc_lock_depth) > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ptr = ptr_in;
|
||||
|
||||
GC_ENTER();
|
||||
|
||||
if (MP_STATE_MEM(gc_lock_depth) > 0) {
|
||||
GC_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the GC block number corresponding to this pointer
|
||||
assert(VERIFY_PTR(ptr));
|
||||
size_t block = BLOCK_FROM_PTR(ptr);
|
||||
|
|
|
@ -20,6 +20,7 @@ ifeq ("$(origin V)", "command line")
|
|||
BUILD_VERBOSE=$(V)
|
||||
endif
|
||||
ifndef BUILD_VERBOSE
|
||||
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
|
||||
BUILD_VERBOSE = 0
|
||||
endif
|
||||
ifeq ($(BUILD_VERBOSE),0)
|
||||
|
@ -32,10 +33,6 @@ else
|
|||
Q =
|
||||
STEPECHO = @echo
|
||||
endif
|
||||
# Since this is a new feature, advertise it
|
||||
ifeq ($(BUILD_VERBOSE),0)
|
||||
$(info Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.)
|
||||
endif
|
||||
|
||||
# default settings; can be overridden in main Makefile
|
||||
|
||||
|
|
|
@ -125,9 +125,13 @@ if(MICROPY_FROZEN_MANIFEST)
|
|||
MICROPY_MODULE_FROZEN_MPY=\(1\)
|
||||
)
|
||||
|
||||
if(NOT MICROPY_LIB_DIR)
|
||||
set(MICROPY_LIB_DIR ${MICROPY_DIR}/../micropython-lib)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${MICROPY_FROZEN_CONTENT}
|
||||
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
|
||||
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
|
||||
DEPENDS MICROPY_FORCE_BUILD
|
||||
${MICROPY_QSTRDEFS_GENERATED}
|
||||
VERBATIM
|
||||
|
|
|
@ -374,7 +374,7 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
|
|||
}
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("ord expects a character"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
|
|
@ -132,13 +132,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_lock_obj, mp_micropython_he
|
|||
|
||||
STATIC mp_obj_t mp_micropython_heap_unlock(void) {
|
||||
gc_unlock();
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_unlock_obj, mp_micropython_heap_unlock);
|
||||
|
||||
#if MICROPY_PY_MICROPYTHON_HEAP_LOCKED
|
||||
STATIC mp_obj_t mp_micropython_heap_locked(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_MEM(gc_lock_depth));
|
||||
return MP_OBJ_NEW_SMALL_INT(MP_STATE_THREAD(gc_lock_depth));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_heap_locked_obj, mp_micropython_heap_locked);
|
||||
#endif
|
||||
|
|
|
@ -173,6 +173,9 @@ STATIC void *thread_entry(void *args_in) {
|
|||
mp_pystack_init(mini_pystack, &mini_pystack[128]);
|
||||
#endif
|
||||
|
||||
// The GC starts off unlocked on this thread.
|
||||
ts.gc_lock_depth = 0;
|
||||
|
||||
// set locals and globals from the calling context
|
||||
mp_locals_set(args->dict_locals);
|
||||
mp_globals_set(args->dict_globals);
|
||||
|
|
|
@ -570,6 +570,12 @@
|
|||
#define MICROPY_VM_HOOK_RETURN
|
||||
#endif
|
||||
|
||||
// Hook for mp_sched_schedule when a function gets scheduled on sched_queue
|
||||
// (this macro executes within an atomic section)
|
||||
#ifndef MICROPY_SCHED_HOOK_SCHEDULED
|
||||
#define MICROPY_SCHED_HOOK_SCHEDULED
|
||||
#endif
|
||||
|
||||
// Whether to include the garbage collector
|
||||
#ifndef MICROPY_ENABLE_GC
|
||||
#define MICROPY_ENABLE_GC (0)
|
||||
|
@ -692,6 +698,8 @@ typedef long long mp_longint_impl_t;
|
|||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#endif
|
||||
|
||||
// Exception messages are removed (requires disabling MICROPY_ROM_TEXT_COMPRESSION)
|
||||
#define MICROPY_ERROR_REPORTING_NONE (0)
|
||||
// Exception messages are short static strings
|
||||
#define MICROPY_ERROR_REPORTING_TERSE (1)
|
||||
// Exception messages provide basic error details
|
||||
|
@ -1518,8 +1526,12 @@ typedef double mp_float_t;
|
|||
/*****************************************************************************/
|
||||
/* Hooks for a port to wrap functions with attributes */
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_KEYBOARD_INTERRUPT
|
||||
#define MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(f) f
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_EXCEPTION
|
||||
#define MICROPY_WRAP_MP_SCHED_EXCEPTION(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT
|
||||
#define MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(f) f
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_SCHED_SCHEDULE
|
||||
|
|
|
@ -82,7 +82,6 @@ typedef struct _mp_state_mem_t {
|
|||
|
||||
int gc_stack_overflow;
|
||||
MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
|
||||
uint16_t gc_lock_depth;
|
||||
|
||||
// This variable controls auto garbage collection. If set to false then the
|
||||
// GC won't automatically run when gc_alloc can't find enough blocks. But
|
||||
|
@ -253,6 +252,9 @@ typedef struct _mp_state_thread_t {
|
|||
uint8_t *pystack_cur;
|
||||
#endif
|
||||
|
||||
// Locking of the GC is done per thread.
|
||||
uint16_t gc_lock_depth;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// START ROOT POINTER SECTION
|
||||
// Everything that needs GC scanning must start here, and
|
||||
|
|
|
@ -58,7 +58,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
|
|||
#else
|
||||
|
||||
__asm volatile (
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"pop %rbp \n" // undo function's prelude
|
||||
#endif
|
||||
"movq (%rsp), %rax \n" // load return %rip
|
||||
|
@ -70,7 +70,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
|
|||
"movq %r13, 56(%rdi) \n" // store %r13 into nlr_buf
|
||||
"movq %r14, 64(%rdi) \n" // store %r14 into nlr_buf
|
||||
"movq %r15, 72(%rdi) \n" // store %r15 into nlr_buf
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"jmp _nlr_push_tail \n" // do the rest in C
|
||||
#else
|
||||
"jmp nlr_push_tail \n" // do the rest in C
|
||||
|
|
20
py/obj.c
20
py/obj.c
|
@ -391,7 +391,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) {
|
|||
mp_float_t val;
|
||||
|
||||
if (!mp_obj_get_float_maybe(arg, &val)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("can't convert to %q"), MP_QSTR_float);
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -431,7 +431,7 @@ bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag)
|
|||
|
||||
void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
|
||||
if (!mp_obj_get_complex_maybe(arg, real, imag)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -449,7 +449,7 @@ void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
|
|||
} else if (mp_obj_is_type(o, &mp_type_list)) {
|
||||
mp_obj_list_get(o, len, items);
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -463,7 +463,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
|
|||
size_t seq_len;
|
||||
mp_obj_get_array(o, &seq_len, items);
|
||||
if (seq_len != len) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
|
@ -478,7 +478,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
|
|||
if (mp_obj_is_small_int(index)) {
|
||||
i = MP_OBJ_SMALL_INT_VALUE(index);
|
||||
} else if (!mp_obj_get_int_maybe(index, &i)) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -498,7 +498,7 @@ size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool
|
|||
}
|
||||
} else {
|
||||
if (i < 0 || (mp_uint_t)i >= len) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_IndexError(MP_ERROR_TEXT("index out of range"));
|
||||
#else
|
||||
mp_raise_msg_varg(&mp_type_IndexError,
|
||||
|
@ -533,7 +533,7 @@ mp_obj_t mp_obj_id(mp_obj_t o_in) {
|
|||
mp_obj_t mp_obj_len(mp_obj_t o_in) {
|
||||
mp_obj_t len = mp_obj_len_maybe(o_in);
|
||||
if (len == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -575,21 +575,21 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
|
|||
}
|
||||
}
|
||||
if (value == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
|
||||
#endif
|
||||
} else if (value == MP_OBJ_SENTINEL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
|
||||
#endif
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
|
5
py/obj.h
5
py/obj.h
|
@ -792,8 +792,13 @@ extern uint64_t float_to_uint64(float f);
|
|||
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type);
|
||||
mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args, const mp_obj_t *args);
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
|
||||
#define mp_obj_new_exception_msg(exc_type, msg) mp_obj_new_exception(exc_type)
|
||||
#define mp_obj_new_exception_msg_varg(exc_type, ...) mp_obj_new_exception(exc_type)
|
||||
#else
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg);
|
||||
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
#endif
|
||||
#ifdef va_start
|
||||
mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list ap); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
|
||||
#endif
|
||||
|
|
|
@ -211,11 +211,7 @@ STATIC mp_obj_t bytearray_make_new(const mp_obj_type_t *type_in, size_t n_args,
|
|||
|
||||
mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items) {
|
||||
mp_obj_array_t *self = m_new_obj(mp_obj_array_t);
|
||||
self->base.type = &mp_type_memoryview;
|
||||
self->typecode = typecode;
|
||||
self->memview_offset = 0;
|
||||
self->len = nitems;
|
||||
self->items = items;
|
||||
mp_obj_memoryview_init(self, typecode, 0, nitems, items);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
|
@ -234,6 +230,14 @@ STATIC mp_obj_t memoryview_make_new(const mp_obj_type_t *type_in, size_t n_args,
|
|||
bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL),
|
||||
bufinfo.buf));
|
||||
|
||||
// If the input object is a memoryview then need to point the items of the
|
||||
// new memoryview to the start of the buffer so the GC can trace it.
|
||||
if (mp_obj_get_type(args[0]) == &mp_type_memoryview) {
|
||||
mp_obj_array_t *other = MP_OBJ_TO_PTR(args[0]);
|
||||
self->memview_offset = other->memview_offset;
|
||||
self->items = other->items;
|
||||
}
|
||||
|
||||
// test if the object can be written to
|
||||
if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) {
|
||||
self->typecode |= MP_OBJ_ARRAY_TYPECODE_FLAG_RW; // indicate writable buffer
|
||||
|
@ -288,6 +292,17 @@ STATIC mp_obj_t array_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
|
|||
}
|
||||
}
|
||||
|
||||
STATIC int typecode_for_comparison(int typecode, bool *is_unsigned) {
|
||||
if (typecode == BYTEARRAY_TYPECODE) {
|
||||
typecode = 'B';
|
||||
}
|
||||
if (typecode <= 'Z') {
|
||||
typecode += 32; // to lowercase
|
||||
*is_unsigned = true;
|
||||
}
|
||||
return typecode;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
|
||||
mp_obj_array_t *lhs = MP_OBJ_TO_PTR(lhs_in);
|
||||
switch (op) {
|
||||
|
@ -376,15 +391,34 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
|
|||
return mp_const_false;
|
||||
}
|
||||
|
||||
case MP_BINARY_OP_EQUAL: {
|
||||
case MP_BINARY_OP_EQUAL:
|
||||
case MP_BINARY_OP_LESS:
|
||||
case MP_BINARY_OP_LESS_EQUAL:
|
||||
case MP_BINARY_OP_MORE:
|
||||
case MP_BINARY_OP_MORE_EQUAL: {
|
||||
mp_buffer_info_t lhs_bufinfo;
|
||||
mp_buffer_info_t rhs_bufinfo;
|
||||
array_get_buffer(lhs_in, &lhs_bufinfo, MP_BUFFER_READ);
|
||||
if (!mp_get_buffer(rhs_in, &rhs_bufinfo, MP_BUFFER_READ)) {
|
||||
return mp_const_false;
|
||||
}
|
||||
// mp_seq_cmp_bytes is used so only compatible representations can be correctly compared.
|
||||
// The type doesn't matter: array/bytearray/str/bytes all have the same buffer layout, so
|
||||
// just check if the typecodes are compatible; for testing equality the types should have the
|
||||
// same code except for signedness, and not be floating point because nan never equals nan.
|
||||
// For > and < the types should be the same and unsigned.
|
||||
// Note that typecode_for_comparison always returns lowercase letters to save code size.
|
||||
// No need for (& TYPECODE_MASK) here: xxx_get_buffer already takes care of that.
|
||||
bool is_unsigned = false;
|
||||
const int lhs_code = typecode_for_comparison(lhs_bufinfo.typecode, &is_unsigned);
|
||||
const int rhs_code = typecode_for_comparison(rhs_bufinfo.typecode, &is_unsigned);
|
||||
if (lhs_code == rhs_code && lhs_code != 'f' && lhs_code != 'd' && (op == MP_BINARY_OP_EQUAL || is_unsigned)) {
|
||||
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs_bufinfo.buf, lhs_bufinfo.len, rhs_bufinfo.buf, rhs_bufinfo.len));
|
||||
}
|
||||
// mp_obj_equal_not_equal treats returning MP_OBJ_NULL as 'fall back to pointer comparison'
|
||||
// for MP_BINARY_OP_EQUAL but that is incompatible with CPython.
|
||||
mp_raise_NotImplementedError(NULL);
|
||||
}
|
||||
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
|
|
|
@ -367,9 +367,11 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, size_t n_args,
|
|||
return exc_type->make_new(exc_type, n_args, args, NULL);
|
||||
}
|
||||
|
||||
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_NONE
|
||||
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
|
||||
return mp_obj_new_exception_msg_varg(exc_type, msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The following struct and function implement a simple printer that conservatively
|
||||
// allocates memory and truncates the output data if no more memory can be obtained.
|
||||
|
|
|
@ -108,7 +108,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
|||
n_kw = kw_args->used;
|
||||
}
|
||||
if (n_args + n_kw != num_fields) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -134,7 +134,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
|||
qstr kw = mp_obj_str_get_qstr(kw_args->table[i].key);
|
||||
size_t id = mp_obj_namedtuple_find_field(type, kw);
|
||||
if (id == (size_t)-1) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
@ -142,7 +142,7 @@ mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, const
|
|||
#endif
|
||||
}
|
||||
if (tuple->items[id] != MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_arg_error_terse_mismatch();
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
|
38
py/objstr.c
38
py/objstr.c
|
@ -968,7 +968,7 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
STATIC NORETURN void terse_str_format_value_error(void) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad format string"));
|
||||
}
|
||||
|
@ -989,7 +989,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
vstr_add_byte(&vstr, '}');
|
||||
continue;
|
||||
}
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("single '}' encountered in format string"));
|
||||
|
@ -1028,7 +1028,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
if (str < top && (*str == 'r' || *str == 's')) {
|
||||
conversion = *str++;
|
||||
} else {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("bad conversion specifier"));
|
||||
|
@ -1066,14 +1066,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
}
|
||||
}
|
||||
if (str >= top) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("unmatched '{' in format"));
|
||||
#endif
|
||||
}
|
||||
if (*str != '}') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("expected ':' after format specifier"));
|
||||
|
@ -1086,7 +1086,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
int index = 0;
|
||||
if (MP_LIKELY(unichar_isdigit(*field_name))) {
|
||||
if (*arg_i > 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
|
@ -1116,7 +1116,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
}
|
||||
} else {
|
||||
if (*arg_i < 0) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
|
@ -1209,7 +1209,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
type = *s++;
|
||||
}
|
||||
if (*s) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid format specifier"));
|
||||
|
@ -1230,14 +1230,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
|
||||
if (flags & (PF_FLAG_SHOW_SIGN | PF_FLAG_SPACE_SIGN)) {
|
||||
if (type == 's') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("sign not allowed in string format specifier"));
|
||||
#endif
|
||||
}
|
||||
if (type == 'c') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
|
@ -1301,7 +1301,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
break;
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
|
@ -1373,7 +1373,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
#endif
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
|
@ -1385,7 +1385,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
// arg doesn't look like a number
|
||||
|
||||
if (align == '=') {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(
|
||||
|
@ -1409,7 +1409,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar
|
|||
}
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
|
@ -1438,7 +1438,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
|||
mp_check_self(mp_obj_is_str_or_bytes(pattern));
|
||||
|
||||
GET_STR_DATA_LEN(pattern, str, len);
|
||||
#if MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING > MICROPY_ERROR_REPORTING_TERSE
|
||||
const byte *start_str = str;
|
||||
#endif
|
||||
bool is_bytes = mp_obj_is_type(pattern, &mp_type_bytes);
|
||||
|
@ -1470,7 +1470,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
|||
const byte *key = ++str;
|
||||
while (*str != ')') {
|
||||
if (str >= top) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format key"));
|
||||
|
@ -1534,7 +1534,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
|||
|
||||
if (str >= top) {
|
||||
incomplete_format:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("incomplete format"));
|
||||
|
@ -1620,7 +1620,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_
|
|||
break;
|
||||
|
||||
default:
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
terse_str_format_value_error();
|
||||
#else
|
||||
mp_raise_ValueError_varg(
|
||||
|
@ -2165,7 +2165,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) {
|
|||
}
|
||||
|
||||
STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly"));
|
||||
#else
|
||||
const qstr src_name = mp_obj_get_type_qstr(self_in);
|
||||
|
|
|
@ -373,7 +373,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, cons
|
|||
m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
|
||||
}
|
||||
if (init_ret != mp_const_none) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("__init__() should return None"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("__init__() should return None, not '%q'"),
|
||||
|
@ -889,7 +889,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons
|
|||
mp_obj_t member[2] = {MP_OBJ_NULL, MP_OBJ_NULL};
|
||||
mp_obj_t call = mp_obj_instance_get_call(self_in, member);
|
||||
if (call == MP_OBJ_NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("object not callable"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"),
|
||||
|
@ -1029,7 +1029,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp
|
|||
mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (self->make_new == NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(MP_ERROR_TEXT("cannot create '%q' instances"), self->name);
|
||||
|
@ -1171,7 +1171,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
|
|||
mp_obj_type_t *t = MP_OBJ_TO_PTR(bases_items[i]);
|
||||
// TODO: Verify with CPy, tested on function type
|
||||
if (t->make_new == NULL) {
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("type is not an acceptable base type"));
|
||||
#else
|
||||
mp_raise_TypeError_varg(
|
||||
|
|
|
@ -147,7 +147,7 @@ overflow:
|
|||
|
||||
value_error:
|
||||
{
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
|
||||
#if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
|
||||
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
MP_ERROR_TEXT("invalid syntax for integer"));
|
||||
raise_exc(exc, lex);
|
||||
|
|
|
@ -298,9 +298,7 @@ STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t
|
|||
mp_prof_is_executing = false;
|
||||
|
||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
|
||||
nlr_raise(obj);
|
||||
mp_handle_pending(true);
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ STATIC bool test_qstr(mp_obj_t obj, qstr name) {
|
|||
} else {
|
||||
// try builtin module
|
||||
return mp_map_lookup((mp_map_t *)&mp_builtin_module_map,
|
||||
MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) != NULL;
|
||||
MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,13 +167,13 @@ STATIC const char *find_completions(const char *s_start, size_t s_len,
|
|||
for (qstr q = MP_QSTR_ + 1; q < nqstr; ++q) {
|
||||
size_t d_len;
|
||||
const char *d_str = (const char *)qstr_data(q, &d_len);
|
||||
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
|
||||
if (test_qstr(obj, q)) {
|
||||
// special case; filter out words that begin with underscore
|
||||
// unless there's already a partial match
|
||||
if (s_len == 0 && d_str[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) {
|
||||
if (test_qstr(obj, q)) {
|
||||
if (match_str == NULL) {
|
||||
match_str = d_str;
|
||||
*match_len = d_len;
|
||||
|
@ -297,7 +297,7 @@ size_t mp_repl_autocomplete(const char *str, size_t len, const mp_print_t *print
|
|||
if (q_first == 0) {
|
||||
// If there're no better alternatives, and if it's first word
|
||||
// in the line, try to complete "import".
|
||||
if (s_start == org_str && s_len > 0) {
|
||||
if (s_start == org_str && s_len > 0 && s_len < sizeof(import_str) - 1) {
|
||||
if (memcmp(s_start, import_str, s_len) == 0) {
|
||||
*compl_str = import_str + s_len;
|
||||
return sizeof(import_str) - 1 - s_len;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue