Merge branch 'master' of https://github.com/micropython/micropython
This commit is contained in:
commit
39a93b48cd
3
.gitignore
vendored
3
.gitignore
vendored
@ -30,9 +30,10 @@ Session.vim
|
||||
tags
|
||||
TAGS
|
||||
|
||||
# Build directory
|
||||
# Build directories
|
||||
######################
|
||||
build/
|
||||
build-*/
|
||||
|
||||
# Test failure outputs
|
||||
######################
|
||||
|
||||
11
.travis.yml
11
.travis.yml
@ -115,6 +115,17 @@ jobs:
|
||||
- make ${MAKEOPTS} -C ports/unix CC=clang CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
|
||||
- make ${MAKEOPTS} -C ports/unix CC=clang test
|
||||
|
||||
# unix with sys.settrace
|
||||
- stage: test
|
||||
env: NAME="unix port with sys.settrace build and tests"
|
||||
script:
|
||||
- make ${MAKEOPTS} -C mpy-cross
|
||||
- make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" test
|
||||
- make ${MAKEOPTS} -C ports/unix clean
|
||||
- make ${MAKEOPTS} -C ports/unix MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1 -DMICROPY_PY_SYS_SETTRACE=1" test
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
|
||||
# windows port via mingw
|
||||
- stage: test
|
||||
env: NAME="windows port build via mingw"
|
||||
|
||||
@ -36,6 +36,51 @@ Functions
|
||||
|
||||
Read the raw value of the internal Hall sensor, returning an integer.
|
||||
|
||||
Flash partitions
|
||||
----------------
|
||||
|
||||
This class gives access to the partitions in the device's flash memory.
|
||||
|
||||
.. class:: Partition(id)
|
||||
|
||||
Create an object representing a partition. *id* can be a string which is the label
|
||||
of the partition to retrieve, or one of the constants: ``BOOT`` or ``RUNNING``.
|
||||
|
||||
.. classmethod:: Partition.find(type=TYPE_APP, subtype=0xff, label=None)
|
||||
|
||||
Find a partition specified by *type*, *subtype* and *label*. Returns a
|
||||
(possibly empty) list of Partition objects.
|
||||
|
||||
.. method:: Partition.info()
|
||||
|
||||
Returns a 6-tuple ``(type, subtype, addr, size, label, encrypted)``.
|
||||
|
||||
.. method:: Partition.readblocks(block_num, buf)
|
||||
.. method:: Partition.writeblocks(block_num, buf)
|
||||
.. method:: Partition.ioctl(cmd, arg)
|
||||
|
||||
These methods implement the block protocol defined by :class:`uos.AbstractBlockDev`.
|
||||
|
||||
.. method:: Partition.set_boot()
|
||||
|
||||
Sets the partition as the boot partition.
|
||||
|
||||
.. method:: Partition.get_next_update()
|
||||
|
||||
Gets the next update partition after this one, and returns a new Partition object.
|
||||
|
||||
Constants
|
||||
~~~~~~~~~
|
||||
|
||||
.. data:: Partition.BOOT
|
||||
Partition.RUNNING
|
||||
|
||||
Used in the `Partition` constructor to fetch various partitions.
|
||||
|
||||
.. data:: Partition.TYPE_APP
|
||||
Partition.TYPE_DATA
|
||||
|
||||
Used in `Partition.find` to specify the partition type.
|
||||
|
||||
The Ultra-Low-Power co-processor
|
||||
--------------------------------
|
||||
|
||||
@ -136,6 +136,7 @@ The following libraries and classes are specific to the WiPy.
|
||||
:maxdepth: 2
|
||||
|
||||
wipy.rst
|
||||
machine.ADCWiPy.rst
|
||||
machine.TimerWiPy.rst
|
||||
|
||||
|
||||
|
||||
@ -4,71 +4,32 @@
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
||||
Usage::
|
||||
The ADC class provides an interface to analog-to-digital convertors, and
|
||||
represents a single endpoint that can sample a continuous voltage and
|
||||
convert it to a discretised value.
|
||||
|
||||
Example usage::
|
||||
|
||||
import machine
|
||||
|
||||
adc = machine.ADC() # create an ADC object
|
||||
apin = adc.channel(pin='GP3') # create an analog pin on GP3
|
||||
val = apin() # read an analog value
|
||||
adc = machine.ADC(pin) # create an ADC object acting on a pin
|
||||
val = adc.read_u16() # read a raw analog value in the range 0-65535
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: ADC(id=0, \*, bits=12)
|
||||
.. class:: ADC(id)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
For more info check the `pinout and alternate functions
|
||||
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
|
||||
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
|
||||
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
|
||||
then the maximum allowed input is 3.6V.
|
||||
Access the ADC associated with a source identified by *id*. This
|
||||
*id* may be an integer (usually specifying a channel number), a
|
||||
:ref:`Pin <machine.Pin>` object, or other value supported by the
|
||||
underlying machine.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: ADC.channel(id, \*, pin)
|
||||
.. method:: ADC.read_u16()
|
||||
|
||||
Create an analog pin. If only channel ID is given, the correct pin will
|
||||
be selected. Alternatively, only the pin can be passed and the correct
|
||||
channel will be selected. Examples::
|
||||
|
||||
# all of these are equivalent and enable ADC channel 1 on GP3
|
||||
apin = adc.channel(1)
|
||||
apin = adc.channel(pin='GP3')
|
||||
apin = adc.channel(id=1, pin='GP3')
|
||||
|
||||
.. method:: ADC.init()
|
||||
|
||||
Enable the ADC block.
|
||||
|
||||
.. method:: ADC.deinit()
|
||||
|
||||
Disable the ADC block.
|
||||
|
||||
class ADCChannel --- read analog values from internal or external sources
|
||||
=========================================================================
|
||||
|
||||
ADC channels can be connected to internal points of the MCU or to GPIO pins.
|
||||
ADC channels are created using the ADC.channel method.
|
||||
|
||||
.. method:: adcchannel()
|
||||
|
||||
Fast method to read the channel value.
|
||||
|
||||
.. method:: adcchannel.value()
|
||||
|
||||
Read the channel value.
|
||||
|
||||
.. method:: adcchannel.init()
|
||||
|
||||
Re-init (and effectively enable) the ADC channel.
|
||||
|
||||
.. method:: adcchannel.deinit()
|
||||
|
||||
Disable the ADC channel.
|
||||
Take an analog reading and return an integer in the range 0-65535.
|
||||
The return value represents the raw reading taken by the ADC, scaled
|
||||
such that the minimum value is 0 and the maximum value is 65535.
|
||||
|
||||
81
docs/library/machine.ADCWiPy.rst
Normal file
81
docs/library/machine.ADCWiPy.rst
Normal file
@ -0,0 +1,81 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.ADCWiPy:
|
||||
|
||||
class ADCWiPy -- analog to digital conversion
|
||||
=============================================
|
||||
|
||||
.. note::
|
||||
|
||||
This class is a non-standard ADC implementation for the WiPy.
|
||||
It is available simply as ``machine.ADC`` on the WiPy but is named in the
|
||||
documentation below as ``machine.ADCWiPy`` to distinguish it from the
|
||||
more general :ref:`machine.ADC <machine.ADC>` class.
|
||||
|
||||
Usage::
|
||||
|
||||
import machine
|
||||
|
||||
adc = machine.ADC() # create an ADC object
|
||||
apin = adc.channel(pin='GP3') # create an analog pin on GP3
|
||||
val = apin() # read an analog value
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: ADCWiPy(id=0, \*, bits=12)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
For more info check the `pinout and alternate functions
|
||||
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
|
||||
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
|
||||
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
|
||||
then the maximum allowed input is 3.6V.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: ADCWiPy.channel(id, \*, pin)
|
||||
|
||||
Create an analog pin. If only channel ID is given, the correct pin will
|
||||
be selected. Alternatively, only the pin can be passed and the correct
|
||||
channel will be selected. Examples::
|
||||
|
||||
# all of these are equivalent and enable ADC channel 1 on GP3
|
||||
apin = adc.channel(1)
|
||||
apin = adc.channel(pin='GP3')
|
||||
apin = adc.channel(id=1, pin='GP3')
|
||||
|
||||
.. method:: ADCWiPy.init()
|
||||
|
||||
Enable the ADC block.
|
||||
|
||||
.. method:: ADCWiPy.deinit()
|
||||
|
||||
Disable the ADC block.
|
||||
|
||||
class ADCChannel --- read analog values from internal or external sources
|
||||
=========================================================================
|
||||
|
||||
ADC channels can be connected to internal points of the MCU or to GPIO pins.
|
||||
ADC channels are created using the ADC.channel method.
|
||||
|
||||
.. method:: adcchannel()
|
||||
|
||||
Fast method to read the channel value.
|
||||
|
||||
.. method:: adcchannel.value()
|
||||
|
||||
Read the channel value.
|
||||
|
||||
.. method:: adcchannel.init()
|
||||
|
||||
Re-init (and effectively enable) the ADC channel.
|
||||
|
||||
.. method:: adcchannel.deinit()
|
||||
|
||||
Disable the ADC channel.
|
||||
@ -93,9 +93,9 @@ Methods
|
||||
|
||||
.. method:: DAC.triangle(freq)
|
||||
|
||||
Generate a triangle wave. The value on the DAC output changes at
|
||||
the given frequency, and the frequency of the repeating triangle wave
|
||||
itself is 2048 times smaller.
|
||||
Generate a triangle wave. The value on the DAC output changes at the given
|
||||
frequency and ramps through the full 12-bit range (up and down). Therefore
|
||||
the frequency of the repeating triangle wave itself is 8192 times smaller.
|
||||
|
||||
.. method:: DAC.write(value)
|
||||
|
||||
|
||||
@ -259,34 +259,45 @@ Miscellaneous functions
|
||||
|
||||
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
|
||||
|
||||
.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse)
|
||||
.. function:: usb_mode([modestr], port=-1, vid=0xf055, pid=-1, msc=(), hid=pyb.hid_mouse, high_speed=False)
|
||||
|
||||
If called with no arguments, return the current USB mode as a string.
|
||||
|
||||
If called with ``modestr`` provided, attempts to set USB mode.
|
||||
This can only be done when called from ``boot.py`` before
|
||||
:meth:`pyb.main()` has been called. The following values of
|
||||
``modestr`` are understood:
|
||||
If called with *modestr* provided, attempts to configure the USB mode.
|
||||
The following values of *modestr* are understood:
|
||||
|
||||
- ``None``: disables USB
|
||||
- ``'VCP'``: enable with VCP (Virtual COM Port) interface
|
||||
- ``'MSC'``: enable with MSC (mass storage device class) interface
|
||||
- ``'VCP+MSC'``: enable with VCP and MSC
|
||||
- ``'VCP+HID'``: enable with VCP and HID (human interface device)
|
||||
- ``'VCP+MSC+HID'``: enabled with VCP, MSC and HID (only available on PYBD boards)
|
||||
|
||||
For backwards compatibility, ``'CDC'`` is understood to mean
|
||||
``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``).
|
||||
|
||||
The ``vid`` and ``pid`` parameters allow you to specify the VID
|
||||
(vendor id) and PID (product id).
|
||||
The *port* parameter should be an integer (0, 1, ...) and selects which
|
||||
USB port to use if the board supports multiple ports. A value of -1 uses
|
||||
the default or automatically selected port.
|
||||
|
||||
The *vid* and *pid* parameters allow you to specify the VID (vendor id)
|
||||
and PID (product id). A *pid* value of -1 will select a PID based on the
|
||||
value of *modestr*.
|
||||
|
||||
If enabling MSC mode, the *msc* parameter can be used to specify a list
|
||||
of SCSI LUNs to expose on the mass storage interface. For example
|
||||
``msc=(pyb.Flash(), pyb.SDCard())``.
|
||||
|
||||
If enabling HID mode, you may also specify the HID details by
|
||||
passing the ``hid`` keyword parameter. It takes a tuple of
|
||||
passing the *hid* keyword parameter. It takes a tuple of
|
||||
(subclass, protocol, max packet length, polling interval, report
|
||||
descriptor). By default it will set appropriate values for a USB
|
||||
mouse. There is also a ``pyb.hid_keyboard`` constant, which is an
|
||||
appropriate tuple for a USB keyboard.
|
||||
|
||||
The *high_speed* parameter, when set to ``True``, enables USB HS mode if
|
||||
it is supported by the hardware.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
|
||||
@ -15,6 +15,19 @@ Functions
|
||||
function raise as `SystemExit` exception. If an argument is given, its
|
||||
value given as an argument to `SystemExit`.
|
||||
|
||||
.. function:: atexit(func)
|
||||
|
||||
Register *func* to be called upon termination. *func* must be a callable
|
||||
that takes no arguments, or ``None`` to disable the call. The ``atexit``
|
||||
function will return the previous value set by this function, which is
|
||||
initially ``None``.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
This function is a MicroPython extension intended to provide similar
|
||||
functionality to the :mod:`atexit` module in CPython.
|
||||
|
||||
.. function:: print_exception(exc, file=sys.stdout)
|
||||
|
||||
Print exception with a traceback to a file-like object *file* (or
|
||||
@ -121,3 +134,9 @@ Constants
|
||||
.. data:: version_info
|
||||
|
||||
Python language version that this implementation conforms to, as a tuple of ints.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
Only the first three version numbers (major, minor, micro) are supported and
|
||||
they can be referenced only by index, not by name.
|
||||
|
||||
@ -31,7 +31,7 @@ have as to what happens next:
|
||||
We will get the serial device working in the next tutorial.
|
||||
|
||||
- **Mac**: Your pyboard will appear on the desktop as a removable disc.
|
||||
It will probably be called "NONAME". Click on it to open the pyboard folder.
|
||||
It will probably be called ``PYBFLASH``. Click on it to open the pyboard folder.
|
||||
|
||||
- **Linux**: Your pyboard will appear as a removable medium. On Ubuntu
|
||||
it will mount automatically and pop-up a window with the pyboard folder.
|
||||
@ -46,17 +46,17 @@ a window (or command line) should be showing the files on the pyboard drive.
|
||||
The drive you are looking at is known as ``/flash`` by the pyboard, and should contain
|
||||
the following 4 files:
|
||||
|
||||
* `boot.py <http://micropython.org/resources/fresh-pyboard/boot.py>`_ -- this script is executed when the pyboard boots up. It sets
|
||||
up various configuration options for the pyboard.
|
||||
* `boot.py <http://micropython.org/resources/fresh-pyboard/boot.py>`_ -- the various configuration options for the pyboard.
|
||||
It is executed when the pyboard boots up.
|
||||
|
||||
* `main.py <http://micropython.org/resources/fresh-pyboard/main.py>`_ -- this is the main script that will contain your Python program.
|
||||
* `main.py <http://micropython.org/resources/fresh-pyboard/main.py>`_ -- the Python program to be run.
|
||||
It is executed after ``boot.py``.
|
||||
|
||||
* `README.txt <http://micropython.org/resources/fresh-pyboard/README.txt>`_ -- this contains some very basic information about getting
|
||||
started with the pyboard.
|
||||
* `README.txt <http://micropython.org/resources/fresh-pyboard/README.txt>`_ -- basic information about getting started with the pyboard.
|
||||
This provides pointers for new users and can be safely deleted.
|
||||
|
||||
* `pybcdc.inf <http://micropython.org/resources/fresh-pyboard/pybcdc.inf>`_ -- this is a Windows driver file to configure the serial USB
|
||||
device. More about this in the next tutorial.
|
||||
* `pybcdc.inf <http://micropython.org/resources/fresh-pyboard/pybcdc.inf>`_ -- the Windows driver file to configure the serial USB device.
|
||||
More about this in the next tutorial.
|
||||
|
||||
Editing ``main.py``
|
||||
-------------------
|
||||
|
||||
@ -39,14 +39,15 @@ Sending mouse events by hand
|
||||
|
||||
To get the py-mouse to do anything we need to send mouse events to the PC.
|
||||
We will first do this manually using the REPL prompt. Connect to your
|
||||
pyboard using your serial program and type the following::
|
||||
pyboard using your serial program and type the following (no need to type
|
||||
the ``#`` and text following it)::
|
||||
|
||||
>>> hid = pyb.USB_HID()
|
||||
>>> hid.send((0, 10, 0, 0))
|
||||
>>> hid.send((0, 100, 0, 0)) # (button status, x-direction, y-direction, scroll)
|
||||
|
||||
Your mouse should move 10 pixels to the right! In the command above you
|
||||
are sending 4 pieces of information: button status, x, y and scroll. The
|
||||
number 10 is telling the PC that the mouse moved 10 pixels in the x direction.
|
||||
Your mouse should move 100 pixels to the right! In the command above you
|
||||
are sending 4 pieces of information: **button status**, **x-direction**, **y-direction**, and **scroll**. The
|
||||
number 100 is telling the PC that the mouse moved 100 pixels in the x direction.
|
||||
|
||||
Let's make the mouse oscillate left and right::
|
||||
|
||||
|
||||
@ -165,7 +165,7 @@ by caching the object in a local variable:
|
||||
|
||||
class foo(object):
|
||||
def __init__(self):
|
||||
ba = bytearray(100)
|
||||
self.ba = bytearray(100)
|
||||
def bar(self, obj_display):
|
||||
ba_ref = self.ba
|
||||
fb = obj_display.framebuffer
|
||||
@ -293,9 +293,11 @@ microseconds. The rules for casting are as follows:
|
||||
* The argument to a bool cast must be integral type (boolean or integer); when used as a return
|
||||
type the viper function will return True or False objects.
|
||||
* If the argument is a Python object and the cast is ``ptr``, ``ptr``, ``ptr16`` or ``ptr32``,
|
||||
then the Python object must either have the buffer protocol with read-write capabilities
|
||||
(in which case a pointer to the start of the buffer is returned) or it must be of integral
|
||||
type (in which case the value of that integral object is returned).
|
||||
then the Python object must either have the buffer protocol (in which case a pointer to the
|
||||
start of the buffer is returned) or it must be of integral type (in which case the value of
|
||||
that integral object is returned).
|
||||
|
||||
Writing to a pointer which points to a read-only object will lead to undefined behaviour.
|
||||
|
||||
The following example illustrates the use of a ``ptr16`` cast to toggle pin X1 ``n`` times:
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ See :ref:`machine.Pin <machine.Pin>` and :ref:`machine.Timer <machine.Timer>`. :
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
See :ref:`machine.ADC <machine.ADC>`. ::
|
||||
See :ref:`machine.ADCWiPy <machine.ADCWiPy>`. ::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ mp_obj_t execute_from_str(const char *str) {
|
||||
qstr src_name = 1/*MP_QSTR_*/;
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false);
|
||||
mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(&pt, src_name, MP_EMIT_OPT_NONE, false);
|
||||
mp_obj_t module_fun = mp_compile(&pt, src_name, false);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
return 0;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
/*********************************************************************
|
||||
* Source: https://github.com/B-Con/crypto-algorithms
|
||||
* Filename: sha256.c
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Copyright: This code is released into the public domain.
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Implementation of the SHA-256 hashing algorithm.
|
||||
SHA-256 is one of the three algorithms in the SHA2
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
/*********************************************************************
|
||||
* Source: https://github.com/B-Con/crypto-algorithms
|
||||
* Filename: sha256.h
|
||||
* Author: Brad Conte (brad AT bradconte.com)
|
||||
* Copyright:
|
||||
* Copyright: This code is released into the public domain.
|
||||
* Disclaimer: This code is presented "as is" without any guarantees.
|
||||
* Details: Defines the API for the corresponding SHA1 implementation.
|
||||
*********************************************************************/
|
||||
|
||||
@ -89,7 +89,7 @@ typedef struct _mp_obj_aes_t {
|
||||
uint8_t key_type: 2;
|
||||
} mp_obj_aes_t;
|
||||
|
||||
STATIC inline bool is_ctr_mode(int block_mode) {
|
||||
static inline bool is_ctr_mode(int block_mode) {
|
||||
#if MICROPY_PY_UCRYPTOLIB_CTR
|
||||
return block_mode == UCRYPTOLIB_MODE_CTR;
|
||||
#else
|
||||
@ -97,7 +97,7 @@ STATIC inline bool is_ctr_mode(int block_mode) {
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
|
||||
static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
|
||||
// ctr_params follows aes object struct
|
||||
return (struct ctr_params*)&o[1];
|
||||
}
|
||||
|
||||
@ -299,13 +299,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, ucty
|
||||
static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
|
||||
char struct_type = big_endian ? '>' : '<';
|
||||
static const char type2char[16] = "BbHhIiQq------fd";
|
||||
return mp_binary_get_val(struct_type, type2char[val_type], &p);
|
||||
return mp_binary_get_val(struct_type, type2char[val_type], p, &p);
|
||||
}
|
||||
|
||||
static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
|
||||
char struct_type = big_endian ? '>' : '<';
|
||||
static const char type2char[16] = "BbHhIiQq------fd";
|
||||
mp_binary_set_val(struct_type, type2char[val_type], val, &p);
|
||||
mp_binary_set_val(struct_type, type2char[val_type], val, p, &p);
|
||||
}
|
||||
|
||||
static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
|
||||
|
||||
@ -31,14 +31,14 @@
|
||||
|
||||
// the algorithm here is modelled on CPython's heapq.py
|
||||
|
||||
STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
|
||||
STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
|
||||
if (!mp_obj_is_type(heap_in, &mp_type_list)) {
|
||||
mp_raise_TypeError("heap must be a list");
|
||||
}
|
||||
return MP_OBJ_TO_PTR(heap_in);
|
||||
}
|
||||
|
||||
STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
STATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
mp_obj_t item = heap->items[pos];
|
||||
while (pos > start_pos) {
|
||||
mp_uint_t parent_pos = (pos - 1) >> 1;
|
||||
@ -53,7 +53,7 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po
|
||||
heap->items[pos] = item;
|
||||
}
|
||||
|
||||
STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
mp_uint_t start_pos = pos;
|
||||
mp_uint_t end_pos = heap->len;
|
||||
mp_obj_t item = heap->items[pos];
|
||||
@ -67,19 +67,19 @@ STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
pos = child_pos;
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
heap_siftdown(heap, start_pos, pos);
|
||||
uheapq_heap_siftdown(heap, start_pos, pos);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
||||
mp_obj_list_append(heap_in, item);
|
||||
heap_siftdown(heap, 0, heap->len - 1);
|
||||
uheapq_heap_siftdown(heap, 0, heap->len - 1);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
|
||||
}
|
||||
@ -88,16 +88,16 @@ STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||
heap->items[0] = heap->items[heap->len];
|
||||
heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
|
||||
if (heap->len) {
|
||||
heap_siftup(heap, 0);
|
||||
uheapq_heap_siftup(heap, 0);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
||||
for (mp_uint_t i = heap->len / 2; i > 0;) {
|
||||
heap_siftup(heap, --i);
|
||||
uheapq_heap_siftup(heap, --i);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Damien P. George
|
||||
* Copyright (c) 2014-2019 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
|
||||
@ -281,9 +281,9 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load);
|
||||
|
||||
STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
|
||||
size_t len;
|
||||
const char *buf = mp_obj_str_get_data(obj, &len);
|
||||
vstr_t vstr = {len, len, (char*)buf, true};
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ);
|
||||
vstr_t vstr = {bufinfo.len, bufinfo.len, (char*)bufinfo.buf, true};
|
||||
mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
|
||||
return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));
|
||||
}
|
||||
|
||||
@ -382,6 +382,7 @@ STATIC const mp_obj_type_t re_type = {
|
||||
};
|
||||
|
||||
STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
const char *re_str = mp_obj_str_get_str(args[0]);
|
||||
int size = re1_5_sizecode(re_str);
|
||||
if (size == -1) {
|
||||
@ -389,18 +390,22 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
|
||||
o->base.type = &re_type;
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
int flags = 0;
|
||||
if (n_args > 1) {
|
||||
flags = mp_obj_get_int(args[1]);
|
||||
}
|
||||
#endif
|
||||
int error = re1_5_compilecode(&o->re, re_str);
|
||||
if (error != 0) {
|
||||
error:
|
||||
mp_raise_ValueError("Error in regex");
|
||||
}
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
if (flags & FLAG_DEBUG) {
|
||||
re1_5_dumpcode(&o->re);
|
||||
}
|
||||
#endif
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
|
||||
@ -440,7 +445,9 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
|
||||
#if MICROPY_PY_URE_SUB
|
||||
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
|
||||
@ -455,7 +462,9 @@ const mp_obj_module_t mp_module_ure = {
|
||||
|
||||
#define re1_5_fatal(x) assert(!x)
|
||||
#include "re1.5/compilecode.c"
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
#include "re1.5/dumpcode.c"
|
||||
#endif
|
||||
#include "re1.5/recursiveloop.c"
|
||||
#include "re1.5/charclass.c"
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ struct ssl_args {
|
||||
|
||||
STATIC const mp_obj_type_t ussl_socket_type;
|
||||
|
||||
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
|
||||
STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) {
|
||||
#if MICROPY_PY_USSL_FINALISER
|
||||
mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
|
||||
#else
|
||||
@ -118,13 +118,13 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
|
||||
return o;
|
||||
}
|
||||
|
||||
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<_SSLSocket %p>", self->ssl_sock);
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t ussl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
|
||||
if (o->ssl_sock == NULL) {
|
||||
@ -173,7 +173,7 @@ eagain:
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
STATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
|
||||
if (o->ssl_sock == NULL) {
|
||||
@ -189,7 +189,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
|
||||
return r;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
STATIC mp_uint_t ussl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
|
||||
if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {
|
||||
ssl_free(self->ssl_sock);
|
||||
@ -200,7 +200,7 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
|
||||
return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
|
||||
STATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
|
||||
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_t sock = o->sock;
|
||||
mp_obj_t dest[3];
|
||||
@ -210,14 +210,14 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
|
||||
o->blocking = mp_obj_is_true(flag_in);
|
||||
return res;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking);
|
||||
|
||||
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ussl_socket_setblocking_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
|
||||
#if MICROPY_PY_USSL_FINALISER
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
|
||||
@ -227,16 +227,16 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
|
||||
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
|
||||
|
||||
STATIC const mp_stream_p_t ussl_socket_stream_p = {
|
||||
.read = socket_read,
|
||||
.write = socket_write,
|
||||
.ioctl = socket_ioctl,
|
||||
.read = ussl_socket_read,
|
||||
.write = ussl_socket_write,
|
||||
.ioctl = ussl_socket_ioctl,
|
||||
};
|
||||
|
||||
STATIC const mp_obj_type_t ussl_socket_type = {
|
||||
{ &mp_type_type },
|
||||
// Save on qstr's, reuse same as for module
|
||||
.name = MP_QSTR_ussl,
|
||||
.print = socket_print,
|
||||
.print = ussl_socket_print,
|
||||
.getiter = NULL,
|
||||
.iternext = NULL,
|
||||
.protocol = &ussl_socket_stream_p,
|
||||
@ -260,7 +260,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
|
||||
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
|
||||
|
||||
return MP_OBJ_FROM_PTR(socket_new(sock, &args));
|
||||
return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ typedef struct _mp_obj_utimeq_t {
|
||||
|
||||
STATIC mp_uint_t utimeq_id;
|
||||
|
||||
STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) {
|
||||
STATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) {
|
||||
return MP_OBJ_TO_PTR(heap_in);
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
STATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
struct qentry item = heap->items[pos];
|
||||
while (pos > start_pos) {
|
||||
mp_uint_t parent_pos = (pos - 1) >> 1;
|
||||
@ -101,7 +101,7 @@ STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t
|
||||
heap->items[pos] = item;
|
||||
}
|
||||
|
||||
STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
|
||||
STATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
|
||||
mp_uint_t start_pos = pos;
|
||||
mp_uint_t end_pos = heap->len;
|
||||
struct qentry item = heap->items[pos];
|
||||
@ -118,13 +118,13 @@ STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
|
||||
pos = child_pos;
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
heap_siftdown(heap, start_pos, pos);
|
||||
utimeq_heap_siftdown(heap, start_pos, pos);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_t heap_in = args[0];
|
||||
mp_obj_utimeq_t *heap = get_heap(heap_in);
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
if (heap->len == heap->alloc) {
|
||||
mp_raise_msg(&mp_type_IndexError, "queue overflow");
|
||||
}
|
||||
@ -133,14 +133,14 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
|
||||
heap->items[l].id = utimeq_id++;
|
||||
heap->items[l].callback = args[2];
|
||||
heap->items[l].args = args[3];
|
||||
heap_siftdown(heap, 0, heap->len);
|
||||
utimeq_heap_siftdown(heap, 0, heap->len);
|
||||
heap->len++;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush);
|
||||
|
||||
STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
|
||||
mp_obj_utimeq_t *heap = get_heap(heap_in);
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
|
||||
}
|
||||
@ -158,14 +158,14 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
|
||||
heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer
|
||||
heap->items[heap->len].args = MP_OBJ_NULL;
|
||||
if (heap->len) {
|
||||
heap_siftup(heap, 0);
|
||||
utimeq_heap_siftup(heap, 0);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
|
||||
|
||||
STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
|
||||
mp_obj_utimeq_t *heap = get_heap(heap_in);
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
|
||||
}
|
||||
@ -177,7 +177,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime);
|
||||
|
||||
#if DEBUG
|
||||
STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
|
||||
mp_obj_utimeq_t *heap = get_heap(heap_in);
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
for (int i = 0; i < heap->len; i++) {
|
||||
printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time,
|
||||
MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args));
|
||||
|
||||
@ -219,7 +219,7 @@ STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size
|
||||
|
||||
// TODO gc hook to close the file if not already closed
|
||||
|
||||
STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
|
||||
STATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||
@ -234,10 +234,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table);
|
||||
|
||||
#if MICROPY_PY_IO_FILEIO
|
||||
STATIC const mp_stream_p_t fileio_stream_p = {
|
||||
STATIC const mp_stream_p_t vfs_fat_fileio_stream_p = {
|
||||
.read = file_obj_read,
|
||||
.write = file_obj_write,
|
||||
.ioctl = file_obj_ioctl,
|
||||
@ -250,12 +250,12 @@ const mp_obj_type_t mp_type_vfs_fat_fileio = {
|
||||
.make_new = file_obj_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &fileio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
|
||||
.protocol = &vfs_fat_fileio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
STATIC const mp_stream_p_t textio_stream_p = {
|
||||
STATIC const mp_stream_p_t vfs_fat_textio_stream_p = {
|
||||
.read = file_obj_read,
|
||||
.write = file_obj_write,
|
||||
.ioctl = file_obj_ioctl,
|
||||
@ -269,8 +269,8 @@ const mp_obj_type_t mp_type_vfs_fat_textio = {
|
||||
.make_new = file_obj_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &textio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
|
||||
.protocol = &vfs_fat_textio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,
|
||||
};
|
||||
|
||||
// Factory function for I/O stream classes
|
||||
|
||||
@ -200,7 +200,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||
}
|
||||
}
|
||||
|
||||
STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
|
||||
STATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||
@ -215,10 +215,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table);
|
||||
|
||||
#if MICROPY_PY_IO_FILEIO
|
||||
STATIC const mp_stream_p_t fileio_stream_p = {
|
||||
STATIC const mp_stream_p_t vfs_posix_fileio_stream_p = {
|
||||
.read = vfs_posix_file_read,
|
||||
.write = vfs_posix_file_write,
|
||||
.ioctl = vfs_posix_file_ioctl,
|
||||
@ -231,12 +231,12 @@ const mp_obj_type_t mp_type_vfs_posix_fileio = {
|
||||
.make_new = vfs_posix_file_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &fileio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
|
||||
.protocol = &vfs_posix_fileio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
STATIC const mp_stream_p_t textio_stream_p = {
|
||||
STATIC const mp_stream_p_t vfs_posix_textio_stream_p = {
|
||||
.read = vfs_posix_file_read,
|
||||
.write = vfs_posix_file_write,
|
||||
.ioctl = vfs_posix_file_ioctl,
|
||||
@ -250,8 +250,8 @@ const mp_obj_type_t mp_type_vfs_posix_textio = {
|
||||
.make_new = vfs_posix_file_make_new,
|
||||
.getiter = mp_identity_getiter,
|
||||
.iternext = mp_stream_unbuffered_iter,
|
||||
.protocol = &textio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
|
||||
.protocol = &vfs_posix_textio_stream_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,
|
||||
};
|
||||
|
||||
const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO};
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit a717b4456b3771ed8a3e1e9aa4802a43e501c003
|
||||
Subproject commit a29af27883dacb96e0b7bf1b75573a1d26026696
|
||||
@ -101,7 +101,7 @@ void upytest_execute_test(const char *src) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
@ -89,7 +89,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
// source is a lexer, parse and compile the script
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, exec_flags & EXEC_FLAG_IS_REPL);
|
||||
module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL);
|
||||
#else
|
||||
mp_raise_msg(&mp_type_RuntimeError, "script compilation not supported");
|
||||
#endif
|
||||
|
||||
@ -72,7 +72,7 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
|
||||
#endif
|
||||
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
|
||||
mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, emit_opt, false);
|
||||
mp_raw_code_t *rc = mp_compile_to_raw_code(&parse_tree, source_name, false);
|
||||
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 16);
|
||||
@ -115,7 +115,11 @@ STATIC int usage(char **argv) {
|
||||
);
|
||||
int impl_opts_cnt = 0;
|
||||
printf(
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
" emit={bytecode,native,viper} -- set the default code emitter\n"
|
||||
#else
|
||||
" emit=bytecode -- set the default code emitter\n"
|
||||
#endif
|
||||
);
|
||||
impl_opts_cnt++;
|
||||
printf(
|
||||
@ -140,10 +144,12 @@ STATIC void pre_process_options(int argc, char **argv) {
|
||||
}
|
||||
if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
|
||||
emit_opt = MP_EMIT_OPT_BYTECODE;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
} else if (strcmp(argv[a + 1], "emit=native") == 0) {
|
||||
emit_opt = MP_EMIT_OPT_NATIVE_PYTHON;
|
||||
} else if (strcmp(argv[a + 1], "emit=viper") == 0) {
|
||||
emit_opt = MP_EMIT_OPT_VIPER;
|
||||
#endif
|
||||
} else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) {
|
||||
char *end;
|
||||
heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0);
|
||||
@ -190,6 +196,13 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
// Set default emitter options
|
||||
MP_STATE_VM(default_emit_opt) = emit_opt;
|
||||
#else
|
||||
(void)emit_opt;
|
||||
#endif
|
||||
|
||||
// set default compiler configuration
|
||||
mp_dynamic_compiler.small_int_bits = 31;
|
||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
|
||||
|
||||
@ -13,7 +13,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
@ -1,7 +1,31 @@
|
||||
# Select the board to build for: if not given on the command line,
|
||||
# then default to GENERIC.
|
||||
BOARD ?= GENERIC
|
||||
|
||||
# If the build directory is not given, make it reflect the board name.
|
||||
BUILD ?= build-$(BOARD)
|
||||
|
||||
BOARD_DIR ?= boards/$(BOARD)
|
||||
ifeq ($(wildcard $(BOARD_DIR)/.),)
|
||||
$(error Invalid BOARD specified: $(BOARD_DIR))
|
||||
endif
|
||||
|
||||
include ../../py/mkenv.mk
|
||||
|
||||
# Optional (not currently used for ESP32)
|
||||
-include mpconfigport.mk
|
||||
|
||||
ifneq ($(SDKCONFIG),)
|
||||
$(error Use the BOARD variable instead of SDKCONFIG)
|
||||
endif
|
||||
|
||||
# Expected to set SDKCONFIG
|
||||
include $(BOARD_DIR)/mpconfigboard.mk
|
||||
|
||||
# qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h
|
||||
QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
|
||||
QSTR_GLOBAL_REQUIREMENTS = $(SDKCONFIG_H)
|
||||
|
||||
MICROPY_PY_USSL = 0
|
||||
MICROPY_SSL_AXTLS = 0
|
||||
@ -23,12 +47,11 @@ FLASH_SIZE ?= 4MB
|
||||
CROSS_COMPILE ?= xtensa-esp32-elf-
|
||||
OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
|
||||
# SDKCONFIG should be overridden to get a different configuration
|
||||
SDKCONFIG ?= boards/sdkconfig
|
||||
SDKCONFIG_COMBINED = $(BUILD)/sdkconfig.combined
|
||||
SDKCONFIG_H = $(BUILD)/sdkconfig.h
|
||||
|
||||
# the git hash of the currently supported ESP IDF version
|
||||
ESPIDF_SUPHASH := 6b3da6b1882f3b72e904cc90be67e9c4e3f369a9
|
||||
ESPIDF_SUPHASH := 6ccb4cf5b7d1fdddb8c2492f9cbc926abaf230df
|
||||
|
||||
# paths to ESP IDF and its components
|
||||
ifeq ($(ESPIDF),)
|
||||
@ -75,6 +98,7 @@ INC += -I$(BUILD)
|
||||
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include_bootloader
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/console
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/driver/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include
|
||||
@ -104,6 +128,9 @@ INC_ESPCOMP += -I$(ESPCOMP)/lwip/port/esp32/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/apps
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/mdns/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/mdns/private_include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/micro-ecc/micro-ecc
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/ulp/include
|
||||
INC_ESPCOMP += -I$(ESPCOMP)/vfs/include
|
||||
@ -128,6 +155,7 @@ CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_co
|
||||
CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP)
|
||||
CFLAGS += -DIDF_VER=\"$(IDF_VER)\"
|
||||
CFLAGS += $(CFLAGS_MOD) $(CFLAGS_EXTRA)
|
||||
CFLAGS += -I$(BOARD_DIR)
|
||||
|
||||
# this is what ESPIDF uses for c++ compilation
|
||||
CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP)
|
||||
@ -191,6 +219,7 @@ SRC_C = \
|
||||
network_ppp.c \
|
||||
modsocket.c \
|
||||
modesp.c \
|
||||
esp32_partition.c \
|
||||
esp32_ulp.c \
|
||||
modesp32.c \
|
||||
espneopixel.c \
|
||||
@ -199,6 +228,7 @@ SRC_C = \
|
||||
mpthreadport.c \
|
||||
machine_rtc.c \
|
||||
machine_sdcard.c \
|
||||
$(wildcard $(BOARD_DIR)/*.c) \
|
||||
$(SRC_MOD)
|
||||
|
||||
EXTMOD_SRC_C = $(addprefix extmod/,\
|
||||
@ -266,7 +296,11 @@ SRC_QSTR_AUTO_DEPS +=
|
||||
################################################################################
|
||||
# Generate sdkconfig.h from sdkconfig
|
||||
|
||||
$(SDKCONFIG_H): $(SDKCONFIG)
|
||||
$(SDKCONFIG_COMBINED): $(SDKCONFIG)
|
||||
$(Q)$(MKDIR) -p $(dir $@)
|
||||
$(Q)$(CAT) $^ > $@
|
||||
|
||||
$(SDKCONFIG_H): $(SDKCONFIG_COMBINED)
|
||||
$(ECHO) "GEN $@"
|
||||
$(Q)$(MKDIR) -p $(dir $@)
|
||||
$(Q)$(PYTHON) $(ESPIDF)/tools/kconfig_new/confgen.py \
|
||||
@ -279,11 +313,15 @@ $(SDKCONFIG_H): $(SDKCONFIG)
|
||||
--env "COMPONENT_KCONFIGS_PROJBUILD=$(ESPCOMP_KCONFIGS_PROJBUILD)"
|
||||
$(Q)touch $@
|
||||
|
||||
$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H)
|
||||
$(HEADER_BUILD)/qstrdefs.generated.h: $(SDKCONFIG_H) $(BOARD_DIR)/mpconfigboard.h
|
||||
|
||||
################################################################################
|
||||
# List of object files from the ESP32 IDF components
|
||||
|
||||
ESPIDF_BOOTLOADER_SUPPORT_O = $(patsubst %.c,%.o,\
|
||||
$(filter-out $(ESPCOMP)/bootloader_support/src/bootloader_init.c,\
|
||||
$(wildcard $(ESPCOMP)/bootloader_support/src/*.c)))
|
||||
|
||||
ESPIDF_DRIVER_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/driver/*.c))
|
||||
|
||||
ESPIDF_EFUSE_O = $(patsubst %.c,%.o,\
|
||||
@ -373,6 +411,8 @@ ESPIDF_MBEDTLS_O = $(patsubst %.c,%.o,\
|
||||
$(wildcard $(ESPCOMP)/mbedtls/port/*.c) \
|
||||
)
|
||||
|
||||
ESPIDF_MDNS_O = $(patsubst %.c,%.o,$(wildcard $(ESPCOMP)/mdns/*.c))
|
||||
|
||||
$(BUILD)/$(ESPCOMP)/wpa_supplicant/%.o: CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DALLOW_EVEN_MOD -D__ets__ -Wno-strict-aliasing
|
||||
ESPIDF_WPA_SUPPLICANT_O = $(patsubst %.c,%.o,\
|
||||
$(wildcard $(ESPCOMP)/wpa_supplicant/port/*.c) \
|
||||
@ -393,6 +433,7 @@ $(BUILD_ESPIDF_LIB)/$(1)/lib$(1).a: $(addprefix $$(BUILD)/,$(2))
|
||||
$(Q)$(AR) cru $$@ $$^
|
||||
endef
|
||||
|
||||
$(eval $(call gen_espidf_lib_rule,bootloader_support,$(ESPIDF_BOOTLOADER_SUPPORT_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,driver,$(ESPIDF_DRIVER_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,efuse,$(ESPIDF_EFUSE_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,esp32,$(ESPIDF_ESP32_O)))
|
||||
@ -417,6 +458,7 @@ $(eval $(call gen_espidf_lib_rule,spi_flash,$(ESPIDF_SPI_FLASH_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,mdns,$(ESPIDF_MDNS_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O)))
|
||||
$(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O)))
|
||||
|
||||
@ -450,12 +492,12 @@ $(eval $(foreach lib,$(LIB_ESPIDF),$(eval $(call gen_sections_info_rule,$(BUILD_
|
||||
$(LDGEN_SECTION_INFOS): $(LDGEN_SECTIONS_INFO) $(ESPIDF)/make/ldgen.mk
|
||||
$(Q)printf "$(foreach info,$(LDGEN_SECTIONS_INFO),$(info)\n)" > $@
|
||||
|
||||
$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG) $(LDGEN_SECTION_INFOS)
|
||||
$(BUILD)/esp32.project.ld: $(ESPCOMP)/esp32/ld/esp32.project.ld.in $(LDGEN_FRAGMENTS) $(SDKCONFIG_COMBINED) $(LDGEN_SECTION_INFOS)
|
||||
$(ECHO) "GEN $@"
|
||||
$(Q)$(PYTHON) $(ESPIDF)/tools/ldgen/ldgen.py \
|
||||
--input $< \
|
||||
--output $@ \
|
||||
--config $(SDKCONFIG) \
|
||||
--config $(SDKCONFIG_COMBINED) \
|
||||
--kconfig $(ESPIDF)/Kconfig \
|
||||
--fragments $(LDGEN_FRAGMENTS) \
|
||||
--sections $(LDGEN_SECTION_INFOS) \
|
||||
@ -493,6 +535,7 @@ OBJ = $(OBJ_MP)
|
||||
|
||||
APP_LD_ARGS =
|
||||
APP_LD_ARGS += $(LDFLAGS_MOD)
|
||||
APP_LD_ARGS += $(addprefix -T,$(LD_FILES))
|
||||
APP_LD_ARGS += --start-group
|
||||
APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
|
||||
APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++
|
||||
@ -674,7 +717,9 @@ $(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ) $(addprefix $(BOOTLOADER_LIB_DIR)/lib
|
||||
# Declarations to build the partitions
|
||||
|
||||
PYTHON2 ?= python2
|
||||
PART_SRC = partitions.csv
|
||||
|
||||
# Can be overriden by mkconfigboard.mk.
|
||||
PART_SRC ?= partitions.csv
|
||||
|
||||
$(BUILD)/partitions.bin: $(PART_SRC)
|
||||
$(ECHO) "Create $@"
|
||||
|
||||
@ -74,11 +74,11 @@ variables for the build. In that case, create a new file in the esp32
|
||||
directory called `makefile` and add the following lines to that file:
|
||||
```
|
||||
ESPIDF = <path to root of esp-idf repository>
|
||||
BOARD = GENERIC
|
||||
#PORT = /dev/ttyUSB0
|
||||
#FLASH_MODE = qio
|
||||
#FLASH_SIZE = 4MB
|
||||
#CROSS_COMPILE = xtensa-esp32-elf-
|
||||
#SDKCONFIG = boards/sdkconfig.spiram
|
||||
|
||||
include Makefile
|
||||
```
|
||||
@ -92,16 +92,18 @@ are `PORT` for the serial port of your esp32 module, and `FLASH_MODE`
|
||||
(which may need to be `dio` for some modules)
|
||||
and `FLASH_SIZE`. See the Makefile for further information.
|
||||
|
||||
The default ESP IDF configuration settings are provided in the file
|
||||
`boards/sdkconfig`, and this file is specified in the build by the make
|
||||
variable `SDKCONFIG`. To use a custom configuration either set `SDKCONFIG`
|
||||
in your custom `makefile` (or `GNUmakefile`) or set this variable on the
|
||||
command line:
|
||||
The default ESP IDF configuration settings are provided by the `GENERIC`
|
||||
board definition in the directory `boards/GENERIC`. For a custom configuration
|
||||
you can define your own board directory.
|
||||
|
||||
The `BOARD` variable can be set on the make command line:
|
||||
```bash
|
||||
$ make SDKCONFIG=sdkconfig.myboard
|
||||
$ make BOARD=TINYPICO
|
||||
```
|
||||
The file `boards/sdkconfig.spiram` is provided for ESP32 modules that have
|
||||
external SPIRAM.
|
||||
or added to your custom `makefile` (or `GNUmakefile`) described above. There
|
||||
is also a `GENERIC_SPIRAM` board for for ESP32 modules that have external
|
||||
SPIRAM, but prefer to use a specific board target (or define your own as
|
||||
necessary).
|
||||
|
||||
Building the firmware
|
||||
---------------------
|
||||
|
||||
2
ports/esp32/boards/GENERIC/mpconfigboard.h
Normal file
2
ports/esp32/boards/GENERIC/mpconfigboard.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define MICROPY_HW_BOARD_NAME "ESP32 module"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32"
|
||||
1
ports/esp32/boards/GENERIC/mpconfigboard.mk
Normal file
1
ports/esp32/boards/GENERIC/mpconfigboard.mk
Normal file
@ -0,0 +1 @@
|
||||
SDKCONFIG += boards/sdkconfig.base
|
||||
2
ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h
Normal file
2
ports/esp32/boards/GENERIC_D2WD/mpconfigboard.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Generic ESP32-D2WD module"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-D2WD"
|
||||
5
ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk
Normal file
5
ports/esp32/boards/GENERIC_D2WD/mpconfigboard.mk
Normal file
@ -0,0 +1,5 @@
|
||||
SDKCONFIG += boards/sdkconfig.base
|
||||
PART_SRC = partitions-2MiB.csv
|
||||
FLASH_SIZE = 2MB
|
||||
FLASH_MODE = dio
|
||||
FLASH_FREQ = 40m
|
||||
2
ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h
Normal file
2
ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define MICROPY_HW_BOARD_NAME "ESP32 module (spiram)"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32"
|
||||
2
ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk
Normal file
2
ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.mk
Normal file
@ -0,0 +1,2 @@
|
||||
SDKCONFIG += boards/sdkconfig.base
|
||||
SDKCONFIG += boards/sdkconfig.spiram
|
||||
2
ports/esp32/boards/TINYPICO/mpconfigboard.h
Normal file
2
ports/esp32/boards/TINYPICO/mpconfigboard.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define MICROPY_HW_BOARD_NAME "TinyPICO"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
|
||||
5
ports/esp32/boards/TINYPICO/mpconfigboard.mk
Normal file
5
ports/esp32/boards/TINYPICO/mpconfigboard.mk
Normal file
@ -0,0 +1,5 @@
|
||||
FLASH_FREQ = 80m
|
||||
|
||||
SDKCONFIG += boards/sdkconfig.base
|
||||
SDKCONFIG += boards/sdkconfig.spiram
|
||||
SDKCONFIG += boards/TINYPICO/sdkconfig.board
|
||||
3
ports/esp32/boards/TINYPICO/sdkconfig.board
Normal file
3
ports/esp32/boards/TINYPICO/sdkconfig.board
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
@ -1,34 +1,5 @@
|
||||
# MicroPython on ESP32, ESP IDF configuration with SPIRAM support
|
||||
# The following options override the defaults
|
||||
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
# Application manager
|
||||
CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y
|
||||
CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y
|
||||
|
||||
# Bootloader config
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y
|
||||
|
||||
# ESP32-specific
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||
CONFIG_SPIRAM_USE_MEMMAP=y
|
||||
CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=n
|
||||
CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=n
|
||||
CONFIG_ESP32_XTAL_FREQ_AUTO=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=n
|
||||
|
||||
# Power Management
|
||||
CONFIG_PM_ENABLE=y
|
||||
|
||||
# FreeRTOS
|
||||
CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=2
|
||||
CONFIG_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK=y
|
||||
|
||||
# UDP
|
||||
CONFIG_PPP_SUPPORT=y
|
||||
CONFIG_PPP_PAP_SUPPORT=y
|
||||
CONFIG_PPP_CHAP_SUPPORT=y
|
||||
|
||||
223
ports/esp32/esp32_partition.c
Normal file
223
ports/esp32/esp32_partition.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 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 <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "modesp32.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
// esp_partition_read and esp_partition_write can operate on arbitrary bytes
|
||||
// but esp_partition_erase_range operates on 4k blocks. But to make a partition
|
||||
// implement the standard block protocol all operations are done on 4k blocks.
|
||||
#define BLOCK_SIZE_BYTES (4096)
|
||||
|
||||
enum {
|
||||
ESP32_PARTITION_BOOT,
|
||||
ESP32_PARTITION_RUNNING,
|
||||
};
|
||||
|
||||
typedef struct _esp32_partition_obj_t {
|
||||
mp_obj_base_t base;
|
||||
const esp_partition_t *part;
|
||||
} esp32_partition_obj_t;
|
||||
|
||||
static inline void check_esp_err(esp_err_t e) {
|
||||
if (e != ESP_OK) {
|
||||
mp_raise_OSError(-e);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC esp32_partition_obj_t *esp32_partition_new(const esp_partition_t *part) {
|
||||
if (part == NULL) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
||||
esp32_partition_obj_t *self = m_new_obj(esp32_partition_obj_t);
|
||||
self->base.type = &esp32_partition_type;
|
||||
self->part = part;
|
||||
return self;
|
||||
}
|
||||
|
||||
STATIC void esp32_partition_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<Partition type=%u, subtype=%u, address=%u, size=%u, label=%s, encrypted=%u>",
|
||||
self->part->type, self->part->subtype,
|
||||
self->part->address, self->part->size,
|
||||
&self->part->label[0], self->part->encrypted
|
||||
);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp32_partition_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||
// Check args
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
// Get requested partition
|
||||
const esp_partition_t *part;
|
||||
if (mp_obj_is_int(all_args[0])) {
|
||||
// Integer given, get that particular partition
|
||||
switch (mp_obj_get_int(all_args[0])) {
|
||||
case ESP32_PARTITION_BOOT:
|
||||
part = esp_ota_get_boot_partition();
|
||||
break;
|
||||
case ESP32_PARTITION_RUNNING:
|
||||
part = esp_ota_get_running_partition();
|
||||
break;
|
||||
default:
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
} else {
|
||||
// String given, search for partition with that label
|
||||
const char *label = mp_obj_str_get_str(all_args[0]);
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, label);
|
||||
if (part == NULL) {
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, label);
|
||||
}
|
||||
}
|
||||
|
||||
// Return new object
|
||||
return MP_OBJ_FROM_PTR(esp32_partition_new(part));
|
||||
}
|
||||
|
||||
STATIC mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// Parse args
|
||||
enum { ARG_type, ARG_subtype, ARG_label };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_type, MP_ARG_INT, {.u_int = ESP_PARTITION_TYPE_APP} },
|
||||
{ MP_QSTR_subtype, MP_ARG_INT, {.u_int = ESP_PARTITION_SUBTYPE_ANY} },
|
||||
{ MP_QSTR_label, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
// Get optional label string
|
||||
const char *label = NULL;
|
||||
if (args[ARG_label].u_obj != mp_const_none) {
|
||||
label = mp_obj_str_get_str(args[ARG_label].u_obj);
|
||||
}
|
||||
|
||||
// Build list of matching partitions
|
||||
mp_obj_t list = mp_obj_new_list(0, NULL);
|
||||
esp_partition_iterator_t iter = esp_partition_find(args[ARG_type].u_int, args[ARG_subtype].u_int, label);
|
||||
while (iter != NULL) {
|
||||
mp_obj_list_append(list, MP_OBJ_FROM_PTR(esp32_partition_new(esp_partition_get(iter))));
|
||||
iter = esp_partition_next(iter);
|
||||
}
|
||||
esp_partition_iterator_release(iter);
|
||||
|
||||
return list;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_partition_find_fun_obj, 0, esp32_partition_find);
|
||||
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(esp32_partition_find_obj, MP_ROM_PTR(&esp32_partition_find_fun_obj));
|
||||
|
||||
STATIC mp_obj_t esp32_partition_info(mp_obj_t self_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_t tuple[] = {
|
||||
MP_OBJ_NEW_SMALL_INT(self->part->type),
|
||||
MP_OBJ_NEW_SMALL_INT(self->part->subtype),
|
||||
mp_obj_new_int_from_uint(self->part->address),
|
||||
mp_obj_new_int_from_uint(self->part->size),
|
||||
mp_obj_new_str(&self->part->label[0], strlen(&self->part->label[0])),
|
||||
mp_obj_new_bool(self->part->encrypted),
|
||||
};
|
||||
return mp_obj_new_tuple(6, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_info_obj, esp32_partition_info);
|
||||
|
||||
STATIC mp_obj_t esp32_partition_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES;
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
|
||||
check_esp_err(esp_partition_read(self->part, offset, bufinfo.buf, bufinfo.len));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_readblocks_obj, esp32_partition_readblocks);
|
||||
|
||||
STATIC mp_obj_t esp32_partition_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t offset = mp_obj_get_int(block_num) * BLOCK_SIZE_BYTES;
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
check_esp_err(esp_partition_erase_range(self->part, offset, bufinfo.len));
|
||||
check_esp_err(esp_partition_write(self->part, offset, bufinfo.buf, bufinfo.len));
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_writeblocks_obj, esp32_partition_writeblocks);
|
||||
|
||||
STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_int_t cmd = mp_obj_get_int(cmd_in);
|
||||
switch (cmd) {
|
||||
case BP_IOCTL_INIT: return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_DEINIT: return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SYNC: return MP_OBJ_NEW_SMALL_INT(0);
|
||||
case BP_IOCTL_SEC_COUNT: return MP_OBJ_NEW_SMALL_INT(self->part->size / BLOCK_SIZE_BYTES);
|
||||
case BP_IOCTL_SEC_SIZE: return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
|
||||
default: return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_partition_ioctl_obj, esp32_partition_ioctl);
|
||||
|
||||
STATIC mp_obj_t esp32_partition_set_boot(mp_obj_t self_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
esp_ota_set_boot_partition(self->part);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_set_boot_obj, esp32_partition_set_boot);
|
||||
|
||||
STATIC mp_obj_t esp32_partition_get_next_update(mp_obj_t self_in) {
|
||||
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_FROM_PTR(esp32_partition_new(esp_ota_get_next_update_partition(self->part)));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_get_next_update_obj, esp32_partition_get_next_update);
|
||||
|
||||
STATIC const mp_rom_map_elem_t esp32_partition_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_find), MP_ROM_PTR(&esp32_partition_find_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&esp32_partition_info_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&esp32_partition_readblocks_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&esp32_partition_writeblocks_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&esp32_partition_ioctl_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_boot), MP_ROM_PTR(&esp32_partition_set_boot_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_next_update), MP_ROM_PTR(&esp32_partition_get_next_update_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_INT(ESP32_PARTITION_BOOT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_RUNNING), MP_ROM_INT(ESP32_PARTITION_RUNNING) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TYPE_APP), MP_ROM_INT(ESP_PARTITION_TYPE_APP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TYPE_DATA), MP_ROM_INT(ESP_PARTITION_TYPE_DATA) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(esp32_partition_locals_dict, esp32_partition_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t esp32_partition_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Partition,
|
||||
.print = esp32_partition_print,
|
||||
.make_new = esp32_partition_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&esp32_partition_locals_dict,
|
||||
};
|
||||
@ -53,12 +53,15 @@ STATIC const madc_obj_t madc_obj[] = {
|
||||
{{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7},
|
||||
};
|
||||
|
||||
STATIC uint8_t adc_bit_width;
|
||||
|
||||
STATIC mp_obj_t madc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
||||
const mp_obj_t *args) {
|
||||
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
adc1_config_width(ADC_WIDTH_12Bit);
|
||||
adc_bit_width = 12;
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
@ -79,6 +82,17 @@ STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_
|
||||
mp_printf(print, "ADC(Pin(%u))", self->gpio_id);
|
||||
}
|
||||
|
||||
// read_u16()
|
||||
STATIC mp_obj_t madc_read_u16(mp_obj_t self_in) {
|
||||
madc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t raw = adc1_get_raw(self->adc1_id);
|
||||
// Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16)
|
||||
uint32_t u16 = raw << (16 - adc_bit_width) | raw >> (2 * adc_bit_width - 16);
|
||||
return MP_OBJ_NEW_SMALL_INT(u16);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(madc_read_u16_obj, madc_read_u16);
|
||||
|
||||
// Legacy method
|
||||
STATIC mp_obj_t madc_read(mp_obj_t self_in) {
|
||||
madc_obj_t *self = self_in;
|
||||
int val = adc1_get_raw(self->adc1_id);
|
||||
@ -99,13 +113,24 @@ MP_DEFINE_CONST_FUN_OBJ_2(madc_atten_obj, madc_atten);
|
||||
STATIC mp_obj_t madc_width(mp_obj_t cls_in, mp_obj_t width_in) {
|
||||
adc_bits_width_t width = mp_obj_get_int(width_in);
|
||||
esp_err_t err = adc1_config_width(width);
|
||||
if (err == ESP_OK) return mp_const_none;
|
||||
mp_raise_ValueError("Parameter Error");
|
||||
if (err != ESP_OK) {
|
||||
mp_raise_ValueError("Parameter Error");
|
||||
}
|
||||
switch (width) {
|
||||
case ADC_WIDTH_9Bit: adc_bit_width = 9; break;
|
||||
case ADC_WIDTH_10Bit: adc_bit_width = 10; break;
|
||||
case ADC_WIDTH_11Bit: adc_bit_width = 11; break;
|
||||
case ADC_WIDTH_12Bit: adc_bit_width = 12; break;
|
||||
default: break;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(madc_width_fun_obj, madc_width);
|
||||
MP_DEFINE_CONST_CLASSMETHOD_OBJ(madc_width_obj, MP_ROM_PTR(&madc_width_fun_obj));
|
||||
|
||||
STATIC const mp_rom_map_elem_t madc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&madc_read_u16_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&madc_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_atten), MP_ROM_PTR(&madc_atten_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&madc_width_obj) },
|
||||
|
||||
@ -154,6 +154,7 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) },
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define RTC_LAST_EXT_PIN 39
|
||||
#define RTC_IS_VALID_EXT_PIN(pin_id) ((1ll << (pin_id)) & RTC_VALID_EXT_PINS)
|
||||
|
||||
extern const mp_obj_type_t esp32_partition_type;
|
||||
extern const mp_obj_type_t esp32_ulp_type;
|
||||
|
||||
#endif // MICROPY_INCLUDED_ESP32_MODESP32_H
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
#include "esp_event_loop.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "tcpip_adapter.h"
|
||||
#include "mdns.h"
|
||||
|
||||
#include "modnetwork.h"
|
||||
|
||||
@ -128,6 +129,11 @@ static bool wifi_sta_connected = false;
|
||||
// Store the current status. 0 means None here, safe to do so as first enum value is WIFI_REASON_UNSPECIFIED=1.
|
||||
static uint8_t wifi_sta_disconn_reason = 0;
|
||||
|
||||
#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
|
||||
// Whether mDNS has been initialised or not
|
||||
static bool mdns_initialised = false;
|
||||
#endif
|
||||
|
||||
// This function is called by the system-event task and so runs in a different
|
||||
// thread to the main MicroPython task. It must not raise any Python exceptions.
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event) {
|
||||
@ -142,6 +148,20 @@ static esp_err_t event_handler(void *ctx, system_event_t *event) {
|
||||
ESP_LOGI("network", "GOT_IP");
|
||||
wifi_sta_connected = true;
|
||||
wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
|
||||
#if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
|
||||
if (!mdns_initialised) {
|
||||
mdns_init();
|
||||
#if MICROPY_HW_ENABLE_MDNS_RESPONDER
|
||||
const char *hostname = NULL;
|
||||
if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) {
|
||||
hostname = "esp32";
|
||||
}
|
||||
mdns_hostname_set(hostname);
|
||||
mdns_instance_name_set(hostname);
|
||||
#endif
|
||||
mdns_initialised = true;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED: {
|
||||
// This is a workaround as ESP32 WiFi libs don't currently
|
||||
@ -530,17 +550,24 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
|
||||
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
|
||||
// get the config for the interface
|
||||
bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA;
|
||||
|
||||
wifi_config_t cfg;
|
||||
ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg));
|
||||
if (is_wifi) {
|
||||
ESP_EXCEPTIONS(esp_wifi_get_config(self->if_id, &cfg));
|
||||
}
|
||||
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
|
||||
if (kwargs->used != 0) {
|
||||
if (!is_wifi) {
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kwargs->alloc; i++) {
|
||||
if (mp_map_slot_is_filled(kwargs, i)) {
|
||||
int req_if = -1;
|
||||
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
switch ((uintptr_t)kwargs->table[i].key) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
mp_buffer_info_t bufinfo;
|
||||
@ -592,7 +619,6 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
#undef QS
|
||||
|
||||
// We post-check interface requirements to save on code size
|
||||
if (req_if >= 0) {
|
||||
@ -613,20 +639,34 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
}
|
||||
|
||||
int req_if = -1;
|
||||
mp_obj_t val;
|
||||
mp_obj_t val = mp_const_none;
|
||||
|
||||
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
|
||||
switch ((uintptr_t)args[1]) {
|
||||
case QS(MP_QSTR_mac): {
|
||||
uint8_t mac[6];
|
||||
ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac));
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
switch (self->if_id) {
|
||||
case WIFI_IF_AP: // fallthrough intentional
|
||||
case WIFI_IF_STA:
|
||||
ESP_EXCEPTIONS(esp_wifi_get_mac(self->if_id, mac));
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
|
||||
case ESP_IF_ETH:
|
||||
esp_eth_get_mac(mac);
|
||||
return mp_obj_new_bytes(mac, sizeof(mac));
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
}
|
||||
case QS(MP_QSTR_essid):
|
||||
if (self->if_id == WIFI_IF_STA) {
|
||||
val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid));
|
||||
} else {
|
||||
val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len);
|
||||
switch (self->if_id) {
|
||||
case WIFI_IF_STA:
|
||||
val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid));
|
||||
break;
|
||||
case WIFI_IF_AP:
|
||||
val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len);
|
||||
break;
|
||||
default:
|
||||
req_if = WIFI_IF_AP;
|
||||
}
|
||||
break;
|
||||
case QS(MP_QSTR_hidden):
|
||||
@ -650,6 +690,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
|
||||
#undef QS
|
||||
|
||||
// We post-check interface requirements to save on code size
|
||||
@ -662,8 +703,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
|
||||
unknown:
|
||||
mp_raise_ValueError("unknown config param");
|
||||
}
|
||||
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
|
||||
|
||||
STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
|
||||
|
||||
@ -31,6 +31,7 @@ enum { PHY_LAN8720, PHY_TLK110 };
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(esp_config_obj);
|
||||
|
||||
void usocket_events_deinit(void);
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/netutils/netutils.h"
|
||||
#include "tcpip_adapter.h"
|
||||
#include "mdns.h"
|
||||
#include "modnetwork.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
@ -56,6 +57,8 @@
|
||||
#include "esp_log.h"
|
||||
|
||||
#define SOCKET_POLL_US (100000)
|
||||
#define MDNS_QUERY_TIMEOUT_MS (5000)
|
||||
#define MDNS_LOCAL_SUFFIX ".local"
|
||||
|
||||
typedef struct _socket_obj_t {
|
||||
mp_obj_base_t base;
|
||||
@ -150,6 +153,58 @@ static inline void check_for_exceptions(void) {
|
||||
mp_handle_pending();
|
||||
}
|
||||
|
||||
// This function mimics lwip_getaddrinfo, with added support for mDNS queries
|
||||
static int _socket_getaddrinfo3(const char *nodename, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res) {
|
||||
|
||||
#if MICROPY_HW_ENABLE_MDNS_QUERIES
|
||||
int nodename_len = strlen(nodename);
|
||||
const int local_len = sizeof(MDNS_LOCAL_SUFFIX) - 1;
|
||||
if (nodename_len > local_len
|
||||
&& strcasecmp(nodename + nodename_len - local_len, MDNS_LOCAL_SUFFIX) == 0) {
|
||||
// mDNS query
|
||||
char nodename_no_local[nodename_len - local_len + 1];
|
||||
memcpy(nodename_no_local, nodename, nodename_len - local_len);
|
||||
nodename_no_local[nodename_len - local_len] = '\0';
|
||||
|
||||
struct ip4_addr addr = {0};
|
||||
esp_err_t err = mdns_query_a(nodename_no_local, MDNS_QUERY_TIMEOUT_MS, &addr);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NOT_FOUND){
|
||||
*res = NULL;
|
||||
return 0;
|
||||
}
|
||||
*res = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
struct addrinfo *ai = memp_malloc(MEMP_NETDB);
|
||||
if (ai == NULL) {
|
||||
*res = NULL;
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
|
||||
|
||||
struct sockaddr_in *sa = (struct sockaddr_in*)((uint8_t*)ai + sizeof(struct addrinfo));
|
||||
inet_addr_from_ip4addr(&sa->sin_addr, &addr);
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_len = sizeof(struct sockaddr_in);
|
||||
sa->sin_port = lwip_htons((u16_t)atoi(servname));
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_canonname = ((char*)sa + sizeof(struct sockaddr_storage));
|
||||
memcpy(ai->ai_canonname, nodename, nodename_len + 1);
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_storage);
|
||||
ai->ai_addr = (struct sockaddr*)sa;
|
||||
|
||||
*res = ai;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Normal query
|
||||
return lwip_getaddrinfo(nodename, servname, hints, res);
|
||||
}
|
||||
|
||||
static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {
|
||||
const struct addrinfo hints = {
|
||||
.ai_family = AF_INET,
|
||||
@ -172,7 +227,7 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc
|
||||
}
|
||||
|
||||
MP_THREAD_GIL_EXIT();
|
||||
int res = lwip_getaddrinfo(host_str, port_str, &hints, resp);
|
||||
int res = _socket_getaddrinfo3(host_str, port_str, &hints, resp);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
|
||||
return res;
|
||||
|
||||
@ -1,34 +1,4 @@
|
||||
import esp
|
||||
from esp32 import Partition
|
||||
|
||||
class FlashBdev:
|
||||
|
||||
SEC_SIZE = 4096
|
||||
START_SEC = esp.flash_user_start() // SEC_SIZE
|
||||
|
||||
def __init__(self, blocks):
|
||||
self.blocks = blocks
|
||||
|
||||
def readblocks(self, n, buf):
|
||||
#print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
|
||||
esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf)
|
||||
|
||||
def writeblocks(self, n, buf):
|
||||
#print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
|
||||
#assert len(buf) <= self.SEC_SIZE, len(buf)
|
||||
esp.flash_erase(n + self.START_SEC)
|
||||
esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf)
|
||||
|
||||
def ioctl(self, op, arg):
|
||||
#print("ioctl(%d, %r)" % (op, arg))
|
||||
if op == 4: # BP_IOCTL_SEC_COUNT
|
||||
return self.blocks
|
||||
if op == 5: # BP_IOCTL_SEC_SIZE
|
||||
return self.SEC_SIZE
|
||||
|
||||
size = esp.flash_size()
|
||||
if size < 1024*1024:
|
||||
# flash too small for a filesystem
|
||||
bdev = None
|
||||
else:
|
||||
# for now we use a fixed size for the filesystem
|
||||
bdev = FlashBdev(2048 * 1024 // FlashBdev.SEC_SIZE)
|
||||
bdev = Partition.find(Partition.TYPE_DATA, label='vfs')
|
||||
bdev = bdev[0] if bdev else None
|
||||
|
||||
@ -2,7 +2,7 @@ import uos
|
||||
from flashbdev import bdev
|
||||
|
||||
def check_bootsec():
|
||||
buf = bytearray(bdev.SEC_SIZE)
|
||||
buf = bytearray(bdev.ioctl(5, 0)) # 5 is SEC_SIZE
|
||||
bdev.readblocks(0, buf)
|
||||
empty = True
|
||||
for b in buf:
|
||||
@ -29,8 +29,7 @@ def setup():
|
||||
print("Performing initial setup")
|
||||
uos.VfsFat.mkfs(bdev)
|
||||
vfs = uos.VfsFat(bdev)
|
||||
uos.mount(vfs, '/flash')
|
||||
uos.chdir('/flash')
|
||||
uos.mount(vfs, '/')
|
||||
with open("boot.py", "w") as f:
|
||||
f.write("""\
|
||||
# This file is executed on every boot (including wake-boot from deepsleep)
|
||||
|
||||
486
ports/esp32/modules/uftpd.py
Normal file
486
ports/esp32/modules/uftpd.py
Normal file
@ -0,0 +1,486 @@
|
||||
#
|
||||
# Small ftp server for ESP8266 Micropython
|
||||
# Based on the work of chrisgp - Christopher Popp and pfalcon - Paul Sokolovsky
|
||||
#
|
||||
# The server accepts passive mode only. It runs in background.
|
||||
# Start the server with:
|
||||
#
|
||||
# import uftpd
|
||||
# uftpd.start([port = 21][, verbose = level])
|
||||
#
|
||||
# port is the port number (default 21)
|
||||
# verbose controls the level of printed activity messages, values 0, 1, 2
|
||||
#
|
||||
# Copyright (c) 2016 Christopher Popp (initial ftp server framework)
|
||||
# Copyright (c) 2016 Paul Sokolovsky (background execution control structure)
|
||||
# Copyright (c) 2016 Robert Hammelrath (putting the pieces together and a
|
||||
# few extensions)
|
||||
# Distributed under MIT License
|
||||
#
|
||||
import socket
|
||||
import network
|
||||
import uos
|
||||
import gc
|
||||
from time import sleep_ms, localtime
|
||||
from micropython import alloc_emergency_exception_buf
|
||||
|
||||
# constant definitions
|
||||
_CHUNK_SIZE = const(1024)
|
||||
_SO_REGISTER_HANDLER = const(20)
|
||||
_COMMAND_TIMEOUT = const(300)
|
||||
_DATA_TIMEOUT = const(100)
|
||||
_DATA_PORT = const(13333)
|
||||
|
||||
# Global variables
|
||||
ftpsocket = None
|
||||
datasocket = None
|
||||
client_list = []
|
||||
verbose_l = 0
|
||||
client_busy = False
|
||||
# Interfaces: (IP-Address (string), IP-Address (integer), Netmask (integer))
|
||||
AP_addr = ("0.0.0.0", 0, 0xffffff00)
|
||||
STA_addr = ("0.0.0.0", 0, 0xffffff00)
|
||||
|
||||
_month_name = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
|
||||
|
||||
|
||||
class FTP_client:
|
||||
|
||||
def __init__(self, ftpsocket):
|
||||
global AP_addr, STA_addr
|
||||
self.command_client, self.remote_addr = ftpsocket.accept()
|
||||
self.remote_addr = self.remote_addr[0]
|
||||
self.command_client.settimeout(_COMMAND_TIMEOUT)
|
||||
log_msg(1, "FTP Command connection from:", self.remote_addr)
|
||||
self.command_client.setsockopt(socket.SOL_SOCKET,
|
||||
_SO_REGISTER_HANDLER,
|
||||
self.exec_ftp_command)
|
||||
self.command_client.sendall("220 Hello, this is the ESP8266.\r\n")
|
||||
self.cwd = '/'
|
||||
self.fromname = None
|
||||
# self.logged_in = False
|
||||
self.act_data_addr = self.remote_addr
|
||||
self.DATA_PORT = 20
|
||||
self.active = True
|
||||
# check which interface was used by comparing the caller's ip
|
||||
# adress with the ip adresses of STA and AP; consider netmask;
|
||||
# select IP address for passive mode
|
||||
if ((AP_addr[1] & AP_addr[2]) ==
|
||||
(num_ip(self.remote_addr) & AP_addr[2])):
|
||||
self.pasv_data_addr = AP_addr[0]
|
||||
elif ((STA_addr[1] & STA_addr[2]) ==
|
||||
(num_ip(self.remote_addr) & STA_addr[2])):
|
||||
self.pasv_data_addr = STA_addr[0]
|
||||
else:
|
||||
self.pasv_data_addr = "0.0.0.0" # Ivalid value
|
||||
|
||||
def send_list_data(self, path, data_client, full):
|
||||
try:
|
||||
for fname in uos.listdir(path):
|
||||
data_client.sendall(self.make_description(path, fname, full))
|
||||
except: # path may be a file name or pattern
|
||||
path, pattern = self.split_path(path)
|
||||
try:
|
||||
for fname in uos.listdir(path):
|
||||
if self.fncmp(fname, pattern):
|
||||
data_client.sendall(
|
||||
self.make_description(path, fname, full))
|
||||
except:
|
||||
pass
|
||||
|
||||
def make_description(self, path, fname, full):
|
||||
global _month_name
|
||||
if full:
|
||||
stat = uos.stat(self.get_absolute_path(path, fname))
|
||||
file_permissions = ("drwxr-xr-x"
|
||||
if (stat[0] & 0o170000 == 0o040000)
|
||||
else "-rw-r--r--")
|
||||
file_size = stat[6]
|
||||
tm = localtime(stat[7])
|
||||
if tm[0] != localtime()[0]:
|
||||
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".\
|
||||
format(file_permissions, file_size,
|
||||
_month_name[tm[1]], tm[2], tm[0], fname)
|
||||
else:
|
||||
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".\
|
||||
format(file_permissions, file_size,
|
||||
_month_name[tm[1]], tm[2], tm[3], tm[4], fname)
|
||||
else:
|
||||
description = fname + "\r\n"
|
||||
return description
|
||||
|
||||
def send_file_data(self, path, data_client):
|
||||
with open(path, "r") as file:
|
||||
chunk = file.read(_CHUNK_SIZE)
|
||||
while len(chunk) > 0:
|
||||
data_client.sendall(chunk)
|
||||
chunk = file.read(_CHUNK_SIZE)
|
||||
data_client.close()
|
||||
|
||||
def save_file_data(self, path, data_client, mode):
|
||||
with open(path, mode) as file:
|
||||
chunk = data_client.recv(_CHUNK_SIZE)
|
||||
while len(chunk) > 0:
|
||||
file.write(chunk)
|
||||
chunk = data_client.recv(_CHUNK_SIZE)
|
||||
data_client.close()
|
||||
|
||||
def get_absolute_path(self, cwd, payload):
|
||||
# Just a few special cases "..", "." and ""
|
||||
# If payload start's with /, set cwd to /
|
||||
# and consider the remainder a relative path
|
||||
if payload.startswith('/'):
|
||||
cwd = "/"
|
||||
for token in payload.split("/"):
|
||||
if token == '..':
|
||||
cwd = self.split_path(cwd)[0]
|
||||
elif token != '.' and token != '':
|
||||
if cwd == '/':
|
||||
cwd += token
|
||||
else:
|
||||
cwd = cwd + '/' + token
|
||||
return cwd
|
||||
|
||||
def split_path(self, path): # instead of path.rpartition('/')
|
||||
tail = path.split('/')[-1]
|
||||
head = path[:-(len(tail) + 1)]
|
||||
return ('/' if head == '' else head, tail)
|
||||
|
||||
# compare fname against pattern. Pattern may contain
|
||||
# the wildcards ? and *.
|
||||
def fncmp(self, fname, pattern):
|
||||
pi = 0
|
||||
si = 0
|
||||
while pi < len(pattern) and si < len(fname):
|
||||
if (fname[si] == pattern[pi]) or (pattern[pi] == '?'):
|
||||
si += 1
|
||||
pi += 1
|
||||
else:
|
||||
if pattern[pi] == '*': # recurse
|
||||
if pi == len(pattern.rstrip("*?")): # only wildcards left
|
||||
return True
|
||||
while si < len(fname):
|
||||
if self.fncmp(fname[si:], pattern[pi + 1:]):
|
||||
return True
|
||||
else:
|
||||
si += 1
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
if pi == len(pattern.rstrip("*")) and si == len(fname):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def open_dataclient(self):
|
||||
if self.active: # active mode
|
||||
data_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
data_client.settimeout(_DATA_TIMEOUT)
|
||||
data_client.connect((self.act_data_addr, self.DATA_PORT))
|
||||
log_msg(1, "FTP Data connection with:", self.act_data_addr)
|
||||
else: # passive mode
|
||||
data_client, data_addr = datasocket.accept()
|
||||
log_msg(1, "FTP Data connection with:", data_addr[0])
|
||||
return data_client
|
||||
|
||||
def exec_ftp_command(self, cl):
|
||||
global datasocket
|
||||
global client_busy
|
||||
global my_ip_addr
|
||||
|
||||
try:
|
||||
gc.collect()
|
||||
|
||||
data = cl.readline().decode("utf-8").rstrip("\r\n")
|
||||
|
||||
if len(data) <= 0:
|
||||
# No data, close
|
||||
# This part is NOT CLEAN; there is still a chance that a
|
||||
# closing data connection will be signalled as closing
|
||||
# command connection
|
||||
log_msg(1, "*** No data, assume QUIT")
|
||||
close_client(cl)
|
||||
return
|
||||
|
||||
if client_busy: # check if another client is busy
|
||||
cl.sendall("400 Device busy.\r\n") # tell so the remote client
|
||||
return # and quit
|
||||
client_busy = True # now it's my turn
|
||||
|
||||
# check for log-in state may done here, like
|
||||
# if self.logged_in == False and not command in\
|
||||
# ("USER", "PASS", "QUIT"):
|
||||
# cl.sendall("530 Not logged in.\r\n")
|
||||
# return
|
||||
|
||||
command = data.split()[0].upper()
|
||||
payload = data[len(command):].lstrip() # partition is missing
|
||||
path = self.get_absolute_path(self.cwd, payload)
|
||||
log_msg(1, "Command={}, Payload={}".format(command, payload))
|
||||
|
||||
if command == "USER":
|
||||
# self.logged_in = True
|
||||
cl.sendall("230 Logged in.\r\n")
|
||||
# If you want to see a password,return
|
||||
# "331 Need password.\r\n" instead
|
||||
# If you want to reject an user, return
|
||||
# "530 Not logged in.\r\n"
|
||||
elif command == "PASS":
|
||||
# you may check here for a valid password and return
|
||||
# "530 Not logged in.\r\n" in case it's wrong
|
||||
# self.logged_in = True
|
||||
cl.sendall("230 Logged in.\r\n")
|
||||
elif command == "SYST":
|
||||
cl.sendall("215 UNIX Type: L8\r\n")
|
||||
elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore
|
||||
cl.sendall('200 OK\r\n')
|
||||
elif command == "QUIT":
|
||||
cl.sendall('221 Bye.\r\n')
|
||||
close_client(cl)
|
||||
elif command == "PWD" or command == "XPWD":
|
||||
cl.sendall('257 "{}"\r\n'.format(self.cwd))
|
||||
elif command == "CWD" or command == "XCWD":
|
||||
try:
|
||||
if (uos.stat(path)[0] & 0o170000) == 0o040000:
|
||||
self.cwd = path
|
||||
cl.sendall('250 OK\r\n')
|
||||
else:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
elif command == "PASV":
|
||||
cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format(
|
||||
self.pasv_data_addr.replace('.', ','),
|
||||
_DATA_PORT >> 8, _DATA_PORT % 256))
|
||||
self.active = False
|
||||
elif command == "PORT":
|
||||
items = payload.split(",")
|
||||
if len(items) >= 6:
|
||||
self.act_data_addr = '.'.join(items[:4])
|
||||
if self.act_data_addr == "127.0.1.1":
|
||||
# replace by command session addr
|
||||
self.act_data_addr = self.remote_addr
|
||||
self.DATA_PORT = int(items[4]) * 256 + int(items[5])
|
||||
cl.sendall('200 OK\r\n')
|
||||
self.active = True
|
||||
else:
|
||||
cl.sendall('504 Fail\r\n')
|
||||
elif command == "LIST" or command == "NLST":
|
||||
if payload.startswith("-"):
|
||||
option = payload.split()[0].lower()
|
||||
path = self.get_absolute_path(
|
||||
self.cwd, payload[len(option):].lstrip())
|
||||
else:
|
||||
option = ""
|
||||
try:
|
||||
data_client = self.open_dataclient()
|
||||
cl.sendall("150 Directory listing:\r\n")
|
||||
self.send_list_data(path, data_client,
|
||||
command == "LIST" or 'l' in option)
|
||||
cl.sendall("226 Done.\r\n")
|
||||
data_client.close()
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
if data_client is not None:
|
||||
data_client.close()
|
||||
elif command == "RETR":
|
||||
try:
|
||||
data_client = self.open_dataclient()
|
||||
cl.sendall("150 Opened data connection.\r\n")
|
||||
self.send_file_data(path, data_client)
|
||||
# if the next statement is reached,
|
||||
# the data_client was closed.
|
||||
data_client = None
|
||||
cl.sendall("226 Done.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
if data_client is not None:
|
||||
data_client.close()
|
||||
elif command == "STOR" or command == "APPE":
|
||||
try:
|
||||
data_client = self.open_dataclient()
|
||||
cl.sendall("150 Opened data connection.\r\n")
|
||||
self.save_file_data(path, data_client,
|
||||
"w" if command == "STOR" else "a")
|
||||
# if the next statement is reached,
|
||||
# the data_client was closed.
|
||||
data_client = None
|
||||
cl.sendall("226 Done.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
if data_client is not None:
|
||||
data_client.close()
|
||||
elif command == "SIZE":
|
||||
try:
|
||||
cl.sendall('213 {}\r\n'.format(uos.stat(path)[6]))
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
elif command == "STAT":
|
||||
if payload == "":
|
||||
cl.sendall("211-Connected to ({})\r\n"
|
||||
" Data address ({})\r\n"
|
||||
" TYPE: Binary STRU: File MODE: Stream\r\n"
|
||||
" Session timeout {}\r\n"
|
||||
"211 Client count is {}\r\n".format(
|
||||
self.remote_addr, self.pasv_data_addr,
|
||||
_COMMAND_TIMEOUT, len(client_list)))
|
||||
else:
|
||||
cl.sendall("213-Directory listing:\r\n")
|
||||
self.send_list_data(path, cl, True)
|
||||
cl.sendall("213 Done.\r\n")
|
||||
elif command == "DELE":
|
||||
try:
|
||||
uos.remove(path)
|
||||
cl.sendall('250 OK\r\n')
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
elif command == "RNFR":
|
||||
try:
|
||||
# just test if the name exists, exception if not
|
||||
uos.stat(path)
|
||||
self.fromname = path
|
||||
cl.sendall("350 Rename from\r\n")
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
elif command == "RNTO":
|
||||
try:
|
||||
uos.rename(self.fromname, path)
|
||||
cl.sendall('250 OK\r\n')
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
self.fromname = None
|
||||
elif command == "CDUP" or command == "XCUP":
|
||||
self.cwd = self.get_absolute_path(self.cwd, "..")
|
||||
cl.sendall('250 OK\r\n')
|
||||
elif command == "RMD" or command == "XRMD":
|
||||
try:
|
||||
uos.rmdir(path)
|
||||
cl.sendall('250 OK\r\n')
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
elif command == "MKD" or command == "XMKD":
|
||||
try:
|
||||
uos.mkdir(path)
|
||||
cl.sendall('250 OK\r\n')
|
||||
except:
|
||||
cl.sendall('550 Fail\r\n')
|
||||
else:
|
||||
cl.sendall("502 Unsupported command.\r\n")
|
||||
# log_msg(2,
|
||||
# "Unsupported command {} with payload {}".format(command,
|
||||
# payload))
|
||||
# handle unexpected errors
|
||||
except Exception as err:
|
||||
log_msg(1, "Exception in exec_ftp_command: {}".format(err))
|
||||
# tidy up before leaving
|
||||
client_busy = False
|
||||
|
||||
|
||||
def log_msg(level, *args):
|
||||
global verbose_l
|
||||
if verbose_l >= level:
|
||||
print(*args)
|
||||
|
||||
|
||||
# close client and remove it from the list
|
||||
def close_client(cl):
|
||||
cl.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
|
||||
cl.close()
|
||||
for i, client in enumerate(client_list):
|
||||
if client.command_client == cl:
|
||||
del client_list[i]
|
||||
break
|
||||
|
||||
|
||||
def accept_ftp_connect(ftpsocket):
|
||||
# Accept new calls for the server
|
||||
try:
|
||||
client_list.append(FTP_client(ftpsocket))
|
||||
except:
|
||||
log_msg(1, "Attempt to connect failed")
|
||||
# try at least to reject
|
||||
try:
|
||||
temp_client, temp_addr = ftpsocket.accept()
|
||||
temp_client.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def num_ip(ip):
|
||||
items = ip.split(".")
|
||||
return (int(items[0]) << 24 | int(items[1]) << 16 |
|
||||
int(items[2]) << 8 | int(items[3]))
|
||||
|
||||
|
||||
def stop():
|
||||
global ftpsocket, datasocket
|
||||
global client_list
|
||||
global client_busy
|
||||
|
||||
for client in client_list:
|
||||
client.command_client.setsockopt(socket.SOL_SOCKET,
|
||||
_SO_REGISTER_HANDLER, None)
|
||||
client.command_client.close()
|
||||
del client_list
|
||||
client_list = []
|
||||
client_busy = False
|
||||
if ftpsocket is not None:
|
||||
ftpsocket.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
|
||||
ftpsocket.close()
|
||||
if datasocket is not None:
|
||||
datasocket.close()
|
||||
|
||||
|
||||
# start listening for ftp connections on port 21
|
||||
def start(port=21, verbose=0, splash=True):
|
||||
global ftpsocket, datasocket
|
||||
global verbose_l
|
||||
global client_list
|
||||
global client_busy
|
||||
global AP_addr, STA_addr
|
||||
|
||||
alloc_emergency_exception_buf(100)
|
||||
verbose_l = verbose
|
||||
client_list = []
|
||||
client_busy = False
|
||||
|
||||
ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
ftpsocket.bind(('0.0.0.0', port))
|
||||
datasocket.bind(('0.0.0.0', _DATA_PORT))
|
||||
|
||||
ftpsocket.listen(0)
|
||||
datasocket.listen(0)
|
||||
|
||||
datasocket.settimeout(10)
|
||||
ftpsocket.setsockopt(socket.SOL_SOCKET,
|
||||
_SO_REGISTER_HANDLER, accept_ftp_connect)
|
||||
|
||||
wlan = network.WLAN(network.AP_IF)
|
||||
if wlan.active():
|
||||
ifconfig = wlan.ifconfig()
|
||||
# save IP address string and numerical values of IP adress and netmask
|
||||
AP_addr = (ifconfig[0], num_ip(ifconfig[0]), num_ip(ifconfig[1]))
|
||||
if splash:
|
||||
print("FTP server started on {}:{}".format(ifconfig[0], port))
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
if wlan.active():
|
||||
ifconfig = wlan.ifconfig()
|
||||
# save IP address string and numerical values of IP adress and netmask
|
||||
STA_addr = (ifconfig[0], num_ip(ifconfig[0]), num_ip(ifconfig[1]))
|
||||
if splash:
|
||||
print("FTP server started on {}:{}".format(ifconfig[0], port))
|
||||
|
||||
|
||||
def restart(port=21, verbose=0, splash=True):
|
||||
stop()
|
||||
sleep_ms(200)
|
||||
start(port, verbose, splash)
|
||||
|
||||
|
||||
start(splash=True)
|
||||
@ -1,6 +1,9 @@
|
||||
// Options to control how MicroPython is built for this port,
|
||||
// overriding defaults in py/mpconfig.h.
|
||||
|
||||
// Board-specific definitions
|
||||
#include "mpconfigboard.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <alloca.h>
|
||||
#include "rom/ets_sys.h"
|
||||
@ -96,6 +99,7 @@
|
||||
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
|
||||
#define MICROPY_PY_MATH_ISCLOSE (1)
|
||||
#define MICROPY_PY_CMATH (1)
|
||||
#define MICROPY_PY_GC (1)
|
||||
#define MICROPY_PY_IO (1)
|
||||
@ -290,7 +294,12 @@ typedef long mp_off_t;
|
||||
#include <sys/types.h>
|
||||
|
||||
// board specifics
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "ESP32 module"
|
||||
#define MICROPY_HW_MCU_NAME "ESP32"
|
||||
#define MICROPY_PY_SYS_PLATFORM "esp32"
|
||||
|
||||
#ifndef MICROPY_HW_ENABLE_MDNS_QUERIES
|
||||
#define MICROPY_HW_ENABLE_MDNS_QUERIES (1)
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_HW_ENABLE_MDNS_RESPONDER
|
||||
#define MICROPY_HW_ENABLE_MDNS_RESPONDER (1)
|
||||
#endif
|
||||
|
||||
@ -205,6 +205,7 @@ STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&lan_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
|
||||
};
|
||||
|
||||
|
||||
@ -129,29 +129,26 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) {
|
||||
if (self->pcb == NULL) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "init failed");
|
||||
}
|
||||
pppapi_set_default(self->pcb);
|
||||
ppp_set_usepeerdns(self->pcb, 1);
|
||||
pppapi_connect(self->pcb, 0);
|
||||
|
||||
xTaskCreatePinnedToCore(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle, MP_TASK_COREID);
|
||||
self->active = true;
|
||||
} else {
|
||||
if (!self->active) {
|
||||
return mp_const_false;
|
||||
}
|
||||
|
||||
// Wait for PPPERR_USER, with timeout
|
||||
pppapi_close(self->pcb, 0);
|
||||
uint32_t t0 = mp_hal_ticks_ms();
|
||||
while (!self->clean_close && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) {
|
||||
mp_hal_delay_ms(10);
|
||||
}
|
||||
if (self->client_task_handle != NULL) { // is connecting or connected?
|
||||
// Wait for PPPERR_USER, with timeout
|
||||
pppapi_close(self->pcb, 0);
|
||||
uint32_t t0 = mp_hal_ticks_ms();
|
||||
while (!self->clean_close && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) {
|
||||
mp_hal_delay_ms(10);
|
||||
}
|
||||
|
||||
// Shutdown task
|
||||
xTaskNotifyGive(self->client_task_handle);
|
||||
t0 = mp_hal_ticks_ms();
|
||||
while (self->client_task_handle != NULL && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) {
|
||||
mp_hal_delay_ms(10);
|
||||
// Shutdown task
|
||||
xTaskNotifyGive(self->client_task_handle);
|
||||
t0 = mp_hal_ticks_ms();
|
||||
while (self->client_task_handle != NULL && mp_hal_ticks_ms() - t0 < PPP_CLOSE_TIMEOUT_MS) {
|
||||
mp_hal_delay_ms(10);
|
||||
}
|
||||
}
|
||||
|
||||
// Release PPP
|
||||
@ -166,6 +163,59 @@ STATIC mp_obj_t ppp_active(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ppp_active_obj, 1, 2, ppp_active);
|
||||
|
||||
STATIC mp_obj_t ppp_connect_py(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
enum { ARG_authmode, ARG_username, ARG_password };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_authmode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PPPAUTHTYPE_NONE} },
|
||||
{ MP_QSTR_username, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
{ MP_QSTR_password, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
};
|
||||
|
||||
mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args);
|
||||
|
||||
ppp_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
|
||||
if (!self->active) {
|
||||
mp_raise_msg(&mp_type_OSError, "must be active");
|
||||
}
|
||||
|
||||
if (self->client_task_handle != NULL) {
|
||||
mp_raise_OSError(MP_EALREADY);
|
||||
}
|
||||
|
||||
switch (parsed_args[ARG_authmode].u_int) {
|
||||
case PPPAUTHTYPE_NONE:
|
||||
case PPPAUTHTYPE_PAP:
|
||||
case PPPAUTHTYPE_CHAP:
|
||||
break;
|
||||
default:
|
||||
mp_raise_msg(&mp_type_ValueError, "invalid auth");
|
||||
}
|
||||
|
||||
if (parsed_args[ARG_authmode].u_int != PPPAUTHTYPE_NONE) {
|
||||
const char* username_str = mp_obj_str_get_str(parsed_args[ARG_username].u_obj);
|
||||
const char* password_str = mp_obj_str_get_str(parsed_args[ARG_password].u_obj);
|
||||
pppapi_set_auth(self->pcb, parsed_args[ARG_authmode].u_int, username_str, password_str);
|
||||
}
|
||||
if (pppapi_set_default(self->pcb) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, "set default failed");
|
||||
}
|
||||
|
||||
ppp_set_usepeerdns(self->pcb, true);
|
||||
|
||||
if (pppapi_connect(self->pcb, 0) != ESP_OK) {
|
||||
mp_raise_msg(&mp_type_OSError, "connect failed");
|
||||
}
|
||||
|
||||
if (xTaskCreatePinnedToCore(pppos_client_task, "ppp", 2048, self, 1, (TaskHandle_t*)&self->client_task_handle, MP_TASK_COREID) != pdPASS) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, "failed to create worker task");
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(ppp_connect_obj, 1, ppp_connect_py);
|
||||
|
||||
STATIC mp_obj_t ppp_delete(mp_obj_t self_in) {
|
||||
ppp_if_obj_t* self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_obj_t args[] = {self, mp_const_false};
|
||||
@ -216,10 +266,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(ppp_isconnected_obj, ppp_isconnected);
|
||||
|
||||
STATIC const mp_rom_map_elem_t ppp_if_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&ppp_active_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&ppp_connect_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&ppp_isconnected_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&ppp_status_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&ppp_ifconfig_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ppp_delete_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_NONE), MP_ROM_INT(PPPAUTHTYPE_NONE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_PAP), MP_ROM_INT(PPPAUTHTYPE_PAP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AUTH_CHAP), MP_ROM_INT(PPPAUTHTYPE_CHAP) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(ppp_if_locals_dict, ppp_if_locals_dict_table);
|
||||
|
||||
|
||||
6
ports/esp32/partitions-2MiB.csv
Normal file
6
ports/esp32/partitions-2MiB.csv
Normal file
@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x110000,
|
||||
vfs, data, fat, 0x120000, 0xA0000,
|
||||
|
@ -2,4 +2,5 @@
|
||||
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x190000,
|
||||
factory, app, factory, 0x10000, 0x200000,
|
||||
vfs, data, fat, 0x210000, 0x1f0000,
|
||||
|
||||
|
@ -110,6 +110,7 @@ SECTIONS
|
||||
*py/obj*.o*(.literal* .text*)
|
||||
*py/opmethods.o*(.literal* .text*)
|
||||
*py/parse*.o*(.literal* .text*)
|
||||
*py/profile*.o*(.literal* .text*)
|
||||
*py/qstr.o*(.literal* .text*)
|
||||
*py/repl.o*(.literal* .text*)
|
||||
*py/runtime.o*(.literal* .text*)
|
||||
|
||||
@ -28,54 +28,71 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
const mp_obj_type_t pyb_adc_type;
|
||||
|
||||
typedef struct _pyb_adc_obj_t {
|
||||
typedef struct _machine_adc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
bool isvdd;
|
||||
} pyb_adc_obj_t;
|
||||
} machine_adc_obj_t;
|
||||
|
||||
STATIC pyb_adc_obj_t pyb_adc_vdd3 = {{&pyb_adc_type}, true};
|
||||
STATIC pyb_adc_obj_t pyb_adc_adc = {{&pyb_adc_type}, false};
|
||||
extern const mp_obj_type_t machine_adc_type;
|
||||
|
||||
STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw,
|
||||
const mp_obj_t *args) {
|
||||
STATIC machine_adc_obj_t machine_adc_vdd3 = {{&machine_adc_type}, true};
|
||||
STATIC machine_adc_obj_t machine_adc_adc = {{&machine_adc_type}, false};
|
||||
|
||||
STATIC uint16_t adc_read(machine_adc_obj_t *self) {
|
||||
if (self->isvdd) {
|
||||
return system_get_vdd33();
|
||||
} else {
|
||||
return system_adc_read();
|
||||
}
|
||||
}
|
||||
void machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "ADC(%u)", self->isvdd);
|
||||
}
|
||||
|
||||
mp_obj_t machine_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
mp_int_t chn = mp_obj_get_int(args[0]);
|
||||
|
||||
switch (chn) {
|
||||
case 0:
|
||||
return &pyb_adc_adc;
|
||||
return &machine_adc_adc;
|
||||
case 1:
|
||||
return &pyb_adc_vdd3;
|
||||
return &machine_adc_vdd3;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
|
||||
"not a valid ADC Channel: %d", chn));
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ADC(%d) doesn't exist", chn));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) {
|
||||
pyb_adc_obj_t *adc = self_in;
|
||||
|
||||
if (adc->isvdd) {
|
||||
return mp_obj_new_int(system_get_vdd33());
|
||||
} else {
|
||||
return mp_obj_new_int(system_adc_read());
|
||||
}
|
||||
// read_u16()
|
||||
STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
uint32_t value = adc_read(self);
|
||||
return MP_OBJ_NEW_SMALL_INT(value * 65535 / 1024);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_adc_read_obj, pyb_adc_read);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_adc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_adc_read_obj) }
|
||||
// Legacy method
|
||||
STATIC mp_obj_t machine_adc_read(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_int(adc_read(self));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_obj, machine_adc_read);
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&machine_adc_read_obj) }
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_adc_locals_dict, pyb_adc_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_adc_type = {
|
||||
const mp_obj_type_t machine_adc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.make_new = pyb_adc_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_adc_locals_dict,
|
||||
.print = machine_adc_print,
|
||||
.make_new = machine_adc_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&machine_adc_locals_dict,
|
||||
};
|
||||
|
||||
@ -29,11 +29,13 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "modmachine.h"
|
||||
|
||||
// UartDev is defined and initialized in rom code.
|
||||
@ -63,14 +65,14 @@ STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_k
|
||||
}
|
||||
|
||||
STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_rxbuf, ARG_timeout, ARG_timeout_char };
|
||||
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_tx, ARG_rx, ARG_rxbuf, ARG_timeout, ARG_timeout_char };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} },
|
||||
//{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
//{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
@ -128,6 +130,22 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o
|
||||
}
|
||||
}
|
||||
|
||||
// set tx/rx pins
|
||||
mp_hal_pin_obj_t tx = 1, rx = 3;
|
||||
if (args[ARG_tx].u_obj != MP_OBJ_NULL) {
|
||||
tx = mp_hal_get_pin_obj(args[ARG_tx].u_obj);
|
||||
}
|
||||
if (args[ARG_rx].u_obj != MP_OBJ_NULL) {
|
||||
rx = mp_hal_get_pin_obj(args[ARG_rx].u_obj);
|
||||
}
|
||||
if (tx == 1 && rx == 3) {
|
||||
system_uart_de_swap();
|
||||
} else if (tx == 15 && rx == 13) {
|
||||
system_uart_swap();
|
||||
} else {
|
||||
mp_raise_ValueError("invalid tx/rx");
|
||||
}
|
||||
|
||||
// set stop bits
|
||||
switch (args[ARG_stop].u_int) {
|
||||
case 0:
|
||||
|
||||
@ -410,7 +410,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
|
||||
#if MICROPY_PY_MACHINE_I2C
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
extern const mp_obj_type_t pyb_pin_type;
|
||||
extern const mp_obj_type_t pyb_pwm_type;
|
||||
extern const mp_obj_type_t pyb_adc_type;
|
||||
extern const mp_obj_type_t machine_adc_type;
|
||||
extern const mp_obj_type_t pyb_rtc_type;
|
||||
extern const mp_obj_type_t pyb_uart_type;
|
||||
extern const mp_obj_type_t pyb_i2c_type;
|
||||
|
||||
@ -46,7 +46,7 @@ int do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
@ -73,6 +73,7 @@
|
||||
#define MICROPY_PY_COLLECTIONS (1)
|
||||
#define MICROPY_PY_MATH (1)
|
||||
#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
|
||||
#define MICROPY_PY_MATH_ISCLOSE (1)
|
||||
#define MICROPY_PY_CMATH (1)
|
||||
#define MICROPY_PY_IO (1)
|
||||
#define MICROPY_PY_STRUCT (1)
|
||||
|
||||
@ -16,7 +16,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
5
ports/nrf/.gitignore
vendored
5
ports/nrf/.gitignore
vendored
@ -1,8 +1,3 @@
|
||||
# Nordic files
|
||||
#####################
|
||||
drivers/bluetooth/s1*/
|
||||
|
||||
# Build files
|
||||
#####################
|
||||
build-*/
|
||||
|
||||
|
||||
@ -254,7 +254,7 @@ OBJ += $(BUILD)/pins_gen.o
|
||||
$(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os
|
||||
$(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os
|
||||
|
||||
.PHONY: all flash sd binary hex
|
||||
.PHONY: all flash deploy sd binary hex
|
||||
|
||||
all: binary hex
|
||||
|
||||
@ -276,7 +276,7 @@ FLASHER ?=
|
||||
|
||||
ifeq ($(FLASHER),)
|
||||
|
||||
flash: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
deploy: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
nrfjprog --program $< --sectorerase -f $(MCU_VARIANT)
|
||||
nrfjprog --reset -f $(MCU_VARIANT)
|
||||
|
||||
@ -288,7 +288,7 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
|
||||
else ifeq ($(FLASHER), pyocd)
|
||||
|
||||
flash: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
deploy: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
pyocd-flashtool -t $(MCU_VARIANT) $<
|
||||
|
||||
sd: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
@ -298,14 +298,47 @@ sd: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
|
||||
else ifeq ($(FLASHER), idap)
|
||||
|
||||
flash: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
deploy: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
IDAPnRFPRog $<
|
||||
|
||||
sd: $(BUILD)/$(OUTPUT_FILENAME).hex
|
||||
IDAPnRFPRog $(SOFTDEV_HEX) $<
|
||||
|
||||
else ifeq ($(FLASHER), bmp)
|
||||
|
||||
BMP_PORT ?= /dev/ttyACM0
|
||||
|
||||
deploy: $(BUILD)/$(OUTPUT_FILENAME).elf
|
||||
$(Q)$(GDB) \
|
||||
-ex 'target extended-remote $(BMP_PORT)' \
|
||||
-ex 'monitor tpwr enable' \
|
||||
-ex 'monitor swdp_scan' \
|
||||
-ex 'attach 1' \
|
||||
-ex 'set mem inaccessible-by-default off' \
|
||||
-ex 'load' \
|
||||
-ex 'kill' \
|
||||
-ex 'quit' \
|
||||
$<
|
||||
|
||||
sd: $(BUILD)/$(OUTPUT_FILENAME).elf
|
||||
$(Q)$(GDB) \
|
||||
-ex 'target extended-remote $(BMP_PORT)' \
|
||||
-ex 'monitor tpwr enable' \
|
||||
-ex 'monitor swdp_scan' \
|
||||
-ex 'attach 1' \
|
||||
-ex 'set mem inaccessible-by-default off' \
|
||||
-ex 'monitor erase_mass' \
|
||||
-ex 'load' \
|
||||
-ex 'file $(SOFTDEV_HEX)' \
|
||||
-ex 'load' \
|
||||
-ex 'kill' \
|
||||
-ex 'quit' \
|
||||
$<
|
||||
|
||||
endif
|
||||
|
||||
flash: deploy
|
||||
|
||||
$(BUILD)/$(OUTPUT_FILENAME).elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
|
||||
|
||||
@ -38,6 +38,7 @@ This is a port of MicroPython to the Nordic Semiconductor nRF series of chips.
|
||||
* [BLUEIO-TAG-EVIM BLYST Nano Sensor board](https://www.crowdsupply.com/i-syst/blyst-nano)
|
||||
* nRF52840
|
||||
* [PCA10056](http://www.nordicsemi.com/eng/Products/nRF52840-Preview-DK)
|
||||
* [Particle Xenon](https://docs.particle.io/xenon/)
|
||||
|
||||
## Compile and Flash
|
||||
|
||||
@ -126,6 +127,7 @@ ibk_blyst_nano | s132 | Peripheral and Central | [IDAP]
|
||||
idk_blyst_nano | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets)
|
||||
blueio_tag_evim | s132 | Peripheral and Central | [IDAP](#idap-midap-link-targets)
|
||||
pca10056 | s140 | Peripheral and Central | [Segger](#segger-targets)
|
||||
particle_xenon | s140 | Peripheral and Central | [Black Magic Probe](#black-magic-probe-targets)
|
||||
|
||||
## IDAP-M/IDAP-Link Targets
|
||||
|
||||
@ -153,6 +155,14 @@ Install the necessary tools to flash and debug using OpenOCD:
|
||||
sudo apt-get install openocd
|
||||
sudo pip install pyOCD
|
||||
|
||||
## Black Magic Probe Targets
|
||||
|
||||
This requires no further dependencies other than `arm-none-eabi-gdb`.
|
||||
|
||||
`make deploy` will use gdb to load and run new firmware. See
|
||||
[this guide](https://github.com/blacksphere/blackmagic/wiki/Useful-GDB-commands)
|
||||
for more tips about using the BMP with GDB.
|
||||
|
||||
## Bluetooth LE REPL
|
||||
|
||||
The port also implements a BLE REPL driver. This feature is disabled by default, as it will deactivate the UART REPL when activated. As some of the nRF devices only have one UART, using the BLE REPL free's the UART instance such that it can be used as a general UART peripheral not bound to REPL.
|
||||
|
||||
@ -93,6 +93,7 @@ class Pin(object):
|
||||
self.adc_num = 0
|
||||
self.adc_channel = 0
|
||||
self.board_pin = False
|
||||
self.board_index = None
|
||||
|
||||
def cpu_pin_name(self):
|
||||
return '{:s}{:d}'.format("P", self.pin)
|
||||
@ -103,6 +104,9 @@ class Pin(object):
|
||||
def set_is_board_pin(self):
|
||||
self.board_pin = True
|
||||
|
||||
def set_board_index(self, index):
|
||||
self.board_index = index
|
||||
|
||||
def parse_adc(self, adc_str):
|
||||
if (adc_str[:3] != 'ADC'):
|
||||
return
|
||||
@ -233,20 +237,24 @@ class Pins(object):
|
||||
|
||||
def print_named(self, label, named_pins):
|
||||
print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
|
||||
index = 0
|
||||
for named_pin in named_pins:
|
||||
pin = named_pin.pin()
|
||||
if pin.is_board_pin():
|
||||
print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&machine_pin_obj[{:d}]) }},'.format(named_pin.name(), index))
|
||||
index += 1
|
||||
print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&machine_board_pin_obj[{:d}]) }},'.format(named_pin.name(), pin.board_index))
|
||||
print('};')
|
||||
print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
|
||||
|
||||
def print_const_table(self):
|
||||
num_board_pins = 0
|
||||
for named_pin in self.cpu_pins:
|
||||
pin = named_pin.pin()
|
||||
if pin.is_board_pin():
|
||||
pin.set_board_index(num_board_pins)
|
||||
num_board_pins += 1
|
||||
print('')
|
||||
print('const uint8_t machine_pin_num_of_pins = {:d};'.format(len(self.board_pins)))
|
||||
print('const uint8_t machine_pin_num_of_board_pins = {:d};'.format(num_board_pins))
|
||||
print('')
|
||||
print('const pin_obj_t machine_pin_obj[{:d}] = {{'.format(len(self.board_pins)))
|
||||
print('const pin_obj_t machine_board_pin_obj[{:d}] = {{'.format(num_board_pins))
|
||||
for named_pin in self.cpu_pins:
|
||||
pin = named_pin.pin()
|
||||
if pin.is_board_pin():
|
||||
|
||||
@ -256,15 +256,15 @@ static const uint16_t render_timings[] =
|
||||
// The scale is (approximately) exponential,
|
||||
// each step is approx x1.9 greater than the previous.
|
||||
{ 0, // Bright, Ticks Duration, Relative power
|
||||
2, // 1, 2, 32µs, inf
|
||||
2, // 2, 4, 64µs, 200%
|
||||
4, // 3, 8, 128µs, 200%
|
||||
7, // 4, 15, 240µs, 187%
|
||||
13, // 5, 28, 448µs, 187%
|
||||
25, // 6, 53, 848µs, 189%
|
||||
49, // 7, 102, 1632µs, 192%
|
||||
97, // 8, 199, 3184µs, 195%
|
||||
// Always on 9, 375, 6000µs, 188%
|
||||
2, // 1, 2, 32us, inf
|
||||
2, // 2, 4, 64us, 200%
|
||||
4, // 3, 8, 128us, 200%
|
||||
7, // 4, 15, 240us, 187%
|
||||
13, // 5, 28, 448us, 187%
|
||||
25, // 6, 53, 848us, 189%
|
||||
49, // 7, 102, 1632us, 192%
|
||||
97, // 8, 199, 3184us, 195%
|
||||
// Always on 9, 375, 6000us, 188%
|
||||
};
|
||||
|
||||
#define DISPLAY_TICKER_SLOT 1
|
||||
@ -281,7 +281,7 @@ static int32_t callback(void) {
|
||||
return -1;
|
||||
}
|
||||
display->previous_brightness = brightness;
|
||||
// Return interval (in 16µs ticks) until next callback
|
||||
// Return interval (in 16us ticks) until next callback
|
||||
return render_timings[brightness];
|
||||
}
|
||||
|
||||
|
||||
@ -962,7 +962,7 @@ const mp_obj_type_t microbit_facade_iterator_type = {
|
||||
};
|
||||
|
||||
mp_obj_t microbit_facade_iterator(mp_obj_t iterable_in, mp_obj_iter_buf_t *iter_buf) {
|
||||
(void)iter_buf;
|
||||
(void)iter_buf;
|
||||
facade_iterator_t *result = m_new_obj(facade_iterator_t);
|
||||
string_image_facade_t *iterable = (string_image_facade_t *)iterable_in;
|
||||
result->base.type = µbit_facade_iterator_type;
|
||||
|
||||
70
ports/nrf/boards/particle_xenon/mpconfigboard.h
Normal file
70
ports/nrf/boards/particle_xenon/mpconfigboard.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 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.
|
||||
*/
|
||||
|
||||
#define MICROPY_HW_BOARD_NAME "XENON"
|
||||
#define MICROPY_HW_MCU_NAME "NRF52840"
|
||||
#define MICROPY_PY_SYS_PLATFORM "PARTICLE-XENON"
|
||||
|
||||
#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_PY_RANDOM_HW_RNG (1)
|
||||
|
||||
#define MICROPY_HW_HAS_LED (1)
|
||||
#define MICROPY_HW_LED_TRICOLOR (1)
|
||||
#define MICROPY_HW_LED_PULLUP (1)
|
||||
|
||||
#define MICROPY_HW_LED_RED (13) // LED1
|
||||
#define MICROPY_HW_LED_GREEN (14) // LED2
|
||||
#define MICROPY_HW_LED_BLUE (15) // LED3
|
||||
|
||||
// UART config
|
||||
#define MICROPY_HW_UART1_RX (8)
|
||||
#define MICROPY_HW_UART1_TX (6)
|
||||
#define MICROPY_HW_UART1_CTS (32+2)
|
||||
#define MICROPY_HW_UART1_RTS (32+1)
|
||||
#define MICROPY_HW_UART1_HWFC (0)
|
||||
|
||||
// SPI0 config
|
||||
#define MICROPY_HW_SPI0_NAME "SPI0"
|
||||
|
||||
#define MICROPY_HW_SPI0_SCK (32+15)
|
||||
#define MICROPY_HW_SPI0_MOSI (32+13)
|
||||
#define MICROPY_HW_SPI0_MISO (32+14)
|
||||
|
||||
#define MICROPY_HW_PWM0_NAME "PWM0"
|
||||
#define MICROPY_HW_PWM1_NAME "PWM1"
|
||||
#define MICROPY_HW_PWM2_NAME "PWM2"
|
||||
#if 0
|
||||
#define MICROPY_HW_PWM3_NAME "PWM3"
|
||||
#endif
|
||||
|
||||
#define HELP_TEXT_BOARD_LED "1,2,3"
|
||||
7
ports/nrf/boards/particle_xenon/mpconfigboard.mk
Normal file
7
ports/nrf/boards/particle_xenon/mpconfigboard.mk
Normal file
@ -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
|
||||
38
ports/nrf/boards/particle_xenon/pins.csv
Normal file
38
ports/nrf/boards/particle_xenon/pins.csv
Normal file
@ -0,0 +1,38 @@
|
||||
LED1,P13
|
||||
LED2,P14
|
||||
LED3,P15
|
||||
A0,P3,ADC0_IN1
|
||||
A1,P4,ADC0_IN2
|
||||
A2,P28,ADC0_IN4
|
||||
A3,P29,ADC0_IN5
|
||||
A4,P30,ADC0_IN6
|
||||
A5,P31,ADC0_IN7
|
||||
SPI_SS,P31
|
||||
SPI_SCK,P47
|
||||
SPI_MOSI,P45
|
||||
SPI_MISO,P46
|
||||
SPI1_SCK,P33
|
||||
SPI1_MOSI,P34
|
||||
SPI1_MISO,P40
|
||||
UART1_RX,P8
|
||||
UART1_TX,P6
|
||||
UART2_RX,P42
|
||||
UART2_TX,P40
|
||||
SDA,P26
|
||||
SCL,P27
|
||||
SDA1,P33
|
||||
SCL1,P34
|
||||
D0,P26
|
||||
D1,P27
|
||||
D2,P33
|
||||
D3,P34
|
||||
D4,P40
|
||||
D5,P42
|
||||
D6,P43
|
||||
D7,P44
|
||||
D8,P35
|
||||
D9,P6
|
||||
D10,P8
|
||||
D11,P46
|
||||
D12,P45
|
||||
D13,P47
|
||||
|
@ -418,7 +418,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
|
||||
p_adv_params->p_device_name,
|
||||
p_adv_params->device_name_len) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
|
||||
"Can not apply device name in the stack."));
|
||||
"Can not apply device name in the stack."));
|
||||
}
|
||||
|
||||
BLE_DRIVER_LOG("Device name applied\n");
|
||||
|
||||
@ -190,7 +190,7 @@ void ble_uart_init0(void) {
|
||||
ble_uart_char_tx.service_handle = ble_uart_service.handle;
|
||||
bool retval = ble_drv_characteristic_add(&ble_uart_char_tx);
|
||||
if (retval) {
|
||||
ble_uart_char_tx.p_service = &ble_uart_service;
|
||||
ble_uart_char_tx.p_service = &ble_uart_service;
|
||||
}
|
||||
mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_tx));
|
||||
|
||||
@ -198,7 +198,7 @@ void ble_uart_init0(void) {
|
||||
ble_uart_char_rx.service_handle = ble_uart_service.handle;
|
||||
retval = ble_drv_characteristic_add(&ble_uart_char_rx);
|
||||
if (retval) {
|
||||
ble_uart_char_rx.p_service = &ble_uart_service;
|
||||
ble_uart_char_rx.p_service = &ble_uart_service;
|
||||
}
|
||||
mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_rx));
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
#define __MICROPY_INCLUDED_LIB_TICKER_H__
|
||||
|
||||
/*************************************
|
||||
* 62.5kHz (16µs cycle time) ticker.
|
||||
* 62.5kHz (16us cycle time) ticker.
|
||||
************************************/
|
||||
|
||||
#include "nrf.h"
|
||||
|
||||
@ -28,6 +28,6 @@
|
||||
#include "lib/oofatfs/ff.h"
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
// TODO: Implement this function. For now, fake it.
|
||||
// TODO: Implement this function. For now, fake it.
|
||||
return ((2016 - 1980) << 25) | ((12) << 21) | ((4) << 16) | ((00) << 11) | ((18) << 5) | (23 / 2);
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t pn = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_obj_t module_fun = mp_compile(&pn, source_name, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
@ -185,8 +185,8 @@ pin_init0();
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd_slash_lib));
|
||||
|
||||
// use SD card as current directory
|
||||
f_chdrive("/sd");
|
||||
// use SD card as current directory
|
||||
f_chdrive("/sd");
|
||||
}
|
||||
no_mem_for_sd:;
|
||||
}
|
||||
@ -293,18 +293,17 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
#if defined(NRF52_SERIES)
|
||||
static volatile uint32_t reg;
|
||||
static volatile uint32_t reg2;
|
||||
static volatile uint32_t bfar;
|
||||
reg = SCB->HFSR;
|
||||
reg2 = SCB->CFSR;
|
||||
bfar = SCB->BFAR;
|
||||
for (int i = 0; i < 0; i++)
|
||||
{
|
||||
(void)reg;
|
||||
(void)reg2;
|
||||
(void)bfar;
|
||||
}
|
||||
static volatile uint32_t reg;
|
||||
static volatile uint32_t reg2;
|
||||
static volatile uint32_t bfar;
|
||||
reg = SCB->HFSR;
|
||||
reg2 = SCB->CFSR;
|
||||
bfar = SCB->BFAR;
|
||||
for (int i = 0; i < 0; i++) {
|
||||
(void)reg;
|
||||
(void)reg2;
|
||||
(void)bfar;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -91,10 +91,19 @@ void adc_init0(void) {
|
||||
}
|
||||
|
||||
STATIC int adc_find(mp_obj_t id) {
|
||||
// given an integer id
|
||||
int adc_id = mp_obj_get_int(id);
|
||||
|
||||
int adc_idx = adc_id;
|
||||
int adc_idx;
|
||||
if (mp_obj_is_int(id)) {
|
||||
// Given an integer id
|
||||
adc_idx = mp_obj_get_int(id);
|
||||
} else {
|
||||
// Assume it's a pin-compatible object and convert it to an ADC channel number
|
||||
mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(id);
|
||||
if (pin->adc_num & PIN_ADC1) {
|
||||
adc_idx = pin->adc_channel;
|
||||
} else {
|
||||
mp_raise_ValueError("invalid Pin for ADC");
|
||||
}
|
||||
}
|
||||
|
||||
if (adc_idx >= 0 && adc_idx < MP_ARRAY_SIZE(machine_adc_obj)
|
||||
&& machine_adc_obj[adc_idx].id != (uint8_t)-1) {
|
||||
@ -137,7 +146,7 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s
|
||||
.acq_time = NRF_SAADC_ACQTIME_3US,
|
||||
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
|
||||
.burst = NRF_SAADC_BURST_DISABLED,
|
||||
.pin_p = self->id, // 0 - 7
|
||||
.pin_p = 1 + self->id, // pin_p=0 is AIN0, pin_p=8 is AIN7
|
||||
.pin_n = NRF_SAADC_INPUT_DISABLED
|
||||
};
|
||||
|
||||
@ -169,6 +178,20 @@ int16_t machine_adc_value_read(machine_adc_obj_t * adc_obj) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// read_u16()
|
||||
STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
|
||||
machine_adc_obj_t *self = self_in;
|
||||
int16_t raw = machine_adc_value_read(self);
|
||||
#if defined(NRF52_SERIES)
|
||||
// raw is signed but the channel is in single-ended mode and this method cannot return negative values
|
||||
if (raw < 0) {
|
||||
raw = 0;
|
||||
}
|
||||
#endif
|
||||
// raw is an 8-bit value
|
||||
return MP_OBJ_NEW_SMALL_INT(raw << 8 | raw);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_machine_adc_read_u16_obj, machine_adc_read_u16);
|
||||
|
||||
/// \method value()
|
||||
/// Read adc level.
|
||||
@ -263,6 +286,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_machine_adc_battery_level_obj, machine_adc_b
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&mp_machine_adc_read_u16_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&mp_machine_adc_value_obj) },
|
||||
|
||||
// class methods
|
||||
|
||||
@ -37,8 +37,8 @@
|
||||
#include "nrf_gpio.h"
|
||||
#include "nrfx_gpiote.h"
|
||||
|
||||
extern const pin_obj_t machine_pin_obj[];
|
||||
extern const uint8_t machine_pin_num_of_pins;
|
||||
extern const pin_obj_t machine_board_pin_obj[];
|
||||
extern const uint8_t machine_pin_num_of_board_pins;
|
||||
|
||||
/// \moduleref machine
|
||||
/// \class Pin - control I/O pins
|
||||
@ -127,12 +127,12 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) {
|
||||
const pin_obj_t *pin_obj;
|
||||
// If pin is SMALL_INT
|
||||
if (mp_obj_is_small_int(user_obj)) {
|
||||
uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj);
|
||||
for (uint8_t i = 0; i < machine_pin_num_of_pins; i++) {
|
||||
if (machine_pin_obj[i].pin == value) {
|
||||
return &machine_pin_obj[i];
|
||||
}
|
||||
}
|
||||
uint8_t value = MP_OBJ_SMALL_INT_VALUE(user_obj);
|
||||
for (uint8_t i = 0; i < machine_pin_num_of_board_pins; i++) {
|
||||
if (machine_board_pin_obj[i].pin == value) {
|
||||
return &machine_board_pin_obj[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a pin was provided, then use it
|
||||
@ -365,7 +365,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con
|
||||
|
||||
// Connect input or not
|
||||
nrf_gpio_pin_input_t input = (mode == NRF_GPIO_PIN_DIR_INPUT) ? NRF_GPIO_PIN_INPUT_CONNECT
|
||||
: NRF_GPIO_PIN_INPUT_DISCONNECT;
|
||||
: NRF_GPIO_PIN_INPUT_DISCONNECT;
|
||||
|
||||
if (mode == NRF_GPIO_PIN_DIR_OUTPUT || mode == NRF_GPIO_PIN_DIR_INPUT) {
|
||||
nrf_gpio_cfg(self->pin,
|
||||
@ -496,7 +496,7 @@ STATIC void pin_common_irq_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum {ARG_handler, ARG_trigger, ARG_wake};
|
||||
enum {ARG_handler, ARG_trigger, ARG_wake};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_handler, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = NRF_GPIOTE_POLARITY_LOTOHI | NRF_GPIOTE_POLARITY_HITOLO} },
|
||||
|
||||
@ -154,9 +154,9 @@ STATIC int spi_find(mp_obj_t id) {
|
||||
void spi_transfer(const machine_hard_spi_obj_t * self, size_t len, const void * src, void * dest) {
|
||||
nrfx_spi_xfer_desc_t xfer_desc = {
|
||||
.p_tx_buffer = src,
|
||||
.tx_length = len,
|
||||
.p_rx_buffer = dest,
|
||||
.rx_length = len
|
||||
.tx_length = len,
|
||||
.p_rx_buffer = dest,
|
||||
.rx_length = len
|
||||
};
|
||||
|
||||
nrfx_spi_xfer(self->p_spi, &xfer_desc, 0);
|
||||
@ -340,7 +340,7 @@ STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) {
|
||||
|
||||
// Active high
|
||||
if (args[ARG_INIT_polarity].u_int == 0) {
|
||||
if (args[ARG_INIT_phase].u_int == 0) {
|
||||
if (args[ARG_INIT_phase].u_int == 0) {
|
||||
// First clock edge
|
||||
self->p_config->mode = NRF_SPI_MODE_0;
|
||||
} else {
|
||||
@ -349,7 +349,7 @@ STATIC void machine_hard_spi_init(mp_obj_t self_in, mp_arg_val_t *args) {
|
||||
}
|
||||
// Active low
|
||||
} else {
|
||||
if (args[ARG_INIT_phase].u_int == 0) {
|
||||
if (args[ARG_INIT_phase].u_int == 0) {
|
||||
// First clock edge
|
||||
self->p_config->mode = NRF_SPI_MODE_2;
|
||||
} else {
|
||||
|
||||
@ -72,7 +72,7 @@ uint32_t machine_rng_generate_random_word(void) {
|
||||
status = sd_rand_application_vector_get((uint8_t *)&retval, 4); // Extract 4 bytes
|
||||
} while (status != 0);
|
||||
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ STATIC const mp_rom_map_elem_t ubluepy_delegate_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_handleConnection), MP_ROM_PTR(&ubluepy_delegate_handle_conn_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_handleNotification), MP_ROM_PTR(&ubluepy_delegate_handle_notif_obj) },
|
||||
#if 0
|
||||
{ MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_handleDiscovery), MP_ROM_PTR(&ubluepy_delegate_handle_disc_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -481,7 +481,7 @@ STATIC const mp_rom_map_elem_t ubluepy_peripheral_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_advertise), MP_ROM_PTR(&ubluepy_peripheral_advertise_obj) },
|
||||
#endif
|
||||
#if MICROPY_PY_UBLUEPY_OBSERVER
|
||||
// Nothing yet.
|
||||
// Nothing yet.
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ STATIC const mp_rom_map_elem_t ubluepy_service_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_addCharacteristic), MP_ROM_PTR(&ubluepy_service_add_char_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_getCharacteristics), MP_ROM_PTR(&ubluepy_service_get_chars_obj) },
|
||||
#if 0
|
||||
// Properties
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_peripheral), MP_ROM_PTR(&ubluepy_service_get_peripheral_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&ubluepy_service_get_uuid_obj) },
|
||||
|
||||
@ -42,7 +42,7 @@ typedef enum
|
||||
} HAL_StatusTypeDef;
|
||||
|
||||
static inline uint32_t hal_tick_fake(void) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define mp_hal_ticks_ms hal_tick_fake // TODO: implement. Right now, return 0 always
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
P0,P0
|
||||
P1,P1
|
||||
P2,P2
|
||||
P3,P3
|
||||
P4,P4
|
||||
P5,P5
|
||||
P2,P2,ADC1_CH0
|
||||
P3,P3,ADC1_CH1
|
||||
P4,P4,ADC1_CH2
|
||||
P5,P5,ADC1_CH3
|
||||
P6,P6
|
||||
P7,P7
|
||||
P8,P8
|
||||
@ -26,10 +26,10 @@ P24,P24
|
||||
P25,P25
|
||||
P26,P26
|
||||
P27,P27
|
||||
P28,P28
|
||||
P29,P29
|
||||
P30,P30
|
||||
P31,P31
|
||||
P28,P28,ADC1_CH4
|
||||
P29,P29,ADC1_CH5
|
||||
P30,P30,ADC1_CH6
|
||||
P31,P31,ADC1_CH7
|
||||
P32,P32
|
||||
P33,P33
|
||||
P34,P34
|
||||
|
||||
|
@ -53,9 +53,12 @@ enum {
|
||||
};
|
||||
|
||||
#define PIN_DEFS_PORT_AF_UNION \
|
||||
NRF_UART_Type *UART;
|
||||
// NRF_SPI_Type *SPIM;
|
||||
// NRF_SPIS_Type *SPIS;
|
||||
NRF_UART_Type *UART;
|
||||
// NRF_SPI_Type *SPIM;
|
||||
// NRF_SPIS_Type *SPIS;
|
||||
|
||||
enum {
|
||||
PIN_ADC1 = (1 << 0),
|
||||
};
|
||||
|
||||
typedef NRF_GPIO_Type pin_gpio_t;
|
||||
|
||||
@ -114,6 +114,14 @@ OBJ = $(OBJ_COMMON) $(OBJ_RUN) $(OBJ_TEST)
|
||||
# List of sources for qstr extraction
|
||||
SRC_QSTR += $(SRC_COMMON_C) $(SRC_RUN_C) $(LIB_SRC_C)
|
||||
|
||||
ifneq ($(FROZEN_MPY_DIR),)
|
||||
# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
|
||||
# then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch).
|
||||
CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
|
||||
CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
|
||||
MPY_CROSS_FLAGS += -march=armv7m
|
||||
endif
|
||||
|
||||
all: run
|
||||
|
||||
run: $(BUILD)/firmware.elf
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
LIB_SRC_C = lib/upytesthelper/upytesthelper.c
|
||||
|
||||
FROZEN_MPY_DIR ?= test-frzmpy
|
||||
|
||||
include Makefile
|
||||
|
||||
CFLAGS += -DTEST
|
||||
@ -8,7 +10,7 @@ CFLAGS += -DTEST
|
||||
|
||||
$(BUILD)/test_main.o: $(BUILD)/genhdr/tests.h
|
||||
$(BUILD)/genhdr/tests.h:
|
||||
(cd $(TOP)/tests; ./run-tests --write-exp)
|
||||
(cd $(TOP)/tests; ./run-tests --target=qemu-arm --write-exp)
|
||||
$(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@
|
||||
|
||||
$(BUILD)/tinytest.o:
|
||||
@ -18,7 +20,8 @@ $(BUILD)/firmware-test.elf: $(OBJ_COMMON) $(OBJ_TEST)
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
# Note: Using timeout(1) to handle cases where qemu hangs (e.g. this can happen with alignment errors).
|
||||
test: $(BUILD)/firmware-test.elf
|
||||
qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out
|
||||
timeout --foreground -k 5s 30s qemu-system-arm -machine $(BOARD) $(QEMU_EXTRA) -nographic -monitor null -semihosting -kernel $< > $(BUILD)/console.out
|
||||
$(Q)tail -n2 $(BUILD)/console.out
|
||||
$(Q)tail -n1 $(BUILD)/console.out | grep -q "status: 0"
|
||||
|
||||
@ -18,7 +18,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
13
ports/qemu-arm/test-frzmpy/native_frozen_align.py
Normal file
13
ports/qemu-arm/test-frzmpy/native_frozen_align.py
Normal file
@ -0,0 +1,13 @@
|
||||
import micropython
|
||||
|
||||
@micropython.native
|
||||
def native_x(x):
|
||||
print(x + 1)
|
||||
|
||||
@micropython.native
|
||||
def native_y(x):
|
||||
print(x + 1)
|
||||
|
||||
@micropython.native
|
||||
def native_z(x):
|
||||
print(x + 1)
|
||||
@ -10,7 +10,7 @@ $(error Invalid BOARD specified: $(BOARD_DIR))
|
||||
endif
|
||||
|
||||
include ../../py/mkenv.mk
|
||||
include $(BOARD_DIR)/board.mk
|
||||
include $(BOARD_DIR)/mpconfigboard.mk
|
||||
|
||||
# Qstr definitions (must come before including py.mk)
|
||||
QSTR_DEFS = qstrdefsport.h
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Feather M0 Express"
|
||||
#define MICROPY_HW_MCU_NAME "SAMD21G18A"
|
||||
@ -0,0 +1,4 @@
|
||||
MCU_SERIES = SAMD21
|
||||
CMSIS_MCU = SAMD21G18A
|
||||
LD_FILES = boards/samd21x18a.ld sections.ld
|
||||
TEXT0 = 0x2000
|
||||
@ -1,4 +1,4 @@
|
||||
MCU_SERIES = SAMD51
|
||||
CMSIS_MCU = SAMD51G19A
|
||||
LD_FILES = $(BOARD_DIR)/link.ld sections.ld
|
||||
LD_FILES = boards/samd51g19a.ld sections.ld
|
||||
TEXT0 = 0x4000
|
||||
@ -1,4 +1,4 @@
|
||||
MCU_SERIES = SAMD21
|
||||
CMSIS_MCU = SAMD21E18A
|
||||
LD_FILES = $(BOARD_DIR)/link.ld sections.ld
|
||||
LD_FILES = boards/samd21x18a.ld sections.ld
|
||||
TEXT0 = 0x2000
|
||||
7
ports/samd/boards/MINISAM_M4/mpconfigboard.h
Normal file
7
ports/samd/boards/MINISAM_M4/mpconfigboard.h
Normal file
@ -0,0 +1,7 @@
|
||||
#define MICROPY_HW_BOARD_NAME "Mini SAM M4"
|
||||
#define MICROPY_HW_MCU_NAME "SAMD51G19A"
|
||||
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
#define MICROPY_PY_BUILTINS_COMPLEX (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_CMATH (0)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user