Merge branch 'master' into nrf52840_usb_hid

This commit is contained in:
hathach 2018-08-01 00:58:23 +07:00
commit 1e524f1b98
778 changed files with 36239 additions and 14253 deletions

2
.gitattributes vendored
View File

@ -18,8 +18,6 @@
tests/basics/string_cr_conversion.py -text
tests/basics/string_crlf_conversion.py -text
ports/stm32/pybcdc.inf_template -text
ports/stm32/usbd_* -text
ports/stm32/usbdev/** -text
ports/stm32/usbhost/** -text
ports/cc3200/hal/aes.c -text
ports/cc3200/hal/aes.h -text

2
.gitmodules vendored
View File

@ -7,7 +7,7 @@
url = https://github.com/atgreen/libffi
[submodule "lib/lwip"]
path = lib/lwip
url = http://git.savannah.gnu.org/r/lwip.git
url = https://git.savannah.gnu.org/r/lwip.git
[submodule "lib/berkeley-db-1.xx"]
path = lib/berkeley-db-1.xx
url = https://github.com/pfalcon/berkeley-db-1.xx

View File

@ -24,9 +24,9 @@ env:
- TRAVIS_BOARD=pirkey_m0
- TRAVIS_BOARD=trinket_m0
- TRAVIS_BOARD=gemma_m0
- TRAVIS_BOARD=hallowing_m0_express
- TRAVIS_BOARD=feather52832
- TRAVIS_BOARD=pca10056
- TRAVIS_TEST=qemu
- TRAVIS_TEST=unix
- TRAVIS_TEST=docs
@ -49,9 +49,7 @@ notifications:
before_script:
- sudo dpkg --add-architecture i386
- ([[ -z "$TRAVIS_TEST" ]] || sudo apt-get install -y qemu-system)
- ([[ -z "$TRAVIS_BOARD" ]] || (wget https://s3.amazonaws.com/adafruit-circuit-python/gcc-arm-embedded_7-2018q2-1~trusty1_amd64.deb && sudo dpkg -i gcc-arm-embedded*_amd64.deb))
- ([[ $TRAVIS_TEST != "qemu" ]] || (wget https://s3.amazonaws.com/adafruit-circuit-python/gcc-arm-embedded_7-2018q2-1~trusty1_amd64.deb && sudo dpkg -i gcc-arm-embedded*_amd64.deb))
# For nrf builds
- ([[ $TRAVIS_BOARD != "feather52832" && $TRAVIS_BOARD != "pca10056" ]] || sudo ports/nrf/drivers/bluetooth/download_ble_stack.sh)
@ -80,10 +78,6 @@ script:
- ([[ $TRAVIS_TEST != "unix" ]] || make -C ports/unix coverage -j2)
- echo -en 'travis_fold:end:unix\\r'
- echo 'Building qemu' && echo -en 'travis_fold:start:qemu\\r'
- ([[ $TRAVIS_TEST != "qemu" ]] || make -C ports/qemu-arm test -j2)
- echo -en 'travis_fold:end:qemu\\r'
# run tests without coverage info
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests -j1)
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests -j1 --emit native)
@ -115,4 +109,3 @@ script:
after_failure:
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
- (grep "FAIL" ports/qemu-arm/build/console.out)

View File

@ -108,6 +108,7 @@ exclude_patterns = ["**/build*",
"ports/cc3200",
"ports/cc3200/FreeRTOS",
"ports/cc3200/hal",
"ports/esp32",
"ports/esp8266/boards",
"ports/esp8266/common-hal",
"ports/esp8266/modules",

View File

@ -21,9 +21,9 @@ Classes
.. method:: append(val)
Append new element to the end of array, growing it.
Append new element ``val`` to the end of array, growing it.
.. method:: extend(iterable)
Append new elements as contained in an iterable to the end of
Append new elements as contained in `iterable` to the end of
array, growing it.

View File

@ -7,7 +7,7 @@
:synopsis: simple BTree database
The ``btree`` module implements a simple key-value database using external
storage (disk files, or in general case, a random-access stream). Keys are
storage (disk files, or in general case, a random-access ``stream``). Keys are
stored sorted in the database, and besides efficient retrieval by a key
value, a database also supports efficient ordered range scans (retrieval
of values with the keys in a given range). On the application interface

View File

@ -150,6 +150,14 @@ Constants
Red Green Blue (16-bit, 5+6+5) color format
.. data:: framebuf.GS2_HMSB
Grayscale (2-bit) color format
.. data:: framebuf.GS4_HMSB
Grayscale (4-bit) color format
.. data:: framebuf.GS8
Grayscale (8-bit) color format

View File

@ -35,16 +35,17 @@ Functions
compilation of scripts, and returns ``None``. Otherwise it returns the current
optimisation level.
.. function:: alloc_emergency_exception_buf(size)
The optimisation level controls the following compilation features:
Allocate *size* bytes of RAM for the emergency exception buffer (a good
size is around 100 bytes). The buffer is used to create exceptions in cases
when normal RAM allocation would fail (eg within an interrupt handler) and
therefore give useful traceback information in these situations.
- Assertions: at level 0 assertion statements are enabled and compiled into the
bytecode; at levels 1 and higher assertions are not compiled.
- Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``;
at levels 1 and higher it expands to ``False``.
- Source-code line numbers: at levels 0, 1 and 2 source-code line number are
stored along with the bytecode so that exceptions can report the line number
they occurred at; at levels 3 and higher line numbers are not stored.
A good way to use this function is to put it at the start of your main script
(eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active
for all the code following it.
The default optimisation level is usually level 0.
.. function:: mem_info([verbose])
@ -90,29 +91,3 @@ Functions
This function can be used to prevent the capturing of Ctrl-C on the
incoming stream of characters that is usually used for the REPL, in case
that stream is used for other purposes.
.. function:: schedule(func, arg)
Schedule the function *func* to be executed "very soon". The function
is passed the value *arg* as its single argument. "Very soon" means that
the MicroPython runtime will do its best to execute the function at the
earliest possible time, given that it is also trying to be efficient, and
that the following conditions hold:
- A scheduled function will never preempt another scheduled function.
- Scheduled functions are always executed "between opcodes" which means
that all fundamental Python operations (such as appending to a list)
are guaranteed to be atomic.
- A given port may define "critical regions" within which scheduled
functions will never be executed. Functions may be scheduled within
a critical region but they will not be executed until that region
is exited. An example of a critical region is a preempting interrupt
handler (an IRQ).
A use for this function is to schedule a callback from a preempting IRQ.
Such an IRQ puts restrictions on the code that runs in the IRQ (for example
the heap may be locked) and scheduling a function to call later will lift
those restrictions.
There is a finite stack to hold the scheduled functions and `schedule`
will raise a `RuntimeError` if the stack is full.

View File

@ -105,15 +105,15 @@ Constants
.. data:: stderr
Standard error stream.
Standard error ``stream``.
.. data:: stdin
Standard input stream.
Standard input ``stream``.
.. data:: stdout
Standard output stream.
Standard output ``stream``.
.. data:: version

View File

@ -10,7 +10,7 @@ This module implements "foreign data interface" for MicroPython. The idea
behind it is similar to CPython's ``ctypes`` modules, but the actual API is
different, streamlined and optimized for small size. The basic idea of the
module is to define data structure layout with about the same power as the
C language allows, and the access it using familiar dot-syntax to reference
C language allows, and then access it using familiar dot-syntax to reference
sub-fields.
.. seealso::
@ -31,25 +31,25 @@ Following are encoding examples for various field types:
* Scalar types::
"field_name": uctypes.UINT32 | 0
"field_name": offset | uctypes.UINT32
in other words, value is scalar type identifier ORed with field offset
(in bytes) from the start of the structure.
* Recursive structures::
"sub": (2, {
"b0": uctypes.UINT8 | 0,
"b1": uctypes.UINT8 | 1,
"sub": (offset, {
"b0": 0 | uctypes.UINT8,
"b1": 1 | uctypes.UINT8,
})
i.e. value is a 2-tuple, first element of which is offset, and second is
a structure descriptor dictionary (note: offsets in recursive descriptors
are relative to a structure it defines).
are relative to the structure it defines).
* Arrays of primitive types::
"arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
"arr": (offset | uctypes.ARRAY, size | uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
with offset, and second is scalar element type ORed number of elements
@ -57,7 +57,7 @@ Following are encoding examples for various field types:
* Arrays of aggregate types::
"arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
"arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}),
i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
with offset, second is a number of elements in array, and third is
@ -65,21 +65,21 @@ Following are encoding examples for various field types:
* Pointer to a primitive type::
"ptr": (uctypes.PTR | 0, uctypes.UINT8),
"ptr": (offset | uctypes.PTR, uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, and second is scalar element type.
* Pointer to an aggregate type::
"ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}),
"ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, second is descriptor of type pointed to.
* Bitfields::
"bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN,
"bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN,
i.e. value is type of scalar value containing given bitfield (typenames are
similar to scalar types, but prefixes with "BF"), ORed with offset for
@ -88,20 +88,21 @@ Following are encoding examples for various field types:
BF_POS and BF_LEN positions, respectively. Bitfield position is counted
from the least significant bit, and is the number of right-most bit of a
field (in other words, it's a number of bits a scalar needs to be shifted
right to extra the bitfield).
right to extract the bitfield).
In the example above, first UINT16 value will be extracted at offset 0
In the example above, first a UINT16 value will be extracted at offset 0
(this detail may be important when accessing hardware registers, where
particular access size and alignment are required), and then bitfield
whose rightmost bit is least-significant bit of this UINT16, and length
is 8 bits, will be extracted - effectively, this will access
least-significant byte of UINT16.
whose rightmost bit is *lsbit* bit of this UINT16, and length
is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and
*bitsize* is 8, then effectively it will access least-significant byte
of UINT16.
Note that bitfield operations are independent of target byte endianness,
in particular, example above will access least-significant byte of UINT16
in both little- and big-endian structures. But it depends on the least
significant bit being numbered 0. Some targets may use different
numbering in their native ABI, but ``uctypes`` always uses normalized
numbering in their native ABI, but ``uctypes`` always uses the normalized
numbering described above.
Module contents

View File

@ -8,7 +8,7 @@
|see_cpython_module| :mod:`cpython:io`.
This module contains additional types of stream (file-like) objects
This module contains additional types of ``stream`` (file-like) objects
and helper functions.
Conceptual hierarchy

View File

@ -14,11 +14,24 @@ data format.
Functions
---------
.. function:: dump(obj, stream)
Serialise ``obj`` to a JSON string, writing it to the given *stream*.
.. function:: dumps(obj)
Return ``obj`` represented as a JSON string.
.. function:: load(stream)
Parse the given ``stream``, interpreting it as a JSON string and
deserialising the data to a Python object. The resulting object is
returned.
Parsing continues until end-of-file is encountered.
A :exc:`ValueError` is raised if the data in ``stream`` is not correctly formed.
.. function:: loads(str)
Parse the JSON ``str`` and return an object. Raises ValueError if the
Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the
string is not correctly formed.

View File

@ -17,8 +17,9 @@ Supported operators are:
``'.'``
Match any character.
``'[]'``
Match set of characters. Individual characters and ranges are supported.
``'[...]'``
Match set of characters. Individual characters and ranges are supported,
including negated sets (e.g. ``[^a-c]``).
``'^'``
@ -38,18 +39,19 @@ Supported operators are:
``'|'``
``'()'``
``'(...)'``
Grouping. Each group is capturing (a substring it captures can be accessed
with `match.group()` method).
Counted repetitions (``{m,n}``), more advanced assertions, named groups,
etc. are not supported.
**NOT SUPPORTED**: Counted repetitions (``{m,n}``), more advanced assertions
(``\b``, ``\B``), named groups (``(?P<name>...)``), non-capturing groups
(``(?:...)``), etc.
Functions
---------
.. function:: compile(regex_str)
.. function:: compile(regex_str, [flags])
Compile regular expression, return `regex <regex>` object.

View File

@ -9,7 +9,7 @@
|see_cpython_module| :mod:`cpython:select`.
This module provides functions to efficiently wait for events on multiple
streams (select streams which are ready for operations).
``stream`` objects (select streams which are ready for operations).
Functions
---------
@ -35,14 +35,17 @@ Methods
.. method:: poll.register(obj[, eventmask])
Register *obj* for polling. *eventmask* is logical OR of:
Register ``stream`` *obj* for polling. *eventmask* is logical OR of:
* ``select.POLLIN`` - data available for reading
* ``select.POLLOUT`` - more data can be written
* ``select.POLLERR`` - error occurred
* ``select.POLLHUP`` - end of stream/connection termination detected
* ``uselect.POLLIN`` - data available for reading
* ``uselect.POLLOUT`` - more data can be written
*eventmask* defaults to ``select.POLLIN | select.POLLOUT``.
Note that flags like ``uselect.POLLHUP`` and ``uselect.POLLERR`` are
*not* valid as input eventmask (these are unsolicited events which
will be returned from `poll()` regardless of whether they are asked
for). This semantics is per POSIX.
*eventmask* defaults to ``uselect.POLLIN | uselect.POLLOUT``.
.. method:: poll.unregister(obj)
@ -52,16 +55,23 @@ Methods
Modify the *eventmask* for *obj*.
.. method:: poll.poll([timeout])
.. method:: poll.poll(timeout=-1)
Wait for at least one of the registered objects to become ready. Returns
list of (``obj``, ``event``, ...) tuples, ``event`` element specifies
which events happened with a stream and is a combination of ``select.POLL*``
constants described above. There may be other elements in tuple, depending
on a platform and version, so don't assume that its size is 2. In case of
timeout, an empty list is returned.
Wait for at least one of the registered objects to become ready or have an
exceptional condition, with optional timeout in milliseconds (if *timeout*
arg is not specified or -1, there is no timeout).
Timeout is in milliseconds.
Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in
tuple, depending on a platform and version, so don't assume that its size is 2.
The ``event`` element specifies which events happened with a stream and
is a combination of ``uselect.POLL*`` constants described above. Note that
flags ``uselect.POLLHUP`` and ``uselect.POLLERR`` can be returned at any time
(even if were not asked for), and must be acted on accordingly (the
corresponding stream unregistered from poll and likely closed), because
otherwise all further invocations of `poll()` may return immediately with
these flags set for this stream again.
In case of timeout, an empty list is returned.
.. admonition:: Difference to CPython
:class: attention
@ -70,15 +80,15 @@ Methods
.. method:: poll.ipoll(timeout=-1, flags=0)
Like :meth:`poll.poll`, but instead returns an iterator which yields
Like :meth:`poll.poll`, but instead returns an iterator which yields a
``callee-owned tuples``. This function provides efficient, allocation-free
way to poll on streams.
If *flags* is 1, one-shot behavior for events is employed: streams for
which events happened, event mask will be automatically reset (equivalent
to ``poll.modify(obj, 0)``), so new events for such a stream won't be
processed until new mask is set with `poll.modify()`. This behavior is
useful for asynchronous I/O schedulers.
which events happened will have their event masks automatically reset
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
won't be processed until new mask is set with `poll.modify()`. This
behavior is useful for asynchronous I/O schedulers.
.. admonition:: Difference to CPython
:class: attention

View File

@ -14,7 +14,7 @@ This module provides access to the BSD socket interface.
.. admonition:: Difference to CPython
:class: attention
For efficiency and consistency, socket objects in MicroPython implement a stream
For efficiency and consistency, socket objects in MicroPython implement a ``stream``
(file-like) interface directly. In CPython, you need to convert a socket to
a file-like object using `makefile()` method. This method is still supported
by MicroPython (but is a no-op), so where compatibility with CPython matters,
@ -245,7 +245,7 @@ Methods
Not every ``MicroPython port`` supports this method. A more portable and
generic solution is to use `uselect.poll` object. This allows to wait on
multiple objects at the same time (and not just on sockets, but on generic
stream objects which support polling). Example::
``stream`` objects which support polling). Example::
# Instead of:
s.settimeout(1.0) # time in seconds

View File

@ -17,13 +17,13 @@ Functions
.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)
Takes a stream *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type),
Takes a ``stream`` *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
an SSL context. Returned object has the usual stream interface methods like
an SSL context. Returned object has the usual ``stream`` interface methods like
``read()``, ``write()``, etc. In MicroPython, the returned object does not expose
socket interface and methods like ``recv()``, ``send()``. In particular, a
server-side SSL socket should be created from a normal socket returned from
`accept()` on a non-SSL listening server socket.
:meth:`~usocket.socket.accept()` on a non-SSL listening server socket.
Depending on the underlying module implementation in a particular
``MicroPython port``, some or all keyword arguments above may be not supported.

View File

@ -27,7 +27,7 @@ Functions
.. class:: DecompIO(stream, wbits=0)
Create a stream wrapper which allows transparent decompression of
Create a ``stream`` wrapper which allows transparent decompression of
compressed data in another *stream*. This allows to process compressed
streams with data larger than available heap size. In addition to
values described in :func:`decompress`, *wbits* may take values

View File

@ -1,8 +1,9 @@
.. warning::
Though this MicroPython-based library is available for use in CircuitPython,
its functionality may change in the future, perhaps significantly.
Though this MicroPython-based library may be available for use
in some builds of CircuitPython, it is unsupported and its functionality
may change in the future, perhaps significantly.
As CircuitPython continues to develop, it may be changed
to comply more closely with the corresponding standard Python library.
You may need to change your code later if you rely
You will likely need to change your code later if you rely
on any non-standard functionality it currently provides.

57
drivers/bus/qspi.h Normal file
View File

@ -0,0 +1,57 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H
#include "py/mphal.h"
enum {
MP_QSPI_IOCTL_INIT,
MP_QSPI_IOCTL_DEINIT,
MP_QSPI_IOCTL_BUS_ACQUIRE,
MP_QSPI_IOCTL_BUS_RELEASE,
};
typedef struct _mp_qspi_proto_t {
int (*ioctl)(void *self, uint32_t cmd);
void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len);
void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);
} mp_qspi_proto_t;
typedef struct _mp_soft_qspi_obj_t {
mp_hal_pin_obj_t cs;
mp_hal_pin_obj_t clk;
mp_hal_pin_obj_t io0;
mp_hal_pin_obj_t io1;
mp_hal_pin_obj_t io2;
mp_hal_pin_obj_t io3;
} mp_soft_qspi_obj_t;
extern const mp_qspi_proto_t mp_soft_qspi_proto;
#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H

203
drivers/bus/softqspi.c Normal file
View File

@ -0,0 +1,203 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 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 "drivers/bus/qspi.h"
#define CS_LOW(self) mp_hal_pin_write(self->cs, 0)
#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1)
#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW
// Use externally provided functions for SCK control and IO reading
#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self)
#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self)
#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self)
#else
// Use generic pin functions for SCK control and IO reading
#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0)
#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1)
#define NIBBLE_READ(self) ( \
mp_hal_pin_read(self->io0) \
| (mp_hal_pin_read(self->io1) << 1) \
| (mp_hal_pin_read(self->io2) << 2) \
| (mp_hal_pin_read(self->io3) << 3))
#endif
STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) {
mp_hal_pin_write(self->io0, v & 1);
mp_hal_pin_write(self->io1, (v >> 1) & 1);
mp_hal_pin_write(self->io2, (v >> 2) & 1);
mp_hal_pin_write(self->io3, (v >> 3) & 1);
}
STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
switch (cmd) {
case MP_QSPI_IOCTL_INIT:
mp_hal_pin_high(self->cs);
mp_hal_pin_output(self->cs);
// Configure pins
mp_hal_pin_write(self->clk, 0);
mp_hal_pin_output(self->clk);
//mp_hal_pin_write(self->clk, 1);
mp_hal_pin_output(self->io0);
mp_hal_pin_input(self->io1);
mp_hal_pin_write(self->io2, 1);
mp_hal_pin_output(self->io2);
mp_hal_pin_write(self->io3, 1);
mp_hal_pin_output(self->io3);
break;
}
return 0; // success
}
STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) {
// Will run as fast as possible, limited only by CPU speed and GPIO time
mp_hal_pin_input(self->io1);
mp_hal_pin_output(self->io0);
if (self->io3) {
mp_hal_pin_write(self->io2, 1);
mp_hal_pin_output(self->io2);
mp_hal_pin_write(self->io3, 1);
mp_hal_pin_output(self->io3);
}
if (src) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->io0, (data_out >> 7) & 1);
mp_hal_pin_write(self->clk, 1);
data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
mp_hal_pin_write(self->clk, 0);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
} else {
for (size_t i = 0; i < len; ++i) {
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j) {
mp_hal_pin_write(self->clk, 1);
data_in = (data_in << 1) | mp_hal_pin_read(self->io1);
mp_hal_pin_write(self->clk, 0);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
}
STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) {
// Make all IO lines input
mp_hal_pin_input(self->io2);
mp_hal_pin_input(self->io3);
mp_hal_pin_input(self->io0);
mp_hal_pin_input(self->io1);
// Will run as fast as possible, limited only by CPU speed and GPIO time
while (len--) {
SCK_HIGH(self);
uint8_t data_in = NIBBLE_READ(self);
SCK_LOW(self);
SCK_HIGH(self);
*buf++ = (data_in << 4) | NIBBLE_READ(self);
SCK_LOW(self);
}
}
STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) {
// Make all IO lines output
mp_hal_pin_output(self->io2);
mp_hal_pin_output(self->io3);
mp_hal_pin_output(self->io0);
mp_hal_pin_output(self->io1);
// Will run as fast as possible, limited only by CPU speed and GPIO time
for (size_t i = 0; i < len; ++i) {
nibble_write(self, buf[i] >> 4);
SCK_HIGH(self);
SCK_LOW(self);
nibble_write(self, buf[i]);
SCK_HIGH(self);
SCK_LOW(self);
}
//mp_hal_pin_input(self->io1);
}
STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd | data << 8;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL);
CS_HIGH(self);
}
STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr};
CS_LOW(self);
mp_soft_qspi_transfer(self, 4, cmd_buf, NULL);
mp_soft_qspi_transfer(self, len, src, NULL);
CS_HIGH(self);
}
STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);
CS_HIGH(self);
return cmd_buf >> 8;
}
STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr};
CS_LOW(self);
mp_soft_qspi_transfer(self, 1, cmd_buf, NULL);
mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)
mp_soft_qspi_qread(self, len, dest);
CS_HIGH(self);
}
const mp_qspi_proto_t mp_soft_qspi_proto = {
.ioctl = mp_soft_qspi_ioctl,
.write_cmd_data = mp_soft_qspi_write_cmd_data,
.write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data,
.read_cmd = mp_soft_qspi_read_cmd,
.read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata,
};

105
drivers/bus/softspi.c Normal file
View File

@ -0,0 +1,105 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 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 "drivers/bus/spi.h"
int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) {
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
switch (cmd) {
case MP_SPI_IOCTL_INIT:
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
break;
case MP_SPI_IOCTL_DEINIT:
break;
}
return 0;
}
void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in;
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
// If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured
// delay_half is equal to this value, then the software SPI implementation
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
mp_hal_pin_write(self->sck, 1 - self->polarity);
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
mp_hal_pin_write(self->sck, self->polarity);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
return;
}
#endif
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, 1 - self->polarity);
} else {
mp_hal_pin_write(self->sck, 1 - self->polarity);
mp_hal_delay_us_fast(delay_half);
}
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, self->polarity);
} else {
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_delay_us_fast(delay_half);
}
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
const mp_spi_proto_t mp_soft_spi_proto = {
.ioctl = mp_soft_spi_ioctl,
.transfer = mp_soft_spi_transfer,
};

55
drivers/bus/spi.h Normal file
View File

@ -0,0 +1,55 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_BUS_SPI_H
#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H
#include "py/mphal.h"
enum {
MP_SPI_IOCTL_INIT,
MP_SPI_IOCTL_DEINIT,
};
typedef struct _mp_spi_proto_t {
int (*ioctl)(void *self, uint32_t cmd);
void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest);
} mp_spi_proto_t;
typedef struct _mp_soft_spi_obj_t {
uint32_t delay_half; // microsecond delay for half SCK period
uint8_t polarity;
uint8_t phase;
mp_hal_pin_obj_t sck;
mp_hal_pin_obj_t mosi;
mp_hal_pin_obj_t miso;
} mp_soft_spi_obj_t;
extern const mp_spi_proto_t mp_soft_spi_proto;
int mp_soft_spi_ioctl(void *self, uint32_t cmd);
void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest);
#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H

View File

@ -23,7 +23,7 @@ typedef uint32_t sys_prot_t;
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#ifdef MICROPY_PY_LWIP_SLIP
#if MICROPY_PY_LWIP_SLIP
#define LWIP_HAVE_SLIPIF 1
#endif

View File

@ -58,7 +58,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// If first argument isn't a Pin-like object, we filter out "invert"
// from keyword arguments and pass them all to the exported Pin
// constructor to create one.
mp_obj_t pin_args[n_args + n_kw * 2];
mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t));
memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
const mp_obj_t *src = args + n_args;
mp_obj_t *dst = pin_args + n_args;
@ -88,6 +88,8 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// will just ignore it as set a concrete type. If not, we'd need
// to expose port's "default" pin type too.
pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
mp_local_free(pin_args);
}
else
#endif

View File

@ -38,61 +38,6 @@
#define MICROPY_PY_MACHINE_SPI_LSB (1)
#endif
void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
// If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured
// delay_half is equal to this value, then the software SPI implementation
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
mp_hal_pin_write(self->sck, 1 - self->polarity);
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
mp_hal_pin_write(self->sck, self->polarity);
}
if (dest != NULL) {
dest[i] = data_in;
}
}
return;
}
#endif
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = src[i];
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, 1 - self->polarity);
} else {
mp_hal_pin_write(self->sck, 1 - self->polarity);
mp_hal_delay_us_fast(delay_half);
}
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
if (self->phase == 0) {
mp_hal_delay_us_fast(delay_half);
mp_hal_pin_write(self->sck, self->polarity);
} else {
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_delay_us_fast(delay_half);
}
}
if (dest != NULL) {
dest[i] = data_in;
}
}
}
/******************************************************************************/
// MicroPython bindings for generic machine.SPI
@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
// Implementation of soft SPI
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE;
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;
} else
#endif
{
@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
}
STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) {
return MICROPY_PY_MACHINE_SPI_MIN_DELAY;
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) {
return MICROPY_HW_SOFTSPI_MIN_DELAY;
} else
#endif
{
@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in,
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u,"
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
baudrate_from_delay_half(self->delay_half), self->polarity, self->phase,
mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso));
baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase,
mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
}
STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
self->base.type = &mp_machine_soft_spi_type;
// set parameters
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->polarity = args[ARG_polarity].u_int;
self->phase = args[ARG_phase].u_int;
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->spi.polarity = args[ARG_polarity].u_int;
self->spi.phase = args[ARG_phase].u_int;
if (args[ARG_bits].u_int != 8) {
mp_raise_ValueError("bits must be 8");
}
@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
|| args[ARG_miso].u_obj == MP_OBJ_NULL) {
mp_raise_ValueError("must specify all of sck/mosi/miso");
}
self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
// configure pins
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
// configure bus
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
return MP_OBJ_FROM_PTR(self);
}
@ -296,32 +238,34 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_baudrate].u_int != -1) {
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
}
if (args[ARG_polarity].u_int != -1) {
self->polarity = args[ARG_polarity].u_int;
self->spi.polarity = args[ARG_polarity].u_int;
}
if (args[ARG_phase].u_int != -1) {
self->phase = args[ARG_phase].u_int;
self->spi.phase = args[ARG_phase].u_int;
}
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
}
if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
}
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
}
// configure pins
mp_hal_pin_write(self->sck, self->polarity);
mp_hal_pin_output(self->sck);
mp_hal_pin_output(self->mosi);
mp_hal_pin_input(self->miso);
// configure bus
mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
}
STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = {
STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
mp_soft_spi_transfer(&self->spi, len, src, dest);
}
const mp_machine_spi_p_t mp_machine_soft_spi_p = {
.init = mp_machine_soft_spi_init,
.deinit = NULL,
.transfer = mp_machine_soft_spi_transfer,

View File

@ -28,6 +28,7 @@
#include "py/obj.h"
#include "py/mphal.h"
#include "drivers/bus/spi.h"
// SPI protocol
typedef struct _mp_machine_spi_p_t {
@ -38,19 +39,13 @@ typedef struct _mp_machine_spi_p_t {
typedef struct _mp_machine_soft_spi_obj_t {
mp_obj_base_t base;
uint32_t delay_half; // microsecond delay for half SCK period
uint8_t polarity;
uint8_t phase;
mp_hal_pin_obj_t sck;
mp_hal_pin_obj_t mosi;
mp_hal_pin_obj_t miso;
mp_soft_spi_obj_t spi;
} mp_machine_soft_spi_obj_t;
extern const mp_machine_spi_p_t mp_machine_soft_spi_p;
extern const mp_obj_type_t mp_machine_soft_spi_type;
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest);
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);

View File

@ -282,7 +282,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in);
switch (op) {
case MP_BINARY_OP_IN: {
case MP_BINARY_OP_CONTAINS: {
DBT key, val;
key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size);
int res = __bt_get(self->db, &key, &val, 0);

View File

@ -54,7 +54,9 @@ typedef struct _mp_framebuf_p_t {
// constants for formats
#define FRAMEBUF_MVLSB (0)
#define FRAMEBUF_RGB565 (1)
#define FRAMEBUF_GS2_HMSB (5)
#define FRAMEBUF_GS4_HMSB (2)
#define FRAMEBUF_GS8 (6)
#define FRAMEBUF_MHLSB (3)
#define FRAMEBUF_MHMSB (4)
@ -130,6 +132,30 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i
}
}
// Functions for GS2_HMSB format
STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];
uint8_t shift = (x & 0x3) << 1;
uint8_t mask = 0x3 << shift;
uint8_t color = (col & 0x3) << shift;
*pixel = color | (*pixel & (~mask));
}
STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];
uint8_t shift = (x & 0x3) << 1;
return (pixel >> shift) & 0x3;
}
STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
for (int xx=x; xx < x+w; xx++) {
for (int yy=y; yy < y+h; yy++) {
gs2_hmsb_setpixel(fb, xx, yy, col);
}
}
}
// Functions for GS4_HMSB format
STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
@ -181,10 +207,31 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w,
}
}
// Functions for GS8 format
STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];
*pixel = col & 0xff;
}
STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
return ((uint8_t*)fb->buf)[(x + y * fb->stride)];
}
STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];
while (h--) {
memset(pixel, col, w);
pixel += fb->stride;
}
}
STATIC mp_framebuf_p_t formats[] = {
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
[FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect},
[FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect},
[FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect},
[FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
};
@ -240,9 +287,14 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
case FRAMEBUF_MHMSB:
o->stride = (o->stride + 7) & ~7;
break;
case FRAMEBUF_GS2_HMSB:
o->stride = (o->stride + 3) & ~3;
break;
case FRAMEBUF_GS4_HMSB:
o->stride = (o->stride + 1) & ~1;
break;
case FRAMEBUF_GS8:
break;
default:
mp_raise_ValueError("invalid format");
}
@ -579,7 +631,9 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
{ MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) },
{ MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) },
{ MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) },
{ MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) },
{ MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) },
{ MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) },
};

View File

@ -38,13 +38,18 @@
#include "lib/netutils/netutils.h"
#include "lwip/init.h"
#include "lwip/timers.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
//#include "lwip/raw.h"
#include "lwip/dns.h"
#include "lwip/tcp_impl.h"
#include "lwip/igmp.h"
#if LWIP_VERSION_MAJOR < 2
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#else
#include "lwip/timeouts.h"
#include "lwip/priv/tcp_priv.h"
#endif
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
@ -64,12 +69,12 @@
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#endif
#ifdef MICROPY_PY_LWIP_SLIP
#if MICROPY_PY_LWIP_SLIP
#include "netif/slipif.h"
#include "lwip/sio.h"
#endif
#ifdef MICROPY_PY_LWIP_SLIP
#if MICROPY_PY_LWIP_SLIP
/******************************************************************************/
// Slip object for modlwip. Requires a serial driver for the port that supports
// the lwip serial callback functions.
@ -171,11 +176,16 @@ STATIC const mp_obj_type_t lwip_slip_type = {
// Table to convert lwIP err_t codes to socket errno codes, from the lwIP
// socket API.
// lwIP 2 changed LWIP_VERSION and it can no longer be used in macros,
// so we define our own equivalent version that can.
#define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \
| LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
// Extension to lwIP error codes
#define _ERR_BADF -16
// TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1,
// investigate in more detail.
#if LWIP_VERSION < 0x01040100
#if LWIP_VERSION_MACRO < 0x01040100
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */
@ -196,7 +206,7 @@ static const int error_lookup_table[] = {
MP_EALREADY, /* ERR_ISCONN -15 Already connected. */
MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
#else
#elif LWIP_VERSION_MACRO < 0x02000000
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */
@ -217,6 +227,30 @@ static const int error_lookup_table[] = {
-1, /* ERR_IF -15 Low-level netif error */
MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
#else
// Matches lwIP 2.0.3
#undef _ERR_BADF
#define _ERR_BADF -17
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK */
MP_ENOMEM, /* ERR_MEM -1 Out of memory error */
MP_ENOBUFS, /* ERR_BUF -2 Buffer error */
MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem */
MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
MP_EINVAL, /* ERR_VAL -6 Illegal value */
MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block */
MP_EADDRINUSE, /* ERR_USE -8 Address in use */
MP_EALREADY, /* ERR_ALREADY -9 Already connecting */
MP_EALREADY, /* ERR_ISCONN -10 Conn already established */
MP_ENOTCONN, /* ERR_CONN -11 Not connected */
-1, /* ERR_IF -12 Low-level netif error */
MP_ECONNABORTED, /* ERR_ABRT -13 Connection aborted */
MP_ECONNRESET, /* ERR_RST -14 Connection reset */
MP_ENOTCONN, /* ERR_CLSD -15 Connection closed */
MP_EIO, /* ERR_ARG -16 Illegal argument. */
MP_EBADF, /* _ERR_BADF -17 Closed socket (null pcb) */
};
#endif
/*******************************************************************************/
@ -276,7 +310,12 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) {
// Callback for incoming UDP packets. We simply stash the packet and the source address,
// in case we need it for recvfrom.
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
#if LWIP_VERSION_MAJOR < 2
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
#else
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
#endif
{
lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
if (socket->incoming.pbuf != NULL) {
@ -498,6 +537,11 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
// If the output buffer is getting full then send the data to the lower layers
if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) {
err = tcp_output(socket->pcb.tcp);
}
if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
return MP_STREAM_ERROR;
@ -632,42 +676,6 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s
return socket;
}
STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) {
lwip_socket_obj_t *socket = self_in;
bool socket_is_listener = false;
if (socket->pcb.tcp == NULL) {
return mp_const_none;
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
if (socket->pcb.tcp->state == LISTEN) {
socket_is_listener = true;
}
if (tcp_close(socket->pcb.tcp) != ERR_OK) {
DEBUG_printf("lwip_close: had to call tcp_abort()\n");
tcp_abort(socket->pcb.tcp);
}
break;
}
case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
//case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
}
socket->pcb.tcp = NULL;
socket->state = _ERR_BADF;
if (socket->incoming.pbuf != NULL) {
if (!socket_is_listener) {
pbuf_free(socket->incoming.pbuf);
} else {
tcp_abort(socket->incoming.connection);
}
socket->incoming.pbuf = NULL;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close);
STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
lwip_socket_obj_t *socket = self_in;
@ -715,6 +723,9 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
socket->pcb.tcp = new_pcb;
tcp_accept(new_pcb, _lwip_tcp_accept);
// Socket is no longer considered "new" for purposes of polling
socket->state = STATE_CONNECTING;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
@ -1163,17 +1174,60 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
ret |= MP_STREAM_POLL_RD;
}
if (flags & MP_STREAM_POLL_WR && tcp_sndbuf(socket->pcb.tcp) > 0) {
// Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf
if (flags & MP_STREAM_POLL_WR && socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) {
ret |= MP_STREAM_POLL_WR;
}
if (socket->state == STATE_PEER_CLOSED) {
if (socket->state == STATE_NEW) {
// New sockets are not connected so set HUP
ret |= flags & MP_STREAM_POLL_HUP;
} else if (socket->state == STATE_PEER_CLOSED) {
// Peer-closed socket is both readable and writable: read will
// return EOF, write - error. Without this poll will hang on a
// socket which was closed by peer.
ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR);
} else if (socket->state == ERR_RST) {
// Socket was reset by peer, a write will return an error
ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP);
} else if (socket->state < 0) {
// Socket in some other error state, use catch-all ERR flag
// TODO: may need to set other return flags here
ret |= flags & MP_STREAM_POLL_ERR;
}
} else if (request == MP_STREAM_CLOSE) {
bool socket_is_listener = false;
if (socket->pcb.tcp == NULL) {
return 0;
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
if (socket->pcb.tcp->state == LISTEN) {
socket_is_listener = true;
}
if (tcp_close(socket->pcb.tcp) != ERR_OK) {
DEBUG_printf("lwip_close: had to call tcp_abort()\n");
tcp_abort(socket->pcb.tcp);
}
break;
}
case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
//case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
}
socket->pcb.tcp = NULL;
socket->state = _ERR_BADF;
if (socket->incoming.pbuf != NULL) {
if (!socket_is_listener) {
pbuf_free(socket->incoming.pbuf);
} else {
tcp_abort(socket->incoming.connection);
}
socket->incoming.pbuf = NULL;
}
ret = 0;
} else {
*errcode = MP_EINVAL;
ret = MP_STREAM_ERROR;
@ -1183,8 +1237,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
}
STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&lwip_socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&lwip_socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) },
@ -1278,7 +1332,12 @@ typedef struct _getaddrinfo_state_t {
} getaddrinfo_state_t;
// Callback for incoming DNS requests.
STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
#if LWIP_VERSION_MAJOR < 2
STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg)
#else
STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg)
#endif
{
getaddrinfo_state_t *state = arg;
if (ipaddr != NULL) {
state->status = 1;
@ -1291,14 +1350,33 @@ STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg)
// lwip.getaddrinfo
STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
if (n_args > 2) {
mp_warning("getaddrinfo constraints not supported");
}
mp_obj_t host_in = args[0], port_in = args[1];
const char *host = mp_obj_str_get_str(host_in);
mp_int_t port = mp_obj_get_int(port_in);
// If constraints were passed then check they are compatible with the supported params
if (n_args > 2) {
mp_int_t family = mp_obj_get_int(args[2]);
mp_int_t type = 0;
mp_int_t proto = 0;
mp_int_t flags = 0;
if (n_args > 3) {
type = mp_obj_get_int(args[3]);
if (n_args > 4) {
proto = mp_obj_get_int(args[4]);
if (n_args > 5) {
flags = mp_obj_get_int(args[5]);
}
}
}
if (!((family == 0 || family == MOD_NETWORK_AF_INET)
&& (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
&& proto == 0
&& flags == 0)) {
mp_warning("unsupported getaddrinfo constraints");
}
}
getaddrinfo_state_t state;
state.status = 0;
@ -1331,7 +1409,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG);
return mp_obj_new_list(1, (mp_obj_t*)&tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
// Debug functions
@ -1341,7 +1419,7 @@ STATIC mp_obj_t lwip_print_pcbs() {
}
MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs);
#ifdef MICROPY_PY_LWIP
#if MICROPY_PY_LWIP
STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) },
@ -1351,7 +1429,7 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_print_pcbs), MP_ROM_PTR(&lwip_print_pcbs_obj) },
// objects
{ MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&lwip_socket_type) },
#ifdef MICROPY_PY_LWIP_SLIP
#if MICROPY_PY_LWIP_SLIP
{ MP_ROM_QSTR(MP_QSTR_slip), MP_ROM_PTR(&lwip_slip_type) },
#endif
// class constants

View File

@ -31,11 +31,69 @@
#if MICROPY_PY_UHASHLIB
#if MICROPY_PY_UHASHLIB_SHA256
#if MICROPY_SSL_MBEDTLS
#include "mbedtls/sha256.h"
#else
#include "crypto-algorithms/sha256.h"
#endif
#endif
#if MICROPY_PY_UHASHLIB_SHA1
#if MICROPY_SSL_AXTLS
#include "lib/axtls/crypto/crypto.h"
#endif
#if MICROPY_SSL_MBEDTLS
#include "mbedtls/sha1.h"
#endif
#endif
typedef struct _mp_obj_hash_t {
mp_obj_base_t base;
char state[0];
} mp_obj_hash_t;
#if MICROPY_PY_UHASHLIB_SHA256
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
#if MICROPY_SSL_MBEDTLS
STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
o->base.type = type;
mbedtls_sha256_init((mbedtls_sha256_context*)&o->state);
mbedtls_sha256_starts((mbedtls_sha256_context*)&o->state, 0);
if (n_args == 1) {
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
mbedtls_sha256_update((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
vstr_init_len(&vstr, 32);
mbedtls_sha256_finish((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
#else
static void check_not_unicode(const mp_obj_t arg) {
#if MICROPY_CPYTHON_COMPAT
if (MP_OBJ_IS_STR(arg)) {
@ -44,40 +102,18 @@ static void check_not_unicode(const mp_obj_t arg) {
#endif
}
typedef struct _mp_obj_hash_t {
mp_obj_base_t base;
char state[0];
} mp_obj_hash_t;
STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_obj_t hash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
o->base.type = type;
sha256_init((CRYAL_SHA256_CTX*)o->state);
if (n_args == 1) {
hash_update(MP_OBJ_FROM_PTR(o), args[0]);
uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
#if MICROPY_PY_UHASHLIB_SHA1
STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg);
STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
o->base.type = type;
SHA1_Init((SHA1_CTX*)o->state);
if (n_args == 1) {
sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
#endif
STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
@ -85,10 +121,50 @@ STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
#endif
STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest);
STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) },
};
STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table);
STATIC const mp_obj_type_t uhashlib_sha256_type = {
{ &mp_type_type },
.name = MP_QSTR_sha256,
.make_new = uhashlib_sha256_make_new,
.locals_dict = (void*)&uhashlib_sha256_locals_dict,
};
#endif
#if MICROPY_PY_UHASHLIB_SHA1
STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) {
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);
#if MICROPY_SSL_AXTLS
STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
o->base.type = type;
SHA1_Init((SHA1_CTX*)o->state);
if (n_args == 1) {
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
@ -96,73 +172,83 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) {
SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update);
#endif
STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
#if MICROPY_PY_UHASHLIB_SHA1
STATIC mp_obj_t sha1_digest(mp_obj_t self_in) {
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
vstr_init_len(&vstr, SHA1_SIZE);
SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest);
#endif
STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) },
#if MICROPY_SSL_MBEDTLS
STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
o->base.type = type;
mbedtls_sha1_init((mbedtls_sha1_context*)o->state);
mbedtls_sha1_starts((mbedtls_sha1_context*)o->state);
if (n_args == 1) {
uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
vstr_init_len(&vstr, 20);
mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf);
mbedtls_sha1_free((mbedtls_sha1_context*)self->state);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
#endif
STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest);
STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) },
};
STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table);
STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table);
STATIC const mp_obj_type_t sha256_type = {
{ &mp_type_type },
.name = MP_QSTR_sha256,
.make_new = hash_make_new,
.locals_dict = (void*)&hash_locals_dict,
};
#if MICROPY_PY_UHASHLIB_SHA1
STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) },
{ MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) },
};
STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table);
STATIC const mp_obj_type_t sha1_type = {
STATIC const mp_obj_type_t uhashlib_sha1_type = {
{ &mp_type_type },
.name = MP_QSTR_sha1,
.make_new = sha1_make_new,
.locals_dict = (void*)&sha1_locals_dict,
.make_new = uhashlib_sha1_make_new,
.locals_dict = (void*)&uhashlib_sha1_locals_dict,
};
#endif
STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) },
{ MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) },
#if MICROPY_PY_UHASHLIB_SHA256
{ MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) },
#endif
#if MICROPY_PY_UHASHLIB_SHA1
{ MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) },
{ MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) },
#endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table);
const mp_obj_module_t mp_module_uhashlib = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
.globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals,
};
#if MICROPY_PY_UHASHLIB_SHA256
#include "crypto-algorithms/sha256.c"
#endif
#endif //MICROPY_PY_UHASHLIB

View File

@ -34,6 +34,14 @@
#if MICROPY_PY_UJSON
STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
mp_obj_print_helper(&print, obj, PRINT_JSON);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
vstr_t vstr;
mp_print_t print;
@ -166,7 +174,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
goto fail;
}
S_NEXT(s);
next = mp_obj_new_str(vstr.buf, vstr.len, false);
next = mp_obj_new_str(vstr.buf, vstr.len);
break;
case '-':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
@ -283,6 +291,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },
{ MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) },
{ MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },
{ MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },
{ MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },

View File

@ -144,7 +144,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
}
mp_obj_t retval = mp_obj_new_list(0, NULL);
const char **caps = alloca(caps_num * sizeof(char*));
const char **caps = mp_local_alloc(caps_num * sizeof(char*));
while (true) {
// cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
memset((char**)caps, 0, caps_num * sizeof(char*));
@ -165,6 +165,8 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
break;
}
}
// cast is a workaround for a bug in msvc (see above)
mp_local_free((char**)caps);
mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin);
mp_obj_list_append(retval, s);

View File

@ -44,6 +44,8 @@ typedef struct _mp_obj_ssl_socket_t {
} mp_obj_ssl_socket_t;
struct ssl_args {
mp_arg_val_t key;
mp_arg_val_t cert;
mp_arg_val_t server_side;
mp_arg_val_t server_hostname;
};
@ -62,10 +64,28 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
o->sock = sock;
uint32_t options = SSL_SERVER_VERIFY_LATER;
if (args->key.u_obj != mp_const_none) {
options |= SSL_NO_DEFAULT_KEY;
}
if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
mp_raise_OSError(MP_EINVAL);
}
if (args->key.u_obj != mp_const_none) {
size_t len;
const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len);
int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL);
if (res != SSL_OK) {
mp_raise_ValueError("invalid key");
}
data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len);
res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL);
if (res != SSL_OK) {
mp_raise_ValueError("invalid cert");
}
}
if (args->server_side.u_bool) {
o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock);
} else {
@ -113,7 +133,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
if (r == SSL_OK) {
// SSL_OK from ssl_read() means "everything is ok, but there's
// not user data yet. So, we just keep reading.
// no user data yet". So, we just keep reading.
continue;
}
if (r < 0) {
@ -121,6 +141,9 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
// EOF
return 0;
}
if (r == SSL_EAGAIN) {
r = MP_EAGAIN;
}
*errcode = r;
return MP_STREAM_ERROR;
}
@ -152,6 +175,25 @@ 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) {
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
(void)arg;
switch (request) {
case MP_STREAM_CLOSE:
if (self->ssl_sock != NULL) {
ssl_free(self->ssl_sock);
ssl_ctx_free(self->ssl_ctx);
self->ssl_sock = NULL;
mp_stream_close(self->sock);
}
return 0;
default:
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
// Currently supports only blocking mode
(void)self_in;
@ -162,28 +204,15 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
if (self->ssl_sock != NULL) {
ssl_free(self->ssl_sock);
ssl_ctx_free(self->ssl_ctx);
self->ssl_sock = NULL;
return mp_stream_close(self->sock);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
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_close), MP_ROM_PTR(&socket_close_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(&socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
#endif
};
@ -192,6 +221,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab
STATIC const mp_stream_p_t ussl_socket_stream_p = {
.read = socket_read,
.write = socket_write,
.ioctl = socket_ioctl,
};
STATIC const mp_obj_type_t ussl_socket_type = {
@ -208,6 +238,8 @@ STATIC const mp_obj_type_t ussl_socket_type = {
STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// TODO: Implement more args
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};

View File

@ -73,19 +73,10 @@ STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, cons
}
#endif
// TODO: FIXME!
STATIC int null_entropy_func(void *data, unsigned char *output, size_t len) {
(void)data;
(void)output;
(void)len;
// enjoy random bytes
return 0;
}
STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
const mp_stream_p_t *sock_stream = mp_get_stream(sock);
int err;
mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
@ -102,7 +93,7 @@ STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
const mp_stream_p_t *sock_stream = mp_get_stream(sock);
int err;
mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
@ -118,12 +109,16 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
// Verify the socket object has the full stream protocol
mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
#if MICROPY_PY_USSL_FINALISER
mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
#else
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
#endif
o->base.type = &ussl_socket_type;
o->sock = sock;
int ret;
mbedtls_ssl_init(&o->ssl);
@ -139,10 +134,9 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
mbedtls_entropy_init(&o->entropy);
const byte seed[] = "upy";
ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed));
ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed));
if (ret != 0) {
printf("ret=%d\n", ret);
assert(0);
goto cleanup;
}
ret = mbedtls_ssl_config_defaults(&o->conf,
@ -150,7 +144,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
assert(0);
goto cleanup;
}
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
@ -161,18 +155,17 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
if (ret != 0) {
assert(0);
goto cleanup;
}
if (args->server_hostname.u_obj != mp_const_none) {
const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
if (ret != 0) {
assert(0);
goto cleanup;
}
}
o->sock = sock;
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
if (args->key.u_obj != MP_OBJ_NULL) {
@ -194,13 +187,27 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
//assert(0);
printf("mbedtls_ssl_handshake error: -%x\n", -ret);
mp_raise_OSError(MP_EIO);
goto cleanup;
}
}
return o;
cleanup:
mbedtls_pk_free(&o->pkey);
mbedtls_x509_crt_free(&o->cert);
mbedtls_x509_crt_free(&o->cacert);
mbedtls_ssl_free(&o->ssl);
mbedtls_ssl_config_free(&o->conf);
mbedtls_ctr_drbg_free(&o->ctr_drbg);
mbedtls_entropy_free(&o->entropy);
if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
mp_raise_OSError(MP_ENOMEM);
} else {
mp_raise_OSError(MP_EIO);
}
}
STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
@ -261,20 +268,26 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
STATIC mp_uint_t 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);
(void)arg;
switch (request) {
case MP_STREAM_CLOSE:
mbedtls_pk_free(&self->pkey);
mbedtls_x509_crt_free(&self->cert);
mbedtls_x509_crt_free(&self->cacert);
mbedtls_ssl_free(&self->ssl);
mbedtls_ssl_config_free(&self->conf);
mbedtls_ctr_drbg_free(&self->ctr_drbg);
mbedtls_entropy_free(&self->entropy);
mp_stream_close(self->sock);
return 0;
mbedtls_pk_free(&self->pkey);
mbedtls_x509_crt_free(&self->cert);
mbedtls_x509_crt_free(&self->cacert);
mbedtls_ssl_free(&self->ssl);
mbedtls_ssl_config_free(&self->conf);
mbedtls_ctr_drbg_free(&self->ctr_drbg);
mbedtls_entropy_free(&self->entropy);
return mp_stream_close(self->sock);
default:
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
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) },
@ -282,9 +295,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ 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_close), MP_ROM_PTR(&socket_close_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(&socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
};
@ -294,6 +307,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab
STATIC const mp_stream_p_t ussl_socket_stream_p = {
.read = socket_read,
.write = socket_write,
.ioctl = socket_ioctl,
};
STATIC const mp_obj_type_t ussl_socket_type = {

View File

@ -53,7 +53,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) {
p -= offsetof(mp_obj_decompio_t, decomp);
mp_obj_decompio_t *self = (mp_obj_decompio_t*)p;
const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ);
const mp_stream_p_t *stream = mp_get_stream(self->src_stream);
int err;
byte c;
mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);
@ -68,6 +68,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) {
STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t);
o->base.type = type;
memset(&o->decomp, 0, sizeof(o->decomp));

View File

@ -37,7 +37,7 @@
#include "extmod/modwebsocket.h"
#include "genhdr/mpversion.h"
#ifdef MICROPY_PY_WEBREPL
#if MICROPY_PY_WEBREPL
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
@ -76,7 +76,7 @@ STATIC char denied_prompt[] = "\r\nAccess denied\r\n";
STATIC char webrepl_passwd[10];
STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {
const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
const mp_stream_p_t *sock_stream = mp_get_stream(websock);
int err;
int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err);
sock_stream->write(websock, buf, len, &err);
@ -86,7 +86,7 @@ STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {
#define SSTR(s) s, sizeof(s) - 1
STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) {
int err;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
const mp_stream_p_t *sock_stream = mp_get_stream(websock);
sock_stream->write(websock, str, sz, &err);
}
@ -110,8 +110,7 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_
}
STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
const mp_stream_p_t *file_stream =
mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);
byte readbuf[2 + 256];
int err;
mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err);
@ -141,7 +140,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) {
// Handle operations requiring opened file
mp_obj_t open_args[2] = {
mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false),
mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)),
MP_OBJ_NEW_QSTR(MP_QSTR_rb)
};
@ -181,7 +180,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int
// We know that os.dupterm always calls with size = 1
assert(size == 1);
mp_obj_webrepl_t *self = self_in;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
const mp_stream_p_t *sock_stream = mp_get_stream(self->sock);
mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode);
//DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz);
if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
@ -293,16 +292,24 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size
// Don't forward output until passwd is entered
return size;
}
const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_WRITE);
const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
return stream_p->write(self->sock, buf, size, errcode);
}
STATIC mp_obj_t webrepl_close(mp_obj_t self_in) {
mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in);
// TODO: This is a place to do cleanup
return mp_stream_close(self->sock);
STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in);
(void)arg;
switch (request) {
case MP_STREAM_CLOSE:
// TODO: This is a place to do cleanup
mp_stream_close(self->sock);
return 0;
default:
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close);
STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) {
size_t len;
@ -319,13 +326,14 @@ STATIC const mp_rom_map_elem_t webrepl_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_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&webrepl_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table);
STATIC const mp_stream_p_t webrepl_stream_p = {
.read = webrepl_read,
.write = webrepl_write,
.ioctl = webrepl_ioctl,
};
STATIC const mp_obj_type_t webrepl_type = {

View File

@ -59,6 +59,7 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si
STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t);
o->base.type = type;
o->sock = args[0];
@ -75,7 +76,7 @@ STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, siz
STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
while (1) {
if (self->to_recv != 0) {
mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);
@ -256,6 +257,11 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si
STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
switch (request) {
case MP_STREAM_CLOSE:
// TODO: Send close signaling to the other side, otherwise it's
// abrupt close (connection abort).
mp_stream_close(self->sock);
return 0;
case MP_STREAM_GET_DATA_OPTS:
return self->ws_flags & FRAME_OPCODE_MASK;
case MP_STREAM_SET_DATA_OPTS: {
@ -269,21 +275,13 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t
}
}
STATIC mp_obj_t websocket_close(mp_obj_t self_in) {
mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
// TODO: Send close signaling to the other side, otherwise it's
// abrupt close (connection abort).
return mp_stream_close(self->sock);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close);
STATIC const mp_rom_map_elem_t websocket_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_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&websocket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);

View File

@ -5,9 +5,9 @@
#include "re1.5.h"
#define INSERT_CODE(at, num, pc) \
((code ? memmove(code + at + num, code + at, pc - at) : (void)0), pc += num)
((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num)
#define REL(at, to) (to - at - 2)
#define EMIT(at, byte) (code ? (code[at] = byte) : (void)(at))
#define EMIT(at, byte) (code ? (code[at] = byte) : (at))
#define PC (prog->bytelen)
static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)

View File

@ -34,7 +34,7 @@
#include "py/stream.h"
#include "lib/utils/interrupt_char.h"
#ifdef MICROPY_PY_OS_DUPTERM
#if MICROPY_PY_OS_DUPTERM
void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
@ -60,25 +60,29 @@ int mp_uos_dupterm_rx_chr(void) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t readinto_m[3];
mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m);
readinto_m[2] = MP_STATE_VM(dupterm_arr_obj);
mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
if (res == mp_const_none) {
nlr_pop();
} else if (res == MP_OBJ_NEW_SMALL_INT(0)) {
byte buf[1];
int errcode;
const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
if (out_sz == 0) {
nlr_pop();
mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
} else if (out_sz == MP_STREAM_ERROR) {
// errcode is valid
if (mp_is_nonblocking_error(errcode)) {
nlr_pop();
} else {
mp_raise_OSError(errcode);
}
} else {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
// read 1 byte
nlr_pop();
if (*(byte*)bufinfo.buf == mp_interrupt_char) {
if (buf[0] == mp_interrupt_char) {
// Signal keyboard interrupt to be raised as soon as the VM resumes
mp_keyboard_interrupt();
return -2;
}
return *(byte*)bufinfo.buf;
return buf[0];
}
} else {
mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
@ -96,18 +100,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t write_m[3];
mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m);
mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
void *org_items = arr->items;
arr->items = (void*)str;
arr->len = len;
write_m[2] = MP_STATE_VM(dupterm_arr_obj);
mp_call_method_n_kw(1, 0, write_m);
arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
arr->items = org_items;
arr->len = 1;
mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);
nlr_pop();
} else {
mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val);
@ -132,10 +125,8 @@ STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
if (args[0] == mp_const_none) {
MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
} else {
mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
MP_STATE_VM(dupterm_objs[idx]) = args[0];
if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) {
MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
}
}
return previous_obj;

View File

@ -124,21 +124,39 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) {
if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) {
return MP_IMPORT_STAT_NO_EXIST;
}
#if MICROPY_VFS_FAT
// fast paths for known VFS types
if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) {
return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out);
// If the mounted object has the VFS protocol, call its import_stat helper
const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol;
if (proto != NULL) {
return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out);
}
// delegate to vfs.stat() method
mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out));
mp_obj_t stat;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o);
nlr_pop();
} else {
// assume an exception means that the path is not found
return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t *items;
mp_obj_get_array_fixed_n(stat, 10, &items);
mp_int_t st_mode = mp_obj_get_int(items[0]);
if (st_mode & MP_S_IFDIR) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
#endif
// TODO delegate to vfs.stat() method
return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_readonly, ARG_mkfs };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
};
// parse args
@ -246,7 +264,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
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);
mp_vfs_mount_t *vfs = lookup_path((mp_obj_t)args[ARG_file].u_rom_obj, &args[ARG_file].u_obj);
mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj);
return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open);
@ -261,7 +279,7 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
// subsequent relative paths begin at the root of that VFS.
for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
if (vfs->len == 1) {
mp_obj_t root = mp_obj_new_str("/", 1, false);
mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root);
break;
}
@ -307,7 +325,7 @@ mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) {
self->cur.vfs = vfs->next;
if (vfs->len == 1) {
// vfs is mounted at root dir, delegate to it
mp_obj_t root = mp_obj_new_str("/", 1, false);
mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
self->is_iter = true;
self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root);
return mp_iternext(self->cur.iter);
@ -355,9 +373,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
mp_obj_t next;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
mp_obj_t *items;
mp_obj_get_array_fixed_n(next, 3, &items);
mp_obj_list_append(dir_list, items[0]);
mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL));
}
return dir_list;
}

View File

@ -45,6 +45,11 @@
#define BP_IOCTL_SEC_COUNT (4)
#define BP_IOCTL_SEC_SIZE (5)
// At the moment the VFS protocol just has import_stat, but could be extended to other methods
typedef struct _mp_vfs_proto_t {
mp_import_stat_t (*import_stat)(void *self, const char *path);
} mp_vfs_proto_t;
typedef struct _mp_vfs_mount_t {
const char *str; // mount point with leading /
size_t len;
@ -63,6 +68,8 @@ typedef struct _mp_vfs_ilistdir_it_t {
bool is_iter;
} mp_vfs_ilistdir_it_t;
mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in);
mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out);
mp_import_stat_t mp_vfs_import_stat(const char *path);
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);

View File

@ -48,6 +48,21 @@
#define mp_obj_fat_vfs_t fs_user_mount_t
mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) {
fs_user_mount_t *vfs = vfs_in;
FILINFO fno;
assert(vfs != NULL);
FRESULT res = f_stat(&vfs->fatfs, path, &fno);
if (res == FR_OK) {
if ((fno.fattrib & AM_DIR) != 0) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
}
return MP_IMPORT_STAT_NO_EXIST;
}
STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -70,9 +85,28 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_
mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count);
}
// mount the block device so the VFS methods can be used
FRESULT res = f_mount(&vfs->fatfs);
if (res == FR_NO_FILESYSTEM) {
// don't error out if no filesystem, to let mkfs()/mount() create one if wanted
vfs->flags |= FSUSER_NO_FILESYSTEM;
} else if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return MP_OBJ_FROM_PTR(vfs);
}
#if _FS_REENTRANT
STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in);
// f_umount only needs to be called to release the sync object
f_umount(&self->fatfs);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del);
#endif
STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
// create new object
fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));
@ -89,7 +123,52 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj));
STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
typedef struct _mp_vfs_fat_ilistdir_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
bool is_str;
FF_DIR dir;
} mp_vfs_fat_ilistdir_it_t;
STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
for (;;) {
FILINFO fno;
FRESULT res = f_readdir(&self->dir, &fno);
char *fn = fno.fname;
if (res != FR_OK || fn[0] == 0) {
// stop on error or end of dir
break;
}
// Note that FatFS already filters . and .., so we don't need to
// make 4-tuple with info about this entry
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
if (self->is_str) {
t->items[0] = mp_obj_new_str(fn, strlen(fn));
} else {
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
}
if (fno.fattrib & AM_DIR) {
// dir
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
} else {
// file
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
}
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
t->items[3] = mp_obj_new_int_from_uint(fno.fsize);
return MP_OBJ_FROM_PTR(t);
}
// ignore error because we may be closing a second time
f_closedir(&self->dir);
return MP_OBJ_STOP_ITERATION;
}
STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]);
@ -104,7 +183,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
path = "";
}
return fat_vfs_ilistdir2(self, path, is_str_type);
// Create a new iterator object to list the dir
mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
iter->is_str = is_str_type;
FRESULT res = f_opendir(&self->fatfs, &iter->dir, path);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return MP_OBJ_FROM_PTR(iter);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func);
@ -198,7 +287,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return mp_obj_new_str(buf, strlen(buf), false);
return mp_obj_new_str(buf, strlen(buf));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
@ -292,10 +381,8 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
self->writeblocks[0] = MP_OBJ_NULL;
}
// mount the block device
FRESULT res = f_mount(&self->fatfs);
// check if we need to make the filesystem
FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;
if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {
uint8_t working_buf[_MAX_SS];
res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
@ -303,17 +390,15 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
self->flags &= ~FSUSER_NO_FILESYSTEM;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount);
STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) {
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
FRESULT res = f_umount(&self->fatfs);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
(void)self_in;
// keep the FAT filesystem mounted internally so the VFS methods can still be used
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount);
@ -326,11 +411,11 @@ STATIC mp_obj_t vfs_fat_getlabel(mp_obj_t self_in) {
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return mp_obj_new_str(working_buf, strlen(working_buf), false);
return mp_obj_new_str(working_buf, strlen(working_buf));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getlabel_obj, vfs_fat_getlabel);
static mp_obj_t vfs_fat_setlabel(mp_obj_t self_in, mp_obj_t label_in) {
STATIC mp_obj_t vfs_fat_setlabel(mp_obj_t self_in, mp_obj_t label_in) {
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
const char *label_str = mp_obj_str_get_str(label_in);
FRESULT res = f_setlabel(&self->fatfs, label_str);
@ -352,6 +437,9 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
#endif
STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
#if _FS_REENTRANT
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) },
@ -371,11 +459,17 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);
STATIC const mp_vfs_proto_t fat_vfs_proto = {
.import_stat = fat_vfs_import_stat,
};
const mp_obj_type_t mp_fat_vfs_type = {
{ &mp_type_type },
.name = MP_QSTR_VfsFat,
.make_new = fat_vfs_make_new,
.protocol = &fat_vfs_proto,
.locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict,
};
#endif // MICROPY_VFS_FAT

View File

@ -35,8 +35,9 @@
#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func
#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount
#define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl
#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it
// Device is writable over USB and read-only to MicroPython.
#define FSUSER_USB_WRITABLE (0x0008)
#define FSUSER_USB_WRITABLE (0x0010)
typedef struct _fs_user_mount_t {
mp_obj_base_t base;
@ -54,12 +55,19 @@ typedef struct _fs_user_mount_t {
FATFS fatfs;
} fs_user_mount_t;
typedef struct _pyb_file_obj_t {
mp_obj_base_t base;
FIL fp;
} pyb_file_obj_t;
extern const byte fresult_to_errno_table[20];
extern const mp_obj_type_t mp_fat_vfs_type;
extern const mp_obj_type_t mp_type_vfs_fat_fileio;
extern const mp_obj_type_t mp_type_vfs_fat_textio;
mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path);
mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode);
MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
mp_import_stat_t fat_vfs_import_stat(void *vfs, const char *path);
MP_DECLARE_CONST_FUN_OBJ_3(fat_vfs_open_obj);
mp_obj_t fat_vfs_ilistdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type);

View File

@ -36,6 +36,8 @@
#include "py/mphal.h"
#include "py/runtime.h"
#include "py/binary.h"
#include "py/objarray.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "extmod/vfs_fat.h"
@ -51,62 +53,6 @@ STATIC fs_user_mount_t *disk_get_device(void *bdev) {
return (fs_user_mount_t*)bdev;
}
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
STATIC
DSTATUS disk_initialize (
bdev_t pdrv /* Physical drive nmuber (0..) */
)
{
fs_user_mount_t *vfs = disk_get_device(pdrv);
if (vfs == NULL) {
return STA_NOINIT;
}
if (vfs->flags & FSUSER_HAVE_IOCTL) {
// new protocol with ioctl; call ioctl(INIT, 0)
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_INIT);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
// error initialising
return STA_NOINIT;
}
}
if (vfs->writeblocks[0] == MP_OBJ_NULL) {
return STA_PROTECT;
} else {
return 0;
}
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
STATIC
DSTATUS disk_status (
bdev_t pdrv /* Physical drive nmuber (0..) */
)
{
fs_user_mount_t *vfs = disk_get_device(pdrv);
if (vfs == NULL) {
return STA_NOINIT;
}
// This is used to determine the writeability of the disk from MicroPython.
// So, if its USB writable we make it read-only from MicroPython.
if (vfs->writeblocks[0] == MP_OBJ_NULL ||
(vfs->flags & FSUSER_USB_WRITABLE) != 0) {
return STA_PROTECT;
} else {
return 0;
}
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
@ -129,8 +75,9 @@ DRESULT disk_read (
return RES_ERROR;
}
} else {
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff};
vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff);
vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->readblocks);
@ -174,8 +121,9 @@ DRESULT disk_write (
return RES_ERROR;
}
} else {
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff};
vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff);
vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->writeblocks);
@ -208,54 +156,21 @@ DRESULT disk_ioctl (
return RES_PARERR;
}
// First part: call the relevant method of the underlying block device
mp_obj_t ret = mp_const_none;
if (vfs->flags & FSUSER_HAVE_IOCTL) {
// new protocol with ioctl
switch (cmd) {
case CTRL_SYNC:
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
mp_call_method_n_kw(2, 0, vfs->u.ioctl);
return RES_OK;
case GET_SECTOR_COUNT: {
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
*((DWORD*)buff) = mp_obj_get_int(ret);
return RES_OK;
}
case GET_SECTOR_SIZE: {
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
if (ret == mp_const_none) {
// Default sector size
*((WORD*)buff) = 512;
} else {
*((WORD*)buff) = mp_obj_get_int(ret);
}
#if _MAX_SS != _MIN_SS
// need to store ssize because we use it in disk_read/disk_write
vfs->fatfs.ssize = *((WORD*)buff);
#endif
return RES_OK;
}
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // erase block size in units of sector size
return RES_OK;
case IOCTL_INIT:
*((DSTATUS*)buff) = disk_initialize(pdrv);
return RES_OK;
case IOCTL_STATUS:
*((DSTATUS*)buff) = disk_status(pdrv);
return RES_OK;
default:
return RES_PARERR;
static const uint8_t op_map[8] = {
[CTRL_SYNC] = BP_IOCTL_SYNC,
[GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT,
[GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE,
[IOCTL_INIT] = BP_IOCTL_INIT,
};
uint8_t bp_op = op_map[cmd & 7];
if (bp_op != 0) {
vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op);
vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
}
} else {
// old protocol with sync and count
@ -264,38 +179,68 @@ DRESULT disk_ioctl (
if (vfs->u.old.sync[0] != MP_OBJ_NULL) {
mp_call_method_n_kw(0, 0, vfs->u.old.sync);
}
return RES_OK;
break;
case GET_SECTOR_COUNT: {
mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
*((DWORD*)buff) = mp_obj_get_int(ret);
return RES_OK;
}
case GET_SECTOR_COUNT:
ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
break;
case GET_SECTOR_SIZE:
*((WORD*)buff) = 512; // old protocol had fixed sector size
#if _MAX_SS != _MIN_SS
// need to store ssize because we use it in disk_read/disk_write
vfs->fatfs.ssize = 512;
#endif
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // erase block size in units of sector size
return RES_OK;
// old protocol has fixed sector size of 512 bytes
break;
case IOCTL_INIT:
*((DSTATUS*)buff) = disk_initialize(pdrv);
return RES_OK;
case IOCTL_STATUS:
*((DSTATUS*)buff) = disk_status(pdrv);
return RES_OK;
default:
return RES_PARERR;
// old protocol doesn't have init
break;
}
}
// Second part: convert the result for return
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT: {
*((DWORD*)buff) = mp_obj_get_int(ret);
return RES_OK;
}
case GET_SECTOR_SIZE: {
if (ret == mp_const_none) {
// Default sector size
*((WORD*)buff) = 512;
} else {
*((WORD*)buff) = mp_obj_get_int(ret);
}
#if _MAX_SS != _MIN_SS
// need to store ssize because we use it in disk_read/disk_write
vfs->fatfs.ssize = *((WORD*)buff);
#endif
return RES_OK;
}
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // erase block size in units of sector size
return RES_OK;
case IOCTL_INIT:
case IOCTL_STATUS: {
DSTATUS stat;
if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
// error initialising
stat = STA_NOINIT;
} else if (vfs->writeblocks[0] == MP_OBJ_NULL) {
stat = STA_PROTECT;
} else {
stat = 0;
}
*((DSTATUS*)buff) = stat;
return RES_OK;
}
default:
return RES_PARERR;
}
}
#endif // MICROPY_VFS && MICROPY_VFS_FAT

View File

@ -27,8 +27,6 @@
#include "py/mpconfig.h"
#if MICROPY_VFS && MICROPY_VFS_FAT
#include "extmod/vfs_fat_file.h"
#include <stdio.h>
#include "py/runtime.h"
@ -94,22 +92,9 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz
}
STATIC mp_obj_t file_obj_close(mp_obj_t self_in) {
pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
// if fs==NULL then the file is closed and in that case this method is a no-op
if (self->fp.obj.fs != NULL) {
FRESULT res = f_close(&self->fp);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close);
STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
return file_obj_close(args[0]);
return mp_stream_close(args[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__);
@ -144,6 +129,17 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
}
return 0;
} else if (request == MP_STREAM_CLOSE) {
// if fs==NULL then the file is closed and in that case this method is a no-op
if (self->fp.obj.fs != NULL) {
FRESULT res = f_close(&self->fp);
if (res != FR_OK) {
*errcode = fresult_to_errno_table[res];
return MP_STREAM_ERROR;
}
}
return 0;
} else {
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
@ -182,11 +178,11 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar
break;
#if MICROPY_PY_IO_FILEIO
case 'b':
type = &mp_type_fileio;
type = &mp_type_vfs_fat_fileio;
break;
#endif
case 't':
type = &mp_type_textio;
type = &mp_type_vfs_fat_textio;
break;
}
}
@ -225,10 +221,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&file_obj_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
};
@ -242,7 +238,7 @@ STATIC const mp_stream_p_t fileio_stream_p = {
.ioctl = file_obj_ioctl,
};
const mp_obj_type_t mp_type_fileio = {
const mp_obj_type_t mp_type_vfs_fat_fileio = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.print = file_obj_print,
@ -261,7 +257,7 @@ STATIC const mp_stream_p_t textio_stream_p = {
.is_text = true,
};
const mp_obj_type_t mp_type_textio = {
const mp_obj_type_t mp_type_vfs_fat_textio = {
{ &mp_type_type },
.name = MP_QSTR_TextIOWrapper,
.print = file_obj_print,
@ -273,14 +269,15 @@ const mp_obj_type_t mp_type_textio = {
};
// Factory function for I/O stream classes
mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
// TODO: analyze buffering args and instantiate appropriate type
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
arg_vals[0].u_obj = path;
arg_vals[1].u_obj = mode;
arg_vals[2].u_obj = mp_const_none;
return file_open(self, &mp_type_textio, arg_vals);
return file_open(self, &mp_type_vfs_fat_textio, arg_vals);
}
MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
#endif // MICROPY_VFS && MICROPY_VFS_FAT

View File

@ -1,108 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mpconfig.h"
#if MICROPY_VFS_FAT
#include <string.h>
#include "py/runtime.h"
#include "lib/oofatfs/ff.h"
#include "extmod/vfs_fat.h"
#include "py/lexer.h"
typedef struct _mp_vfs_fat_ilistdir_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
bool is_str;
FF_DIR dir;
} mp_vfs_fat_ilistdir_it_t;
STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
for (;;) {
FILINFO fno;
FRESULT res = f_readdir(&self->dir, &fno);
char *fn = fno.fname;
if (res != FR_OK || fn[0] == 0) {
// stop on error or end of dir
break;
}
// Note that FatFS already filters . and .., so we don't need to
// make 3-tuple with info about this entry
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
if (self->is_str) {
t->items[0] = mp_obj_new_str(fn, strlen(fn), false);
} else {
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
}
if (fno.fattrib & AM_DIR) {
// dir
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
} else {
// file
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
}
t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
return MP_OBJ_FROM_PTR(t);
}
// ignore error because we may be closing a second time
f_closedir(&self->dir);
return MP_OBJ_STOP_ITERATION;
}
mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) {
mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
iter->is_str = is_str_type;
FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path);
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
return MP_OBJ_FROM_PTR(iter);
}
mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) {
FILINFO fno;
assert(vfs != NULL);
FRESULT res = f_stat(&vfs->fatfs, path, &fno);
if (res == FR_OK) {
if ((fno.fattrib & AM_DIR) != 0) {
return MP_IMPORT_STAT_DIR;
} else {
return MP_IMPORT_STAT_FILE;
}
}
return MP_IMPORT_STAT_NO_EXIST;
}
#endif // MICROPY_VFS_FAT

363
extmod/vfs_posix.c Normal file
View File

@ -0,0 +1,363 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "py/mperrno.h"
#include "extmod/vfs.h"
#include "extmod/vfs_posix.h"
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
typedef struct _mp_obj_vfs_posix_t {
mp_obj_base_t base;
vstr_t root;
size_t root_len;
bool readonly;
} mp_obj_vfs_posix_t;
STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) {
if (self->root_len == 0) {
return mp_obj_str_get_str(path);
} else {
self->root.len = self->root_len;
vstr_add_str(&self->root, mp_obj_str_get_str(path));
return vstr_null_terminated_str(&self->root);
}
}
STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) {
if (self->root_len == 0) {
return path;
} else {
self->root.len = self->root_len;
vstr_add_str(&self->root, mp_obj_str_get_str(path));
return mp_obj_new_str(self->root.buf, self->root.len);
}
}
STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
int ret = f(vfs_posix_get_path_str(self, path_in));
if (ret != 0) {
mp_raise_OSError(errno);
}
return mp_const_none;
}
STATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) {
mp_obj_vfs_posix_t *self = self_in;
if (self->root_len != 0) {
self->root.len = self->root_len;
vstr_add_str(&self->root, path);
path = vstr_null_terminated_str(&self->root);
}
struct stat st;
if (stat(path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
return MP_IMPORT_STAT_DIR;
} else if (S_ISREG(st.st_mode)) {
return MP_IMPORT_STAT_FILE;
}
}
return MP_IMPORT_STAT_NO_EXIST;
}
STATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t);
vfs->base.type = type;
vstr_init(&vfs->root, 0);
if (n_args == 1) {
vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0]));
vstr_add_char(&vfs->root, '/');
}
vfs->root_len = vfs->root.len;
vfs->readonly = false;
return MP_OBJ_FROM_PTR(vfs);
}
STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
if (mp_obj_is_true(readonly)) {
self->readonly = true;
}
if (mp_obj_is_true(mkfs)) {
mp_raise_OSError(MP_EPERM);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount);
STATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) {
(void)self_in;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount);
STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *mode = mp_obj_str_get_str(mode_in);
if (self->readonly
&& (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) {
mp_raise_OSError(MP_EROFS);
}
if (!MP_OBJ_IS_SMALL_INT(path_in)) {
path_in = vfs_posix_get_path_obj(self, path_in);
}
return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open);
STATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) {
return vfs_posix_fun1_helper(self_in, path_in, chdir);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir);
STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
char buf[MICROPY_ALLOC_PATH_MAX + 1];
const char *ret = getcwd(buf, sizeof(buf));
if (ret == NULL) {
mp_raise_OSError(errno);
}
ret += self->root_len;
return mp_obj_new_str(ret, strlen(ret));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd);
typedef struct _vfs_posix_ilistdir_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
bool is_str;
DIR *dir;
} vfs_posix_ilistdir_it_t;
STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {
vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
if (self->dir == NULL) {
return MP_OBJ_STOP_ITERATION;
}
for (;;) {
struct dirent *dirent = readdir(self->dir);
if (dirent == NULL) {
closedir(self->dir);
self->dir = NULL;
return MP_OBJ_STOP_ITERATION;
}
const char *fn = dirent->d_name;
if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
// skip . and ..
continue;
}
// make 3-tuple with info about this entry
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
if (self->is_str) {
t->items[0] = mp_obj_new_str(fn, strlen(fn));
} else {
t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
}
#ifdef _DIRENT_HAVE_D_TYPE
if (dirent->d_type == DT_DIR) {
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
} else if (dirent->d_type == DT_REG) {
t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
} else {
t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type);
}
#else
// DT_UNKNOWN should have 0 value on any reasonable system
t->items[1] = MP_OBJ_NEW_SMALL_INT(0);
#endif
#ifdef _DIRENT_HAVE_D_INO
t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino);
#else
t->items[2] = MP_OBJ_NEW_SMALL_INT(0);
#endif
return MP_OBJ_FROM_PTR(t);
}
}
STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t);
iter->base.type = &mp_type_polymorph_iter;
iter->iternext = vfs_posix_ilistdir_it_iternext;
iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;
const char *path = vfs_posix_get_path_str(self, path_in);
iter->dir = opendir(path);
if (iter->dir == NULL) {
mp_raise_OSError(errno);
}
return MP_OBJ_FROM_PTR(iter);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir);
typedef struct _mp_obj_listdir_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
DIR *dir;
} mp_obj_listdir_t;
STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777);
if (ret != 0) {
mp_raise_OSError(errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir);
STATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) {
return vfs_posix_fun1_helper(self_in, path_in, unlink);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove);
STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
int ret = rename(old_path, new_path);
if (ret != 0) {
mp_raise_OSError(errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);
STATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) {
return vfs_posix_fun1_helper(self_in, path_in, rmdir);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);
STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
struct stat sb;
int ret = stat(vfs_posix_get_path_str(self, path_in), &sb);
if (ret != 0) {
mp_raise_OSError(errno);
}
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);
t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev);
t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink);
t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid);
t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid);
t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size);
t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime);
t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime);
t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime);
return MP_OBJ_FROM_PTR(t);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
#ifdef __ANDROID__
#define USE_STATFS 1
#endif
#if USE_STATFS
#include <sys/vfs.h>
#define STRUCT_STATVFS struct statfs
#define STATVFS statfs
#define F_FAVAIL sb.f_ffree
#define F_NAMEMAX sb.f_namelen
#define F_FLAG sb.f_flags
#else
#include <sys/statvfs.h>
#define STRUCT_STATVFS struct statvfs
#define STATVFS statvfs
#define F_FAVAIL sb.f_favail
#define F_NAMEMAX sb.f_namemax
#define F_FLAG sb.f_flag
#endif
STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
STRUCT_STATVFS sb;
const char *path = vfs_posix_get_path_str(self, path_in);
int ret = STATVFS(path, &sb);
if (ret != 0) {
mp_raise_OSError(errno);
}
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);
t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks);
t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree);
t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail);
t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files);
t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree);
t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL);
t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG);
t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX);
return MP_OBJ_FROM_PTR(t);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs);
STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) },
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) },
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) },
{ MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) },
{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) },
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) },
};
STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table);
STATIC const mp_vfs_proto_t vfs_posix_proto = {
.import_stat = mp_vfs_posix_import_stat,
};
const mp_obj_type_t mp_type_vfs_posix = {
{ &mp_type_type },
.name = MP_QSTR_VfsPosix,
.make_new = vfs_posix_make_new,
.protocol = &vfs_posix_proto,
.locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict,
};
#endif // MICROPY_VFS_POSIX

View File

@ -1,9 +1,9 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2018 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
@ -23,28 +23,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
#ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H
#define MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H
#include "py/lexer.h"
#include "py/mpconfig.h"
#if MICROPY_VFS && MICROPY_VFS_FAT
#include "lib/oofatfs/ff.h"
#include "py/obj.h"
#define mp_type_fileio fatfs_type_fileio
#define mp_type_textio fatfs_type_textio
extern const mp_obj_type_t mp_type_vfs_posix;
extern const mp_obj_type_t mp_type_vfs_posix_fileio;
extern const mp_obj_type_t mp_type_vfs_posix_textio;
extern const mp_obj_type_t mp_type_fileio;
extern const mp_obj_type_t mp_type_textio;
mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in);
typedef struct _pyb_file_obj_t {
mp_obj_base_t base;
FIL fp;
} pyb_file_obj_t;
#endif // MICROPY_VFS && MICROPY_VFS_FAT
#endif // MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H
#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H

261
extmod/vfs_posix_file.c Normal file
View File

@ -0,0 +1,261 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2018 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "py/stream.h"
#include "extmod/vfs_posix.h"
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX
#include <fcntl.h>
#ifdef _WIN32
#define fsync _commit
#endif
typedef struct _mp_obj_vfs_posix_file_t {
mp_obj_base_t base;
int fd;
} mp_obj_vfs_posix_file_t;
#ifdef MICROPY_CPYTHON_COMPAT
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
if (o->fd < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file"));
}
}
#else
#define check_fd_is_open(o)
#endif
STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<io.%s %d>", mp_obj_get_type_str(self_in), self->fd);
}
mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) {
mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t);
const char *mode_s = mp_obj_str_get_str(mode_in);
int mode_rw = 0, mode_x = 0;
while (*mode_s) {
switch (*mode_s++) {
case 'r':
mode_rw = O_RDONLY;
break;
case 'w':
mode_rw = O_WRONLY;
mode_x = O_CREAT | O_TRUNC;
break;
case 'a':
mode_rw = O_WRONLY;
mode_x = O_CREAT | O_APPEND;
break;
case '+':
mode_rw = O_RDWR;
break;
#if MICROPY_PY_IO_FILEIO
// If we don't have io.FileIO, then files are in text mode implicitly
case 'b':
type = &mp_type_vfs_posix_fileio;
break;
case 't':
type = &mp_type_vfs_posix_textio;
break;
#endif
}
}
o->base.type = type;
mp_obj_t fid = file_in;
if (MP_OBJ_IS_SMALL_INT(fid)) {
o->fd = MP_OBJ_SMALL_INT_VALUE(fid);
return MP_OBJ_FROM_PTR(o);
}
const char *fname = mp_obj_str_get_str(fid);
int fd = open(fname, mode_x | mode_rw, 0644);
if (fd == -1) {
mp_raise_OSError(errno);
}
o->fd = fd;
return MP_OBJ_FROM_PTR(o);
}
STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
};
mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals);
return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj);
}
STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) {
mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);
check_fd_is_open(self);
return MP_OBJ_NEW_SMALL_INT(self->fd);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno);
STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
return mp_stream_close(args[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__);
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
mp_int_t r = read(o->fd, buf, size);
if (r == -1) {
*errcode = errno;
return MP_STREAM_ERROR;
}
return r;
}
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
#if MICROPY_PY_OS_DUPTERM
if (o->fd <= STDERR_FILENO) {
mp_hal_stdout_tx_strn(buf, size);
return size;
}
#endif
mp_int_t r = write(o->fd, buf, size);
while (r == -1 && errno == EINTR) {
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
}
r = write(o->fd, buf, size);
}
if (r == -1) {
*errcode = errno;
return MP_STREAM_ERROR;
}
return r;
}
STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
switch (request) {
case MP_STREAM_FLUSH:
if (fsync(o->fd) < 0) {
*errcode = errno;
return MP_STREAM_ERROR;
}
return 0;
case MP_STREAM_SEEK: {
struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg;
off_t off = lseek(o->fd, s->offset, s->whence);
if (off == (off_t)-1) {
*errcode = errno;
return MP_STREAM_ERROR;
}
s->offset = off;
return 0;
}
case MP_STREAM_CLOSE:
close(o->fd);
#ifdef MICROPY_CPYTHON_COMPAT
o->fd = -1;
#endif
return 0;
default:
*errcode = EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC const mp_rom_map_elem_t 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) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
};
STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
#if MICROPY_PY_IO_FILEIO
STATIC const mp_stream_p_t fileio_stream_p = {
.read = vfs_posix_file_read,
.write = vfs_posix_file_write,
.ioctl = vfs_posix_file_ioctl,
};
const mp_obj_type_t mp_type_vfs_posix_fileio = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.print = vfs_posix_file_print,
.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,
};
#endif
STATIC const mp_stream_p_t textio_stream_p = {
.read = vfs_posix_file_read,
.write = vfs_posix_file_write,
.ioctl = vfs_posix_file_ioctl,
.is_text = true,
};
const mp_obj_type_t mp_type_vfs_posix_textio = {
{ &mp_type_type },
.name = MP_QSTR_TextIOWrapper,
.print = vfs_posix_file_print,
.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,
};
const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
#endif // MICROPY_VFS_POSIX

View File

@ -71,7 +71,7 @@ STATIC void mp_reader_vfs_close(void *data) {
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false);
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));
rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map);
int errcode;
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);

@ -1 +1 @@
Subproject commit dac9176cac58cc5e49669a9a4d404a6f6dd7cc10
Subproject commit 43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0

View File

@ -41,7 +41,7 @@ mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) {
} else {
ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
}
return mp_obj_new_str(ip_str, ip_len, false);
return mp_obj_new_str(ip_str, ip_len);
}
// Takes an array with a raw IP address, and a port, and returns a net-address

View File

@ -2579,8 +2579,8 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create
if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */
lfn[di++] = w; /* Store the Unicode character */
}
cf = ((w < ' ') || ((w == '/' || w == '\\') && p[si+1] < ' ')) ? NS_LAST : 0; /* Set last segment flag if end of the path */
*path = &p[si]; /* Return pointer to the next segment */
cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
#if _FS_RPATH != 0
if ((di == 1 && lfn[di - 1] == '.') ||
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */

View File

@ -234,8 +234,9 @@ testcase_run_one(const struct testgroup_t *group,
return SKIP;
}
printf("# starting %s%s\n", group->prefix, testcase->name);
if (opt_verbosity>0 && !opt_forked) {
printf("%s%s: ", group->prefix, testcase->name);
//printf("%s%s: ", group->prefix, testcase->name);
} else {
if (opt_verbosity==0) printf(".");
cur_test_prefix = group->prefix;
@ -252,6 +253,7 @@ testcase_run_one(const struct testgroup_t *group,
outcome = testcase_run_bare_(testcase);
}
printf("%s%s: ", group->prefix, testcase->name);
if (outcome == OK) {
++n_ok;
if (opt_verbosity>0 && !opt_forked)
@ -263,7 +265,8 @@ testcase_run_one(const struct testgroup_t *group,
} else {
++n_bad;
if (!opt_forked)
printf("\n [%s FAILED]\n", testcase->name);
//printf("\n [%s FAILED]\n", testcase->name);
puts("FAILED");
}
if (opt_forked) {

View File

@ -0,0 +1,126 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Linaro Limited
*
* 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/mphal.h"
#include "py/gc.h"
#include "py/runtime.h"
#include "py/compile.h"
#include "upytesthelper.h"
static const char *test_exp_output;
static int test_exp_output_len, test_rem_output_len;
static int test_failed;
static void *heap_start, *heap_end;
void upytest_set_heap(void *start, void *end) {
heap_start = start;
heap_end = end;
}
void upytest_set_expected_output(const char *output, unsigned len) {
test_exp_output = output;
test_exp_output_len = test_rem_output_len = len;
test_failed = false;
}
bool upytest_is_failed(void) {
if (test_failed) {
return true;
}
#if 0
if (test_rem_output_len != 0) {
printf("remaining len: %d\n", test_rem_output_len);
}
#endif
return test_rem_output_len != 0;
}
// MP_PLAT_PRINT_STRN() should be redirected to this function.
// It will pass-thru any content to mp_hal_stdout_tx_strn_cooked()
// (the dfault value of MP_PLAT_PRINT_STRN), but will also match
// it to the expected output as set by upytest_set_expected_output().
// If mismatch happens, upytest_is_failed() returns true.
void upytest_output(const char *str, mp_uint_t len) {
if (!test_failed) {
if (len > test_rem_output_len) {
test_failed = true;
} else {
test_failed = memcmp(test_exp_output, str, len);
#if 0
if (test_failed) {
printf("failed after char %u, within %d chars, res: %d\n",
test_exp_output_len - test_rem_output_len, (int)len, test_failed);
for (int i = 0; i < len; i++) {
if (str[i] != test_exp_output[i]) {
printf("%d %02x %02x\n", i, str[i], test_exp_output[i]);
}
}
}
#endif
test_exp_output += len;
test_rem_output_len -= len;
}
}
mp_hal_stdout_tx_strn_cooked(str, len);
}
void upytest_execute_test(const char *src) {
// To provide clean room for each test, interpreter and heap are
// reinitialized before running each.
gc_init(heap_start, heap_end);
mp_init();
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_init(mp_sys_argv, 0);
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
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_call_function_0(module_fun);
nlr_pop();
} else {
mp_obj_t exc = (mp_obj_t)nlr.ret_val;
if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) {
// Assume that sys.exit() is called to skip the test.
// TODO: That can be always true, we should set up convention to
// use specific exit code as skip indicator.
tinytest_set_test_skipped_();
goto end;
}
mp_obj_print_exception(&mp_plat_print, exc);
tt_abort_msg("Uncaught exception\n");
}
if (upytest_is_failed()) {
tinytest_set_test_failed_();
}
end:
mp_deinit();
}

View File

@ -0,0 +1,37 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Linaro Limited
*
* 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 <stdbool.h>
#include <stdio.h>
#include "py/mpconfig.h"
#include "lib/tinytest/tinytest.h"
#include "lib/tinytest/tinytest_macros.h"
void upytest_set_heap(void *start, void *end);
void upytest_set_expected_output(const char *output, unsigned len);
void upytest_execute_test(const char *src);
void upytest_output(const char *str, mp_uint_t len);
bool upytest_is_failed(void);

View File

@ -36,7 +36,7 @@
#include "py/gc_long_lived.h"
#include "py/frozenmod.h"
#include "py/mphal.h"
#if defined(USE_DEVICE_MODE)
#if MICROPY_HW_ENABLE_USB
#include "irq.h"
#include "usb.h"
#endif
@ -431,7 +431,7 @@ friendly_repl_reset:
for (;;) {
input_restart:
#if defined(USE_DEVICE_MODE)
#if MICROPY_HW_ENABLE_USB
if (usb_vcp_is_enabled()) {
// If the user gets to here and interrupts are disabled then
// they'll never see the prompt, traceback etc. The USB REPL needs

View File

@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
#define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
#include "py/obj.h"
typedef enum {
PYEXEC_MODE_RAW_REPL,
PYEXEC_MODE_FRIENDLY_REPL,

View File

@ -27,7 +27,7 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H
#define MICROPY_INCLUDED_ATMEL_SAMD_AUDIO_DMA_H
#include "extmod/vfs_fat_file.h"
#include "extmod/vfs_fat.h"
#include "py/obj.h"
#include "shared-module/audioio/RawSample.h"
#include "shared-module/audioio/WaveFile.h"

View File

@ -0,0 +1,38 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* 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 "boards/board.h"
void board_init(void)
{
}
bool board_requests_safe_mode(void) {
return false;
}
void reset_board(void) {
}

View File

@ -0,0 +1,63 @@
#define MICROPY_HW_BOARD_NAME "HalloWing M0 Express"
#define MICROPY_HW_MCU_NAME "samd21g18"
#define MICROPY_HW_NEOPIXEL (&pin_PA12)
// Clock rates are off: Salae reads 12MHz which is the limit even though we set it to the safer 8MHz.
#define SPI_FLASH_BAUDRATE (8000000)
#define SPI_FLASH_MOSI_PIN PIN_PB10
#define SPI_FLASH_MISO_PIN PIN_PA13
#define SPI_FLASH_SCK_PIN PIN_PB11
#define SPI_FLASH_CS_PIN PIN_PA07
#define SPI_FLASH_MOSI_PIN_FUNCTION PINMUX_PB10D_SERCOM4_PAD2
#define SPI_FLASH_MISO_PIN_FUNCTION PINMUX_PA13D_SERCOM4_PAD1
#define SPI_FLASH_SCK_PIN_FUNCTION PINMUX_PB11D_SERCOM4_PAD3
#define SPI_FLASH_SERCOM SERCOM4
#define SPI_FLASH_SERCOM_INDEX 4
#define SPI_FLASH_MOSI_PAD 2
#define SPI_FLASH_MISO_PAD 1
#define SPI_FLASH_SCK_PAD 3
// <o> Transmit Data Pinout
// <0x0=>PAD[0,1]_DO_SCK
// <0x1=>PAD[2,3]_DO_SCK
// <0x2=>PAD[3,1]_DO_SCK
// <0x3=>PAD[0,3]_DO_SCK
#define SPI_FLASH_DOPO 0x1
#define SPI_FLASH_DIPO 1 // same as MISO pad
// These are pins not to reset.
#define MICROPY_PORT_A (PORT_PA07 | PORT_PA12 | PORT_PA13 | PORT_PA24 | PORT_PA25)
#define MICROPY_PORT_B ( PORT_PB10 | PORT_PB11 )
#define MICROPY_PORT_C ( 0 )
#include "external_flash/external_flash.h"
// If you change this, then make sure to update the linker scripts as well to
// make sure you don't overwrite code.
#define CIRCUITPY_INTERNAL_NVM_SIZE 256
#define BOARD_FLASH_SIZE (0x00040000 - 0x2000 - CIRCUITPY_INTERNAL_NVM_SIZE)
#include "external_flash/devices.h"
#define EXTERNAL_FLASH_DEVICE_COUNT 2
#define EXTERNAL_FLASH_DEVICES W25Q64JV_IM, \
GD25Q64C
#include "external_flash/external_flash.h"
#define DEFAULT_I2C_BUS_SCL (&pin_PA17)
#define DEFAULT_I2C_BUS_SDA (&pin_PA16)
#define DEFAULT_SPI_BUS_SCK (&pin_PB23)
#define DEFAULT_SPI_BUS_MOSI (&pin_PB22)
#define DEFAULT_SPI_BUS_MISO (&pin_PB03)
#define DEFAULT_UART_BUS_RX (&pin_PA09)
#define DEFAULT_UART_BUS_TX (&pin_PA10)
// USB is always used internally so skip the pin objects for it.
#define IGNORE_PIN_PA24 1
#define IGNORE_PIN_PA25 1

View File

@ -0,0 +1,17 @@
LD_FILE = boards/samd21x18-bootloader-external-flash.ld
USB_VID = 0x239A
USB_PID = 0xD1ED
USB_PRODUCT = "HalloWing M0 Express"
USB_MANUFACTURER = "Adafruit Industries LLC"
SPI_FLASH_FILESYSTEM = 1
LONGINT_IMPL = MPZ
CHIP_VARIANT = SAMD21G18A
CHIP_FAMILY = samd21
# Include these Python libraries in firmware.
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_LIS3DH
FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel

View File

@ -0,0 +1,60 @@
#include "shared-bindings/board/__init__.h"
#include "board_busses.h"
STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },
{ MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_PA02) },
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB08) },
{ MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_PB08) },
{ MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB09) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH4), MP_ROM_PTR(&pin_PB09) },
{ MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PA04) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH3), MP_ROM_PTR(&pin_PA04) },
{ MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PA05) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH2), MP_ROM_PTR(&pin_PA05) },
{ MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PA06) },
{ MP_ROM_QSTR(MP_QSTR_TOUCH1), MP_ROM_PTR(&pin_PA06) },
{ MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB23) },
{ MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB22) },
{ MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB03) },
{ MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA09) },
{ MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA09) },
{ MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA10) },
{ MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) },
{ MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA16) },
{ MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA17) },
{ MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PA15) },
{ MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PA18) },
{ MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PA19) },
{ MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA20) },
{ MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA21) },
{ MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA22) },
{ MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA23) },
{ MP_ROM_QSTR(MP_QSTR_EXTERNAL_NEOPIXEL), MP_ROM_PTR(&pin_PA08) },
{ MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PA12) },
{ MP_ROM_QSTR(MP_QSTR_SENSE), MP_ROM_PTR(&pin_PA11) },
{ MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_PA00) },
{ MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_PA01) },
{ MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_PA28) },
{ MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_PA27) },
{ MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_PB02) },
{ MP_ROM_QSTR(MP_QSTR_ACCELEROMETER_INTERRUPT), MP_ROM_PTR(&pin_PA14) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

View File

@ -27,7 +27,7 @@
#include <stdint.h>
#include <string.h>
#include "extmod/vfs_fat_file.h"
#include "extmod/vfs_fat.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/runtime.h"

View File

@ -29,7 +29,7 @@
#include "common-hal/microcontroller/Pin.h"
#include "extmod/vfs_fat_file.h"
#include "extmod/vfs_fat.h"
#include "py/obj.h"
typedef struct {

View File

@ -27,7 +27,7 @@
#include <stdint.h>
#include <string.h>
#include "extmod/vfs_fat_file.h"
#include "extmod/vfs_fat.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/runtime.h"

View File

@ -89,6 +89,22 @@ typedef struct {
.supports_qspi_writes = true, \
}
// Settings for the Gigadevice GD25Q64C 8MiB SPI flash.
// Datasheet: http://www.elm-tech.com/en/products/spi-flash-memory/gd25q64/gd25q64.pdf
#define GD25Q64C {\
.total_size = (1 << 23), /* 8 MiB */ \
.start_up_time_us = 5000, \
.manufacturer_id = 0xc8, \
.memory_type = 0x40, \
.capacity = 0x17, \
.max_clock_speed_mhz = 104, /* if we need 120 then we can turn on high performance mode */ \
.has_sector_protection = false, \
.supports_fast_read = true, \
.supports_qspi = true, \
.has_quad_enable = true, \
.supports_qspi_writes = true, \
}
// Settings for the Cypress (was Spansion) S25FL064L 8MiB SPI flash.
// Datasheet: http://www.cypress.com/file/316661/download
#define S25FL064L {\
@ -185,6 +201,22 @@ typedef struct {
.supports_qspi_writes = false, \
}
// Settings for the Winbond W25Q64JV-IM 8MiB SPI flash. Note that JV-IQ has a different .memory_type (0x40)
// Datasheet: http://www.winbond.com/resource-files/w25q64jv%20revj%2003272018%20plus.pdf
#define W25Q64JV_IM {\
.total_size = (1 << 23), /* 8 MiB */ \
.start_up_time_us = 5000, \
.manufacturer_id = 0xef, \
.memory_type = 0x70, \
.capacity = 0x17, \
.max_clock_speed_mhz = 133, \
.has_sector_protection = false, \
.supports_fast_read = true, \
.supports_qspi = true, \
.has_quad_enable = true, \
.supports_qspi_writes = true, \
}
// Settings for the Winbond W25Q80DL 1MiB SPI flash.
// Datasheet: https://www.winbond.com/resource-files/w25q80dv%20dl_revh_10022015.pdf
#define W25Q80DL {\
@ -201,4 +233,6 @@ typedef struct {
.supports_qspi_writes = false, \
}
#endif // MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H

View File

@ -123,6 +123,9 @@ typedef long mp_off_t;
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
#define mp_type_fileio mp_type_vfs_fat_fileio
#define mp_type_textio mp_type_vfs_fat_textio
#define mp_import_stat mp_vfs_import_stat
#define mp_builtin_open_obj mp_vfs_open_obj

View File

@ -36,7 +36,7 @@ SRC_S = \
# startup_stm32f40xx.s \
gchelper.s \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o) $(SRC_S:.s=.o))
all: $(BUILD)/firmware.elf

View File

@ -336,6 +336,9 @@ STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp
if (SL_FD_ISSET(sd, &xfds)) {
ret |= MP_STREAM_POLL_HUP;
}
} else if (request == MP_STREAM_CLOSE) {
wlan_socket_close(s);
ret = 0;
} else {
*_errno = MP_EINVAL;
ret = MP_STREAM_ERROR;
@ -466,14 +469,6 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
return s;
}
// method socket.close()
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
mod_network_socket_obj_t *self = self_in;
wlan_socket_close(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
// method socket.bind(address)
STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
mod_network_socket_obj_t *self = self_in;
@ -704,8 +699,8 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },

View File

@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
#define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
#include "py/stream.h"
extern const mp_obj_dict_t socket_locals_dict;
extern const mp_stream_p_t socket_stream_p;

View File

@ -886,7 +886,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) {
}
mp_obj_t tuple[5];
tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false);
tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len);
tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH);
// 'normalize' the security type
if (wlanEntry.sec_type > 2) {
@ -1076,7 +1076,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode);
STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) {
wlan_obj_t *self = args[0];
if (n_args == 1) {
return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false);
return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid));
} else {
size_t len;
const char *ssid = mp_obj_str_get_data(args[1], &len);
@ -1096,7 +1096,7 @@ STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) {
} else {
mp_obj_t security[2];
security[0] = mp_obj_new_int(self->auth);
security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false);
security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key));
return mp_obj_new_tuple(2, security);
}
} else {
@ -1200,7 +1200,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
// mp_obj_t connections = mp_obj_new_list(0, NULL);
//
// if (wlan_is_connected()) {
// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false);
// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o));
// device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH);
// // add the device to the list
// mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device));
@ -1233,7 +1233,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq);
// if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) {
// mp_raise_OSError(MP_EIO);
// }
// return mp_obj_new_str(urn, (len - 1), false);
// return mp_obj_new_str(urn, (len - 1));
// }
//
// return mp_const_none;

View File

@ -131,8 +131,8 @@
X(ETIMEDOUT) \
// TODO these should be generic, not bound to fatfs
#define mp_type_fileio fatfs_type_fileio
#define mp_type_textio fatfs_type_textio
#define mp_type_fileio mp_type_vfs_fat_fileio
#define mp_type_textio mp_type_vfs_fat_textio
// use vfs's functions for import stat and builtin open
#define mp_import_stat mp_vfs_import_stat

786
ports/esp32/Makefile Normal file
View File

@ -0,0 +1,786 @@
include ../../py/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
MICROPY_PY_USSL = 0
MICROPY_SSL_AXTLS = 0
MICROPY_FATFS = 1
MICROPY_PY_BTREE = 1
#FROZEN_DIR = scripts
FROZEN_MPY_DIR = modules
# include py core make definitions
include $(TOP)/py/py.mk
PORT ?= /dev/ttyUSB0
BAUD ?= 460800
FLASH_MODE ?= dio
FLASH_FREQ ?= 40m
FLASH_SIZE ?= 4MB
CROSS_COMPILE ?= xtensa-esp32-elf-
ESPIDF_SUPHASH := 9a55b42f0841b3d38a61089b1dda4bf28135decd
# paths to ESP IDF and its components
ifeq ($(ESPIDF),)
ifneq ($(IDF_PATH),)
ESPIDF = $(IDF_PATH)
else
$(info The ESPIDF variable has not been set, please set it to the root of the esp-idf repository.)
$(info See README.md for installation instructions.)
$(info Supported git hash: $(ESPIDF_SUPHASH))
$(error ESPIDF not set)
endif
endif
ESPCOMP = $(ESPIDF)/components
ESPTOOL ?= $(ESPCOMP)/esptool_py/esptool/esptool.py
# verify the ESP IDF version
ESPIDF_CURHASH := $(shell git -C $(ESPIDF) show -s --pretty=format:'%H')
ifneq ($(ESPIDF_CURHASH),$(ESPIDF_SUPHASH))
$(info ** WARNING **)
$(info The git hash of ESP IDF does not match the supported version)
$(info The build may complete and the firmware may work but it is not guaranteed)
$(info ESP IDF path: $(ESPIDF))
$(info Current git hash: $(ESPIDF_CURHASH))
$(info Supported git hash: $(ESPIDF_SUPHASH))
endif
# pretty format of ESP IDF version, used internally by the IDF
IDF_VER := $(shell git -C $(ESPIDF) describe)
INC += -I.
INC += -I$(TOP)
INC += -I$(TOP)/lib/mp-readline
INC += -I$(TOP)/lib/netutils
INC += -I$(TOP)/lib/timeutils
INC += -I$(BUILD)
INC_ESPCOMP += -I$(ESPCOMP)/bootloader_support/include
INC_ESPCOMP += -I$(ESPCOMP)/driver/include
INC_ESPCOMP += -I$(ESPCOMP)/driver/include/driver
INC_ESPCOMP += -I$(ESPCOMP)/nghttp/port/include
INC_ESPCOMP += -I$(ESPCOMP)/nghttp/nghttp2/lib/includes
INC_ESPCOMP += -I$(ESPCOMP)/esp32/include
INC_ESPCOMP += -I$(ESPCOMP)/soc/include
INC_ESPCOMP += -I$(ESPCOMP)/soc/esp32/include
INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include
INC_ESPCOMP += -I$(ESPCOMP)/expat/include/expat
INC_ESPCOMP += -I$(ESPCOMP)/expat/port/include
INC_ESPCOMP += -I$(ESPCOMP)/heap/include
INC_ESPCOMP += -I$(ESPCOMP)/json/include
INC_ESPCOMP += -I$(ESPCOMP)/json/port/include
INC_ESPCOMP += -I$(ESPCOMP)/log/include
INC_ESPCOMP += -I$(ESPCOMP)/newlib/include
INC_ESPCOMP += -I$(ESPCOMP)/nvs_flash/include
INC_ESPCOMP += -I$(ESPCOMP)/freertos/include
INC_ESPCOMP += -I$(ESPCOMP)/tcpip_adapter/include
INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip
INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/port
INC_ESPCOMP += -I$(ESPCOMP)/lwip/include/lwip/posix
INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/mbedtls/include
INC_ESPCOMP += -I$(ESPCOMP)/mbedtls/port/include
INC_ESPCOMP += -I$(ESPCOMP)/spi_flash/include
INC_ESPCOMP += -I$(ESPCOMP)/ulp/include
INC_ESPCOMP += -I$(ESPCOMP)/vfs/include
INC_ESPCOMP += -I$(ESPCOMP)/newlib/platform_include
INC_ESPCOMP += -I$(ESPCOMP)/xtensa-debug-module/include
INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/include
INC_ESPCOMP += -I$(ESPCOMP)/wpa_supplicant/port/include
INC_ESPCOMP += -I$(ESPCOMP)/ethernet/include
INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include
INC_ESPCOMP += -I$(ESPCOMP)/app_update/include
INC_ESPCOMP += -I$(ESPCOMP)/pthread/include
INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include
# these flags are common to C and C++ compilation
CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \
-mlongcalls -nostdlib \
-Wall -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable \
-Wno-error=unused-variable -Wno-error=deprecated-declarations \
-DESP_PLATFORM
CFLAGS_BASE = -std=gnu99 $(CFLAGS_COMMON) -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' -DHAVE_CONFIG_H
CFLAGS = $(CFLAGS_BASE) $(INC) $(INC_ESPCOMP)
CFLAGS += -DIDF_VER=\"$(IDF_VER)\"
CFLAGS += $(CFLAGS_MOD)
# this is what ESPIDF uses for c++ compilation
CXXFLAGS = -std=gnu++11 $(CFLAGS_COMMON) $(INC) $(INC_ESPCOMP)
LDFLAGS = -nostdlib -Map=$(@:.elf=.map) --cref
LDFLAGS += --gc-sections -static -EL
LDFLAGS += -u call_user_start_cpu0 -u uxTopUsedPriority -u ld_include_panic_highint_hdl
LDFLAGS += -u __cxa_guard_dummy # so that implementation of static guards is taken from cxx_guards.o instead of libstdc++.a
LDFLAGS += -L$(ESPCOMP)/esp32/ld
LDFLAGS += -T $(BUILD)/esp32_out.ld
LDFLAGS += -T ./esp32.custom_common.ld
LDFLAGS += -T esp32.rom.ld
LDFLAGS += -T esp32.peripherals.ld
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
LIBSTDCXX_FILE_NAME = $(shell $(CXX) $(CXXFLAGS) -print-file-name=libstdc++.a)
# Debugging/Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -g
COPT = -O0
else
#CFLAGS += -fdata-sections -ffunction-sections
COPT += -Os -DNDEBUG
#LDFLAGS += --gc-sections
endif
# Enable SPIRAM support if CONFIG_SPIRAM_SUPPORT=1
ifeq ($(CONFIG_SPIRAM_SUPPORT),1)
CFLAGS_COMMON += -mfix-esp32-psram-cache-issue -DCONFIG_SPIRAM_SUPPORT=1
LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc-psram-workaround.a $(ESPCOMP)/newlib/lib/libm-psram-workaround.a
else
LDFLAGS += -T esp32.rom.spiram_incompatible_fns.ld
LIBC_LIBM = $(ESPCOMP)/newlib/lib/libc.a $(ESPCOMP)/newlib/lib/libm.a
endif
################################################################################
# List of MicroPython source and object files
SRC_C = \
main.c \
uart.c \
gccollect.c \
mphalport.c \
fatfs_port.c \
help.c \
modutime.c \
moduos.c \
machine_timer.c \
machine_pin.c \
machine_touchpad.c \
machine_adc.c \
machine_dac.c \
machine_pwm.c \
machine_uart.c \
modmachine.c \
modnetwork.c \
network_lan.c \
modsocket.c \
modesp.c \
esp32_ulp.c \
modesp32.c \
espneopixel.c \
machine_hw_spi.c \
machine_wdt.c \
mpthreadport.c \
machine_rtc.c \
$(SRC_MOD)
EXTMOD_SRC_C = $(addprefix extmod/,\
modonewire.c \
)
LIB_SRC_C = $(addprefix lib/,\
libm/math.c \
libm/fmodf.c \
libm/roundf.c \
libm/ef_sqrt.c \
libm/kf_rem_pio2.c \
libm/kf_sin.c \
libm/kf_cos.c \
libm/kf_tan.c \
libm/ef_rem_pio2.c \
libm/sf_sin.c \
libm/sf_cos.c \
libm/sf_tan.c \
libm/sf_frexp.c \
libm/sf_modf.c \
libm/sf_ldexp.c \
libm/asinfacosf.c \
libm/atanf.c \
libm/atan2f.c \
mp-readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
utils/pyexec.c \
utils/interrupt_char.c \
utils/sys_stdio_mphal.c \
)
ifeq ($(MICROPY_FATFS), 1)
LIB_SRC_C += \
lib/oofatfs/ff.c \
lib/oofatfs/option/unicode.c
endif
DRIVERS_SRC_C = $(addprefix drivers/,\
bus/softspi.c \
dht/dht.c \
)
OBJ_MP =
OBJ_MP += $(PY_O)
OBJ_MP += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ_MP += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ_MP += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
OBJ_MP += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
################################################################################
# List of object files from the ESP32 IDF components
ESPIDF_DRIVER_O = $(addprefix $(ESPCOMP)/driver/,\
uart.o \
periph_ctrl.o \
ledc.o \
gpio.o \
timer.o \
spi_master.o \
spi_common.o \
rtc_module.o \
)
$(BUILD)/$(ESPCOMP)/esp32/dport_access.o: CFLAGS += -Wno-array-bounds
ESPIDF_ESP32_O = $(addprefix $(ESPCOMP)/esp32/,\
brownout.o \
panic.o \
esp_timer.o \
esp_timer_esp32.o \
ets_timer_legacy.o \
event_default_handlers.o \
fast_crypto_ops.o \
task_wdt.o \
cache_err_int.o \
clk.o \
core_dump.o \
cpu_start.o \
gdbstub.o \
crosscore_int.o \
ipc.o \
int_wdt.o \
event_loop.o \
hwcrypto/sha.o \
hwcrypto/aes.o \
lib_printf.o \
freertos_hooks.o \
system_api.o \
hw_random.o \
phy_init.o \
intr_alloc.o \
dport_access.o \
wifi_init.o \
wifi_os_adapter.o \
sleep_modes.o \
spiram.o \
spiram_psram.o \
)
ESPIDF_HEAP_O = $(addprefix $(ESPCOMP)/heap/,\
heap_caps.o \
heap_caps_init.o \
multi_heap.o \
)
ESPIDF_SOC_O = $(addprefix $(ESPCOMP)/soc/,\
esp32/cpu_util.o \
esp32/rtc_clk.o \
esp32/rtc_init.o \
esp32/rtc_pm.o \
esp32/rtc_sleep.o \
esp32/rtc_time.o \
esp32/soc_memory_layout.o \
esp32/spi_periph.o \
)
ESPIDF_CXX_O = $(addprefix $(ESPCOMP)/cxx/,\
cxx_guards.o \
)
ESPIDF_ETHERNET_O = $(addprefix $(ESPCOMP)/ethernet/,\
emac_dev.o \
emac_main.o \
eth_phy/phy_tlk110.o \
eth_phy/phy_lan8720.o \
eth_phy/phy_common.o \
)
$(BUILD)/$(ESPCOMP)/expat/%.o: CFLAGS += -Wno-unused-function
ESPIDF_EXPAT_O = $(addprefix $(ESPCOMP)/expat/,\
library/xmltok_ns.o \
library/xmltok.o \
library/xmlparse.o \
library/xmlrole.o \
library/xmltok_impl.o \
port/minicheck.o \
port/expat_element.o \
port/chardata.o \
)
ESPIDF_PTHREAD_O = $(addprefix $(ESPCOMP)/pthread/,\
pthread.o \
pthread_local_storage.o \
)
# Assembler .S files need only basic flags, and in particular should not have
# -Os because that generates subtly different code.
# We also need custom CFLAGS for .c files because FreeRTOS has headers with
# generic names (eg queue.h) which can clash with other files in the port.
CFLAGS_ASM = -I$(ESPCOMP)/esp32/include -I$(ESPCOMP)/soc/esp32/include -I$(ESPCOMP)/freertos/include/freertos -I.
$(BUILD)/$(ESPCOMP)/freertos/portasm.o: CFLAGS = $(CFLAGS_ASM)
$(BUILD)/$(ESPCOMP)/freertos/xtensa_context.o: CFLAGS = $(CFLAGS_ASM)
$(BUILD)/$(ESPCOMP)/freertos/xtensa_intr_asm.o: CFLAGS = $(CFLAGS_ASM)
$(BUILD)/$(ESPCOMP)/freertos/xtensa_vectors.o: CFLAGS = $(CFLAGS_ASM)
$(BUILD)/$(ESPCOMP)/freertos/%.o: CFLAGS = $(CFLAGS_BASE) -I. $(INC_ESPCOMP) -I$(ESPCOMP)/freertos/include/freertos -D_ESP_FREERTOS_INTERNAL
ESPIDF_FREERTOS_O = $(addprefix $(ESPCOMP)/freertos/,\
croutine.o \
event_groups.o \
FreeRTOS-openocd.o \
list.o \
portasm.o \
port.o \
queue.o \
ringbuf.o \
tasks.o \
timers.o \
xtensa_context.o \
xtensa_init.o \
xtensa_intr_asm.o \
xtensa_intr.o \
xtensa_overlay_os_hook.o \
xtensa_vector_defaults.o \
xtensa_vectors.o \
)
ESPIDF_VFS_O = $(addprefix $(ESPCOMP)/vfs/,\
vfs_uart.o \
vfs.o \
)
ESPIDF_JSON_O = $(addprefix $(ESPCOMP)/json/cJSON/,\
cJSON.o \
cJSON_Utils.o \
)
ESPIDF_LOG_O = $(addprefix $(ESPCOMP)/log/,\
log.o \
)
ESPIDF_XTENSA_DEBUG_MODULE_O = $(addprefix $(ESPCOMP)/xtensa-debug-module/,\
eri.o \
trax.o \
)
ESPIDF_TCPIP_ADAPTER_O = $(addprefix $(ESPCOMP)/tcpip_adapter/,\
tcpip_adapter_lwip.o \
)
ESPIDF_APP_TRACE_O = $(addprefix $(ESPCOMP)/app_trace/,\
app_trace.o \
)
ESPIDF_APP_UPDATE_O = $(addprefix $(ESPCOMP)/app_update/,\
esp_ota_ops.o \
)
ESPIDF_NEWLIB_O = $(addprefix $(ESPCOMP)/newlib/,\
time.o \
select.o \
syscalls.o \
syscall_table.o \
reent_init.o \
locks.o \
)
ESPIDF_NGHTTP_O = $(addprefix $(ESPCOMP)/nghttp/,\
nghttp2/lib/nghttp2_http.o \
nghttp2/lib/nghttp2_version.o \
nghttp2/lib/nghttp2_mem.o \
nghttp2/lib/nghttp2_hd_huffman.o \
nghttp2/lib/nghttp2_rcbuf.o \
nghttp2/lib/nghttp2_callbacks.o \
nghttp2/lib/nghttp2_session.o \
nghttp2/lib/nghttp2_stream.o \
nghttp2/lib/nghttp2_hd.o \
nghttp2/lib/nghttp2_priority_spec.o \
nghttp2/lib/nghttp2_buf.o \
nghttp2/lib/nghttp2_option.o \
nghttp2/lib/nghttp2_npn.o \
nghttp2/lib/nghttp2_helper.o \
nghttp2/lib/nghttp2_frame.o \
nghttp2/lib/nghttp2_outbound_item.o \
nghttp2/lib/nghttp2_hd_huffman_data.o \
nghttp2/lib/nghttp2_pq.o \
nghttp2/lib/nghttp2_queue.o \
nghttp2/lib/nghttp2_submit.o \
nghttp2/lib/nghttp2_map.o \
port/http_parser.o \
)
ESPIDF_NVS_FLASH_O = $(addprefix $(ESPCOMP)/nvs_flash/,\
src/nvs_types.o \
src/nvs_page.o \
src/nvs_item_hash_list.o \
src/nvs_pagemanager.o \
src/nvs_storage.o \
src/nvs_api.o \
)
ESPIDF_OPENSSL_O = $(addprefix $(ESPCOMP)/openssl/,\
)
ESPIDF_SMARTCONFIG_ACK_O = $(addprefix $(ESPCOMP)/smartconfig_ack/,\
smartconfig_ack.o \
)
ESPIDF_SPI_FLASH_O = $(addprefix $(ESPCOMP)/spi_flash/,\
flash_mmap.o \
partition.o \
spi_flash_rom_patch.o \
cache_utils.o \
flash_ops.o \
)
ESPIDF_ULP_O = $(addprefix $(ESPCOMP)/ulp/,\
ulp.o \
)
$(BUILD)/$(ESPCOMP)/lwip/%.o: CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
ESPIDF_LWIP_O = $(addprefix $(ESPCOMP)/lwip/,\
api/pppapi.o \
api/netbuf.o \
api/api_lib.o \
api/netifapi.o \
api/tcpip.o \
api/netdb.o \
api/err.o \
api/api_msg.o \
api/sockets.o \
apps/sntp/sntp.o \
apps/dhcpserver.o \
core/ipv4/ip_frag.o \
core/ipv4/dhcp.o \
core/ipv4/ip4_addr.o \
core/ipv4/igmp.o \
core/ipv4/ip4.o \
core/ipv4/autoip.o \
core/ipv4/icmp.o \
core/ipv6/ip6_frag.o \
core/ipv6/dhcp6.o \
core/ipv6/inet6.o \
core/ipv6/ip6_addr.o \
core/ipv6/ip6.o \
core/ipv6/nd6.o \
core/ipv6/mld6.o \
core/ipv6/ethip6.o \
core/ipv6/icmp6.o \
core/mem.o \
core/init.o \
core/memp.o \
core/sys.o \
core/tcp_in.o \
core/dns.o \
core/ip.o \
core/pbuf.o \
core/raw.o \
core/tcp.o \
core/def.o \
core/netif.o \
core/stats.o \
core/timers.o \
core/inet_chksum.o \
core/udp.o \
core/tcp_out.o \
netif/slipif.o \
netif/etharp.o \
netif/ethernet.o \
netif/lowpan6.o \
netif/ethernetif.o \
port/freertos/sys_arch.o \
port/netif/wlanif.o \
port/netif/ethernetif.o \
port/vfs_lwip.o \
)
ESPIDF_MBEDTLS_O = $(addprefix $(ESPCOMP)/mbedtls/,\
mbedtls/library/entropy.o \
mbedtls/library/pkcs12.o \
mbedtls/library/ccm.o \
mbedtls/library/pk.o \
mbedtls/library/sha1.o \
mbedtls/library/x509_csr.o \
mbedtls/library/ssl_cli.o \
mbedtls/library/ecp.o \
mbedtls/library/blowfish.o \
mbedtls/library/x509.o \
mbedtls/library/ecp_curves.o \
mbedtls/library/error.o \
mbedtls/library/ssl_ticket.o \
mbedtls/library/entropy_poll.o \
mbedtls/library/cipher.o \
mbedtls/library/version_features.o \
mbedtls/library/ripemd160.o \
mbedtls/library/rsa.o \
mbedtls/library/rsa_internal.o \
mbedtls/library/md.o \
mbedtls/library/md_wrap.o \
mbedtls/library/sha256.o \
mbedtls/library/dhm.o \
mbedtls/library/ssl_cache.o \
mbedtls/library/pkwrite.o \
mbedtls/library/base64.o \
mbedtls/library/asn1parse.o \
mbedtls/library/ssl_tls.o \
mbedtls/library/hmac_drbg.o \
mbedtls/library/pem.o \
mbedtls/library/version.o \
mbedtls/library/gcm.o \
mbedtls/library/memory_buffer_alloc.o \
mbedtls/library/md2.o \
mbedtls/library/ecdsa.o \
mbedtls/library/ssl_srv.o \
mbedtls/library/x509_crt.o \
mbedtls/library/ecdh.o \
mbedtls/library/asn1write.o \
mbedtls/library/md4.o \
mbedtls/library/debug.o \
mbedtls/library/x509_create.o \
mbedtls/library/ecjpake.o \
mbedtls/library/oid.o \
mbedtls/library/md5.o \
mbedtls/library/ssl_ciphersuites.o \
mbedtls/library/sha512.o \
mbedtls/library/xtea.o \
mbedtls/library/aes.o \
mbedtls/library/cipher_wrap.o \
mbedtls/library/arc4.o \
mbedtls/library/bignum.o \
mbedtls/library/pkparse.o \
mbedtls/library/padlock.o \
mbedtls/library/threading.o \
mbedtls/library/x509_crl.o \
mbedtls/library/pkcs11.o \
mbedtls/library/aesni.o \
mbedtls/library/timing.o \
mbedtls/library/certs.o \
mbedtls/library/pkcs5.o \
mbedtls/library/ssl_cookie.o \
mbedtls/library/camellia.o \
mbedtls/library/havege.o \
mbedtls/library/des.o \
mbedtls/library/x509write_csr.o \
mbedtls/library/platform.o \
mbedtls/library/ctr_drbg.o \
mbedtls/library/x509write_crt.o \
mbedtls/library/pk_wrap.o \
port/esp_bignum.o \
port/esp_hardware.o \
port/esp_sha1.o \
port/esp_sha256.o \
port/esp_sha512.o \
)
$(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 -D__ets__ -Wno-strict-aliasing
ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\
src/crypto/aes-internal-enc.o \
src/crypto/sha256-internal.o \
src/crypto/md5-internal.o \
src/crypto/aes-internal.o \
src/crypto/sha1.o \
src/crypto/aes-internal-dec.o \
src/crypto/aes-unwrap.o \
src/crypto/crypto_internal-rsa.o \
src/crypto/dh_groups.o \
src/crypto/crypto_internal.o \
src/crypto/aes-wrap.o \
src/crypto/sha1-internal.o \
src/crypto/dh_group5.o \
src/crypto/sha256.o \
src/crypto/rc4.o \
src/crypto/md5.o \
src/crypto/aes-cbc.o \
src/crypto/sha1-pbkdf2.o \
src/crypto/bignum.o \
src/crypto/crypto_internal-modexp.o \
src/crypto/crypto_internal-cipher.o \
src/fast_crypto/fast_aes-unwrap.o \
src/fast_crypto/fast_aes-wrap.o \
src/fast_crypto/fast_sha256.o \
src/fast_crypto/fast_sha256-internal.o \
port/os_xtensa.o \
)
OBJ_ESPIDF =
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ESP32_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_HEAP_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SOC_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_CXX_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ETHERNET_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_EXPAT_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_PTHREAD_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_FREERTOS_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_VFS_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_JSON_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LOG_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_LWIP_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_MBEDTLS_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_XTENSA_DEBUG_MODULE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_TCPIP_ADAPTER_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_TRACE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_APP_UPDATE_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NGHTTP_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NVS_FLASH_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_OPENSSL_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O))
OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O))
################################################################################
# Main targets
all: $(BUILD)/firmware.bin
.PHONY: idf-version deploy erase
idf-version:
$(ECHO) "ESP IDF supported hash: $(ESPIDF_SUPHASH)"
$(BUILD)/firmware.bin: $(BUILD)/bootloader.bin $(BUILD)/partitions.bin $(BUILD)/application.bin
$(ECHO) "Create $@"
$(Q)$(PYTHON) makeimg.py $^ $@
deploy: $(BUILD)/firmware.bin
$(ECHO) "Writing $^ to the board"
$(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) write_flash -z --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) 0x1000 $^
erase:
$(ECHO) "Erasing flash"
$(Q)$(ESPTOOL) --chip esp32 --port $(PORT) --baud $(BAUD) erase_flash
################################################################################
# Declarations to build the application
OBJ = $(OBJ_MP) $(OBJ_ESPIDF)
APP_LD_ARGS =
APP_LD_ARGS += $(LDFLAGS_MOD)
APP_LD_ARGS += --start-group
APP_LD_ARGS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
APP_LD_ARGS += -L$(dir $(LIBSTDCXX_FILE_NAME)) -lstdc++
APP_LD_ARGS += $(LIBC_LIBM)
APP_LD_ARGS += $(ESPCOMP)/esp32/libhal.a
APP_LD_ARGS += -L$(ESPCOMP)/esp32/lib -lcore -lmesh -lnet80211 -lphy -lrtc -lpp -lwpa -lsmartconfig -lcoexist -lwps -lwpa2
APP_LD_ARGS += $(OBJ)
APP_LD_ARGS += --end-group
$(BUILD)/esp32_out.ld: sdkconfig.h
$(Q)$(CC) -I. -C -P -x c -E $(ESPCOMP)/esp32/ld/esp32.ld -o $@
$(BUILD)/application.bin: $(BUILD)/application.elf
$(ECHO) "Create $@"
$(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $<
$(BUILD)/application.elf: $(OBJ) $(BUILD)/esp32_out.ld
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $(APP_LD_ARGS)
$(Q)$(SIZE) $@
define compile_cxx
$(ECHO) "CXX $<"
$(Q)$(CXX) $(CXXFLAGS) -c -MD -o $@ $<
@# The following fixes the dependency file.
@# See http://make.paulandlesley.org/autodep.html for details.
@# Regex adjusted from the above to play better with Windows paths, etc.
@$(CP) $(@:.o=.d) $(@:.o=.P); \
$(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
$(RM) -f $(@:.o=.d)
endef
vpath %.cpp . $(TOP)
$(BUILD)/%.o: %.cpp
$(call compile_cxx)
################################################################################
# Declarations to build the bootloader
$(BUILD)/bootloader/$(ESPCOMP)/%.o: CFLAGS += -DBOOTLOADER_BUILD=1 -I$(ESPCOMP)/bootloader_support/include_priv -I$(ESPCOMP)/bootloader_support/include -I$(ESPCOMP)/micro-ecc/micro-ecc -I$(ESPCOMP)/esp32 -Wno-error=format
BOOTLOADER_OBJ = $(addprefix $(BUILD)/bootloader/$(ESPCOMP)/,\
bootloader_support/src/bootloader_clock.o \
bootloader_support/src/bootloader_common.o \
bootloader_support/src/bootloader_flash.o \
bootloader_support/src/bootloader_init.o \
bootloader_support/src/bootloader_random.o \
bootloader_support/src/bootloader_sha.o \
bootloader_support/src/bootloader_utility.o \
bootloader_support/src/efuse.o \
bootloader_support/src/flash_qio_mode.o \
bootloader_support/src/secure_boot_signatures.o \
bootloader_support/src/secure_boot.o \
bootloader_support/src/esp_image_format.o \
bootloader_support/src/flash_encrypt.o \
bootloader_support/src/flash_partitions.o \
log/log.o \
spi_flash/spi_flash_rom_patch.o \
soc/esp32/rtc_clk.o \
soc/esp32/rtc_time.o \
soc/esp32/cpu_util.o \
micro-ecc/micro-ecc/uECC.o \
bootloader/subproject/main/bootloader_start.o \
)
BOOTLOADER_LIBS =
BOOTLOADER_LIBS += -Wl,--start-group
BOOTLOADER_LIBS += $(BOOTLOADER_OBJ)
BOOTLOADER_LIBS += -L$(ESPCOMP)/esp32/lib -lrtc
BOOTLOADER_LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
BOOTLOADER_LIBS += -Wl,--end-group
BOOTLOADER_LDFLAGS =
BOOTLOADER_LDFLAGS += -nostdlib
BOOTLOADER_LDFLAGS += -L$(ESPIDF)/lib
BOOTLOADER_LDFLAGS += -L$(ESPIDF)/ld
BOOTLOADER_LDFLAGS += -u call_user_start_cpu0
BOOTLOADER_LDFLAGS += -Wl,--gc-sections
BOOTLOADER_LDFLAGS += -static
BOOTLOADER_LDFLAGS += -Wl,-EL
BOOTLOADER_LDFLAGS += -Wl,-Map=$(@:.elf=.map) -Wl,--cref
BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.ld
BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/bootloader/subproject/main/esp32.bootloader.rom.ld
BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.ld
BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.rom.spiram_incompatible_fns.ld
BOOTLOADER_LDFLAGS += -T $(ESPCOMP)/esp32/ld/esp32.peripherals.ld
BOOTLOADER_OBJ_DIRS = $(sort $(dir $(BOOTLOADER_OBJ)))
$(BOOTLOADER_OBJ): | $(BOOTLOADER_OBJ_DIRS)
$(BOOTLOADER_OBJ_DIRS):
$(MKDIR) -p $@
$(BUILD)/bootloader/%.o: %.c
$(call compile_c)
$(BUILD)/bootloader.bin: $(BUILD)/bootloader.elf
$(ECHO) "Create $@"
$(Q)$(ESPTOOL) --chip esp32 elf2image --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) --flash_size $(FLASH_SIZE) $<
$(BUILD)/bootloader.elf: $(BOOTLOADER_OBJ)
$(ECHO) "LINK $@"
$(Q)$(CC) $(BOOTLOADER_LDFLAGS) -o $@ $(BOOTLOADER_LIBS)
################################################################################
# Declarations to build the partitions
PYTHON2 ?= python2
PART_SRC = partitions.csv
$(BUILD)/partitions.bin: $(PART_SRC)
$(ECHO) "Create $@"
$(Q)$(PYTHON2) $(ESPCOMP)/partition_table/gen_esp32part.py -q $< $@
################################################################################
include $(TOP)/py/mkrules.mk

202
ports/esp32/README.md Normal file
View File

@ -0,0 +1,202 @@
MicroPython port to the ESP32
=============================
This is an experimental port of MicroPython to the Espressif ESP32
microcontroller. It uses the ESP-IDF framework and MicroPython runs as
a task under FreeRTOS.
Supported features include:
- REPL (Python prompt) over UART0.
- 16k stack for the MicroPython task and 96k Python heap.
- Many of MicroPython's features are enabled: unicode, arbitrary-precision
integers, single-precision floats, complex numbers, frozen bytecode, as
well as many of the internal modules.
- Internal filesystem using the flash (currently 2M in size).
- The machine module with GPIO, UART, SPI, software I2C, ADC, DAC, PWM,
TouchPad, WDT and Timer.
- The network module with WLAN (WiFi) support.
Development of this ESP32 port was sponsored in part by Microbric Pty Ltd.
Setting up the toolchain and ESP-IDF
------------------------------------
There are two main components that are needed to build the firmware:
- the Xtensa cross-compiler that targets the CPU in the ESP32 (this is
different to the compiler used by the ESP8266)
- the Espressif IDF (IoT development framework, aka SDK)
The ESP-IDF changes quickly and MicroPython only supports a certain version. The
git hash of this version can be found by running `make` without a configured
`ESPIDF`. Then you can fetch only the given esp-idf using the following command:
$ git clone https://github.com/espressif/esp-idf.git
$ git checkout <Current supported ESP-IDF commit hash>
$ git submodule update --init --recursive
The binary toolchain (binutils, gcc, etc.) can be installed using the following
guides:
* [Linux installation](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
* [MacOS installation](https://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
* [Windows installation](https://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
If you are on a Windows machine then the
[Windows Subsystem for Linux](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide)
is the most efficient way to install the ESP32 toolchain and build the project.
If you use WSL then follow the
[Linux guidelines](https://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
for the ESP-IDF instead of the Windows ones.
The Espressif ESP-IDF instructions above only install pyserial for Python 2,
so if you're running Python 3 or a non-system Python you'll also need to
install `pyserial` (or `esptool`) so that the Makefile can flash the board
and set parameters:
```bash
$ pip install pyserial
```
Once everything is set up you should have a functioning toolchain with
prefix xtensa-esp32-elf- (or otherwise if you configured it differently)
as well as a copy of the ESP-IDF repository. You will need to update your `PATH`
environment variable to include the ESP32 toolchain. For example, you can issue
the following commands on (at least) Linux:
$ export PATH=$PATH:$HOME/esp/crosstool-NG/builds/xtensa-esp32-elf/bin
You can put this command in your `.profile` or `.bash_login`.
You then need to set the `ESPIDF` environment/makefile variable to point to
the root of the ESP-IDF repository. You can set the variable in your PATH,
or at the command line when calling make, or in your own custom `makefile`.
The last option is recommended as it allows you to easily configure other
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>
#PORT = /dev/ttyUSB0
#FLASH_MODE = qio
#FLASH_SIZE = 4MB
#CROSS_COMPILE = xtensa-esp32-elf-
#CONFIG_SPIRAM_SUPPORT = 1
include Makefile
```
Be sure to enter the correct path to your local copy of the IDF repository
(and use `$(HOME)`, not tilde, to reference your home directory).
If your filesystem is case-insensitive then you'll need to use `GNUmakefile`
instead of `makefile`.
If the Xtensa cross-compiler is not in your path you can use the
`CROSS_COMPILE` variable to set its location. Other options of interest
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.
Building the firmware
---------------------
The MicroPython cross-compiler must be built to pre-compile some of the
built-in scripts to bytecode. This can be done by (from the root of
this repository):
```bash
$ make -C mpy-cross
```
The ESP32 port has a dependency on Berkeley DB, which is an external
dependency (git submodule). You'll need to have git initialize that
module using the commands:
```bash
$ git submodule init lib/berkeley-db-1.xx
$ git submodule update
```
Then to build MicroPython for the ESP32 run:
```bash
$ cd ports/esp32
$ make
```
This will produce binary firmware images in the `build/` subdirectory
(three of them: bootloader.bin, partitions.bin and application.bin).
To flash the firmware you must have your ESP32 module in the bootloader
mode and connected to a serial port on your PC. Refer to the documentation
for your particular ESP32 module for how to do this. The serial port and
flash settings are set in the `Makefile`, and can be overridden in your
local `makefile`; see above for more details.
You will also need to have user permissions to access the /dev/ttyUSB0 device.
On Linux, you can enable this by adding your user to the `dialout` group,
and rebooting or logging out and in again.
```bash
$ sudo adduser <username> dialout
```
If you are installing MicroPython to your module for the first time, or
after installing any other firmware, you should first erase the flash
completely:
```bash
$ make erase
```
To flash the MicroPython firmware to your ESP32 use:
```bash
$ make deploy
```
This will use the `esptool.py` script (provided by ESP-IDF) to download the
binary images.
Getting a Python prompt
-----------------------
You can get a prompt via the serial port, via UART0, which is the same UART
that is used for programming the firmware. The baudrate for the REPL is
115200 and you can use a command such as:
```bash
$ picocom -b 115200 /dev/ttyUSB0
```
Configuring the WiFi and using the board
----------------------------------------
The ESP32 port is designed to be (almost) equivalent to the ESP8266 in
terms of the modules and user-facing API. There are some small differences,
notably that the ESP32 does not automatically connect to the last access
point when booting up. But for the most part the documentation and tutorials
for the ESP8266 should apply to the ESP32 (at least for the components that
are implemented).
See http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html for
a quick reference, and http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html
for a tutorial.
The following function can be used to connect to a WiFi access point (you can
either pass in your own SSID and password, or change the defaults so you can
quickly call `wlan_connect()` and it just works):
```python
def wlan_connect(ssid='MYSSID', password='MYPASS'):
import network
wlan = network.WLAN(network.STA_IF)
if not wlan.active() or not wlan.isconnected():
wlan.active(True)
print('connecting to:', ssid)
wlan.connect(ssid, password)
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
```
Note that some boards require you to configure the WiFi antenna before using
the WiFi. On Pycom boards like the LoPy and WiPy 2.0 you need to execute the
following code to select the internal antenna (best to put this line in your
boot.py file):
```python
import machine
antenna = machine.Pin(16, machine.Pin.OUT, value=0)
```
Troubleshooting
---------------
* Continuous reboots after programming: Ensure FLASH_MODE is correct for your
board (e.g. ESP-WROOM-32 should be DIO). Then perform a `make clean`, rebuild,
redeploy.

126
ports/esp32/README.ulp.md Normal file
View File

@ -0,0 +1,126 @@
# ULP
To compile binarys for the ulp you need the ulp toolkit. Download it from https://github.com/espressif/binutils-esp32ulp/wiki#downloads
Then extract it, then add ```esp32ulp-elf-binutils/bin``` to your PATH
## Example Makefile
```make
ULP_S_SOURCES := main.S
ULP_APP_NAME := test
ULP_LD_SCRIPT := esp32.ulp.ld
SRC_PATH := src
BUILD_PATH := build
include $(ESPIDF)/components/ulp/Makefile.projbuild
ULP_ELF := $(ULP_APP_NAME).elf
ULP_MAP := $(ULP_ELF:.elf=.map)
ULP_SYM := $(ULP_ELF:.elf=.sym)
ULP_BIN := $(ULP_ELF:.elf=.bin)
ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld)
ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h)
ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o))
ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d)
ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS))
ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst))
.PHONY: all clean
all: $(BUILD_PATH) $(BUILD_PATH)/$(ULP_BIN)
clean:
rm -rf $(BUILD_PATH)
$(BUILD_PATH):
mkdir $@
# Generate preprocessed linker file.
$(BUILD_PATH)/$(ULP_APP_NAME).ld: $(SRC_PATH)/$(ULP_LD_SCRIPT)
cpp -P $< -o $@
# Generate preprocessed assembly files.
# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule.
$(BUILD_PATH)/%.ulp.pS: $(SRC_PATH)/%.S
cpp $< -o $@
# Compiled preprocessed files into object files.
$(BUILD_PATH)/%.ulp.o: $(BUILD_PATH)/%.ulp.pS
$(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $<
# Link object files and generate map file
$(BUILD_PATH)/$(ULP_ELF): $(BUILD_PATH)/$(ULP_OBJECTS) $(BUILD_PATH)/$(ULP_APP_NAME).ld
$(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(BUILD_PATH)/$(ULP_MAP) -T $(BUILD_PATH)/$(ULP_APP_NAME).ld $<
# Dump the list of global symbols in a convenient format.
$(ULP_SYM): $(ULP_ELF)
$(ULP_NM) -g -f posix $< > $@
# Dump the binary for inclusion into the project
$(BUILD_PATH)/$(ULP_BIN): $(BUILD_PATH)/$(ULP_ELF)
$(ULP_OBJCOPY) -O binary $< $@
```
## Example linker script for the ulp
```
#define ULP_BIN_MAGIC 0x00706c75
#define HEADER_SIZE 12
#define CONFIG_ULP_COPROC_RESERVE_MEM 4096
MEMORY
{
ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM
}
SECTIONS
{
.text : AT(HEADER_SIZE)
{
*(.text)
} >ram
.data :
{
. = ALIGN(4);
*(.data)
} >ram
.bss :
{
. = ALIGN(4);
*(.bss)
} >ram
.header : AT(0)
{
LONG(ULP_BIN_MAGIC)
SHORT(LOADADDR(.text))
SHORT(SIZEOF(.text))
SHORT(SIZEOF(.data))
SHORT(SIZEOF(.bss))
}
}
```
## Example ulp code
```asm
move R3, 99
move R0, 10
# mem[R0+0] = R3
st R3, R0, 0
HALT
```
## Example python code using the ulp
```python
import esp32
import time
u = esp32.ULP()
with open('test.bin', 'rb') as f:
b = f.read()
u.load_binary(0,b)
u.run(0)
```

View File

@ -0,0 +1,254 @@
/* Default entry point: */
ENTRY(call_start_cpu0);
SECTIONS
{
/* RTC fast memory holds RTC wake stub code,
including from any source file named rtc_wake_stub*.c
*/
.rtc.text :
{
. = ALIGN(4);
*(.rtc.literal .rtc.text)
*rtc_wake_stub*.o(.literal .text .literal.* .text.*)
} > rtc_iram_seg
/* RTC slow memory holds RTC wake stub
data/rodata, including from any source file
named rtc_wake_stub*.c
*/
.rtc.data :
{
_rtc_data_start = ABSOLUTE(.);
*(.rtc.data)
*(.rtc.rodata)
*rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*)
_rtc_data_end = ABSOLUTE(.);
} > rtc_slow_seg
/* RTC bss, from any source file named rtc_wake_stub*.c */
.rtc.bss (NOLOAD) :
{
_rtc_bss_start = ABSOLUTE(.);
*rtc_wake_stub*.o(.bss .bss.*)
*rtc_wake_stub*.o(COMMON)
_rtc_bss_end = ABSOLUTE(.);
} > rtc_slow_seg
/* This section holds data that should not be initialized at power up
and will be retained during deep sleep. The section located in
RTC SLOW Memory area. User data marked with RTC_NOINIT_ATTR will be placed
into this section. See the file "esp_attr.h" for more information.
*/
.rtc_noinit (NOLOAD):
{
. = ALIGN(4);
_rtc_noinit_start = ABSOLUTE(.);
*(.rtc_noinit .rtc_noinit.*)
. = ALIGN(4) ;
_rtc_noinit_end = ABSOLUTE(.);
} > rtc_slow_seg
/* Send .iram0 code to iram */
.iram0.vectors :
{
/* Vectors go to IRAM */
_init_start = ABSOLUTE(.);
/* Vectors according to builds/RF-2015.2-win32/esp108_v1_2_s5_512int_2/config.html */
. = 0x0;
KEEP(*(.WindowVectors.text));
. = 0x180;
KEEP(*(.Level2InterruptVector.text));
. = 0x1c0;
KEEP(*(.Level3InterruptVector.text));
. = 0x200;
KEEP(*(.Level4InterruptVector.text));
. = 0x240;
KEEP(*(.Level5InterruptVector.text));
. = 0x280;
KEEP(*(.DebugExceptionVector.text));
. = 0x2c0;
KEEP(*(.NMIExceptionVector.text));
. = 0x300;
KEEP(*(.KernelExceptionVector.text));
. = 0x340;
KEEP(*(.UserExceptionVector.text));
. = 0x3C0;
KEEP(*(.DoubleExceptionVector.text));
. = 0x400;
*(.*Vector.literal)
*(.UserEnter.literal);
*(.UserEnter.text);
. = ALIGN (16);
*(.entry.text)
*(.init.literal)
*(.init)
_init_end = ABSOLUTE(.);
/* This goes here, not at top of linker script, so addr2line finds it last,
and uses it in preference to the first symbol in IRAM */
_iram_start = ABSOLUTE(0);
} > iram0_0_seg
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
*(.iram1 .iram1.*)
*freertos/*(.literal .text .literal.* .text.*)
*heap/multi_heap.o(.literal .text .literal.* .text.*)
*heap/multi_heap_poisoning.o(.literal .text .literal.* .text.*)
*esp32/panic.o(.literal .text .literal.* .text.*)
*esp32/core_dump.o(.literal .text .literal.* .text.*)
*app_trace/*(.literal .text .literal.* .text.*)
*xtensa-debug-module/eri.o(.literal .text .literal.* .text.*)
*librtc.a:(.literal .text .literal.* .text.*)
*soc/esp32/*(.literal .text .literal.* .text.*)
*libhal.a:(.literal .text .literal.* .text.*)
*libgcc.a:lib2funcs.o(.literal .text .literal.* .text.*)
*spi_flash/spi_flash_rom_patch.o(.literal .text .literal.* .text.*)
*libgcov.a:(.literal .text .literal.* .text.*)
INCLUDE esp32.spiram.rom-functions-iram.ld
*py/scheduler.o*(.literal .text .literal.* .text.*)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
.dram0.data :
{
_data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.data1)
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
*(.jcr)
*(.dram1 .dram1.*)
*esp32/panic.o(.rodata .rodata.*)
*libphy.a:(.rodata .rodata.*)
*soc/esp32/rtc_clk.o(.rodata .rodata.*)
*app_trace/app_trace.o(.rodata .rodata.*)
*libgcov.a:(.rodata .rodata.*)
*heap/multi_heap.o(.rodata .rodata.*)
*heap/multi_heap_poisoning.o(.rodata .rodata.*)
INCLUDE esp32.spiram.rom-functions-dram.ld
_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > dram0_0_seg
/*This section holds data that should not be initialized at power up.
The section located in Internal SRAM memory region. The macro _NOINIT
can be used as attribute to place data into this section.
See the esp_attr.h file for more information.
*/
.noinit (NOLOAD):
{
. = ALIGN(4);
_noinit_start = ABSOLUTE(.);
*(.noinit .noinit.*)
. = ALIGN(4) ;
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.bss)
*(.bss.*)
*(.share.mem)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
/* The heap starts right after end of this section */
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
.flash.rodata :
{
_rodata_start = ABSOLUTE(.);
*(.rodata)
*(.rodata.*)
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
*(.gnu.linkonce.r.*)
*(.rodata1)
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
*(.xt_except_table)
*(.gcc_except_table .gcc_except_table.*)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
. = (. + 3) & ~ 3;
__eh_frame = ABSOLUTE(.);
KEEP(*(.eh_frame))
. = (. + 7) & ~ 3;
/* C++ constructor and destructor tables, properly ordered: */
__init_array_start = ABSOLUTE(.);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__init_array_end = ABSOLUTE(.);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/* C++ exception handlers table: */
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
*(.xt_except_desc)
*(.gnu.linkonce.h.*)
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
*(.xt_except_desc_end)
*(.dynamic)
*(.gnu.version_d)
_rodata_end = ABSOLUTE(.);
/* Literals are also RO data. */
_lit4_start = ABSOLUTE(.);
*(*.lit4)
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
*(.tbss)
*(.tbss.*)
_thread_local_end = ABSOLUTE(.);
. = ALIGN(4);
} >drom0_0_seg
.flash.text :
{
_stext = .;
_text_start = ABSOLUTE(.);
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
*(.fini.literal)
*(.fini)
*(.gnu.version)
_text_end = ABSOLUTE(.);
_etext = .;
/* Similar to _iram_start, this symbol goes here so it is
resolved by addr2line in preference to the first symbol in
the flash.text segment.
*/
_flash_cache_start = ABSOLUTE(0);
} >iram0_2_seg
}

97
ports/esp32/esp32_ulp.c Normal file
View File

@ -0,0 +1,97 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2018 "Andreas Valder" <andreas.valder@serioese.gmbh>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "esp32/ulp.h"
#include "esp_err.h"
typedef struct _esp32_ulp_obj_t {
mp_obj_base_t base;
} esp32_ulp_obj_t;
const mp_obj_type_t esp32_ulp_type;
// singleton ULP object
STATIC const esp32_ulp_obj_t esp32_ulp_obj = {{&esp32_ulp_type}};
STATIC mp_obj_t esp32_ulp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
// return constant object
return (mp_obj_t)&esp32_ulp_obj;
}
STATIC mp_obj_t esp32_ulp_set_wakeup_period(mp_obj_t self_in, mp_obj_t period_index_in, mp_obj_t period_us_in) {
mp_uint_t period_index = mp_obj_get_int(period_index_in);
mp_uint_t period_us = mp_obj_get_int(period_us_in);
int _errno = ulp_set_wakeup_period(period_index, period_us);
if (_errno != ESP_OK) {
mp_raise_OSError(_errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_set_wakeup_period_obj, esp32_ulp_set_wakeup_period);
STATIC mp_obj_t esp32_ulp_load_binary(mp_obj_t self_in, mp_obj_t load_addr_in, mp_obj_t program_binary_in) {
mp_uint_t load_addr = mp_obj_get_int(load_addr_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(program_binary_in, &bufinfo, MP_BUFFER_READ);
int _errno = ulp_load_binary(load_addr, bufinfo.buf, bufinfo.len/sizeof(uint32_t));
if (_errno != ESP_OK) {
mp_raise_OSError(_errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_ulp_load_binary_obj, esp32_ulp_load_binary);
STATIC mp_obj_t esp32_ulp_run(mp_obj_t self_in, mp_obj_t entry_point_in) {
mp_uint_t entry_point = mp_obj_get_int(entry_point_in);
int _errno = ulp_run(entry_point/sizeof(uint32_t));
if (_errno != ESP_OK) {
mp_raise_OSError(_errno);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_ulp_run_obj, esp32_ulp_run);
STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) },
{ MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) },
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) },
{ MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) },
};
STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table);
const mp_obj_type_t esp32_ulp_type = {
{ &mp_type_type },
.name = MP_QSTR_ULP,
.make_new = esp32_ulp_make_new,
.locals_dict = (mp_obj_t)&esp32_ulp_locals_dict,
};

53
ports/esp32/espneopixel.c Normal file
View File

@ -0,0 +1,53 @@
// Original version from https://github.com/adafruit/Adafruit_NeoPixel
// Modifications by dpgeorge to support auto-CPU-frequency detection
// This is a mash-up of the Due show() code + insights from Michael Miller's
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
#include "py/mpconfig.h"
#include "py/mphal.h"
#include "modesp.h"
void IRAM_ATTR esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t timing) {
uint8_t *p, *end, pix, mask;
uint32_t t, time0, time1, period, c, startTime, pinMask;
pinMask = 1 << pin;
p = pixels;
end = p + numBytes;
pix = *p++;
mask = 0x80;
startTime = 0;
uint32_t fcpu = ets_get_cpu_frequency() * 1000000;
if (timing == 1) {
// 800 KHz
time0 = (fcpu * 0.35) / 1000000; // 0.35us
time1 = (fcpu * 0.8) / 1000000; // 0.8us
period = (fcpu * 1.25) / 1000000; // 1.25us per bit
} else {
// 400 KHz
time0 = (fcpu * 0.5) / 1000000; // 0.35us
time1 = (fcpu * 1.2) / 1000000; // 0.8us
period = (fcpu * 2.5) / 1000000; // 1.25us per bit
}
uint32_t irq_state = mp_hal_quiet_timing_enter();
for (t = time0;; t = time0) {
if (pix & mask) t = time1; // Bit high duration
while (((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, pinMask); // Set high
startTime = c; // Save start time
while (((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, pinMask); // Set low
if (!(mask >>= 1)) { // Next bit/byte
if(p >= end) break;
pix = *p++;
mask = 0x80;
}
}
while ((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
mp_hal_quiet_timing_exit(irq_state);
}

80
ports/esp32/esponewire.c Normal file
View File

@ -0,0 +1,80 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015-2017 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "esp8266/esponewire.h"
#define TIMING_RESET1 (0)
#define TIMING_RESET2 (1)
#define TIMING_RESET3 (2)
#define TIMING_READ1 (3)
#define TIMING_READ2 (4)
#define TIMING_READ3 (5)
#define TIMING_WRITE1 (6)
#define TIMING_WRITE2 (7)
#define TIMING_WRITE3 (8)
uint16_t esp_onewire_timings[9] = {480, 40, 420, 5, 5, 40, 10, 50, 10};
#define DELAY_US mp_hal_delay_us_fast
int esp_onewire_reset(mp_hal_pin_obj_t pin) {
mp_hal_pin_write(pin, 0);
DELAY_US(esp_onewire_timings[TIMING_RESET1]);
uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
mp_hal_pin_write(pin, 1);
DELAY_US(esp_onewire_timings[TIMING_RESET2]);
int status = !mp_hal_pin_read(pin);
MICROPY_END_ATOMIC_SECTION(i);
DELAY_US(esp_onewire_timings[TIMING_RESET3]);
return status;
}
int esp_onewire_readbit(mp_hal_pin_obj_t pin) {
mp_hal_pin_write(pin, 1);
uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
mp_hal_pin_write(pin, 0);
DELAY_US(esp_onewire_timings[TIMING_READ1]);
mp_hal_pin_write(pin, 1);
DELAY_US(esp_onewire_timings[TIMING_READ2]);
int value = mp_hal_pin_read(pin);
MICROPY_END_ATOMIC_SECTION(i);
DELAY_US(esp_onewire_timings[TIMING_READ3]);
return value;
}
void esp_onewire_writebit(mp_hal_pin_obj_t pin, int value) {
uint32_t i = MICROPY_BEGIN_ATOMIC_SECTION();
mp_hal_pin_write(pin, 0);
DELAY_US(esp_onewire_timings[TIMING_WRITE1]);
if (value) {
mp_hal_pin_write(pin, 1);
}
DELAY_US(esp_onewire_timings[TIMING_WRITE2]);
mp_hal_pin_write(pin, 1);
DELAY_US(esp_onewire_timings[TIMING_WRITE3]);
MICROPY_END_ATOMIC_SECTION(i);
}

41
ports/esp32/fatfs_port.c Normal file
View File

@ -0,0 +1,41 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014, 2016 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 <sys/time.h>
#include "lib/oofatfs/ff.h"
#include "timeutils.h"
DWORD get_fattime(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
timeutils_struct_time_t tm;
timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm);
return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) |
((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1));
}

66
ports/esp32/gccollect.c Normal file
View File

@ -0,0 +1,66 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
* Copyright (c) 2017 Pycom Limited
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "py/mpconfig.h"
#include "py/mpstate.h"
#include "py/gc.h"
#include "py/mpthread.h"
#include "gccollect.h"
#include "soc/cpu.h"
#include "xtensa/hal.h"
static void gc_collect_inner(int level) {
if (level < XCHAL_NUM_AREGS / 8) {
gc_collect_inner(level + 1);
if (level != 0) {
return;
}
}
if (level == XCHAL_NUM_AREGS / 8) {
// get the sp
volatile uint32_t sp = (uint32_t)get_sp();
gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
return;
}
// trace root pointers from any threads
#if MICROPY_PY_THREAD
mp_thread_gc_others();
#endif
}
void gc_collect(void) {
gc_collect_start();
gc_collect_inner(0);
gc_collect_end();
}

42
ports/esp32/gccollect.h Normal file
View File

@ -0,0 +1,42 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
extern uint32_t _text_start;
extern uint32_t _text_end;
extern uint32_t _irom0_text_start;
extern uint32_t _irom0_text_end;
extern uint32_t _data_start;
extern uint32_t _data_end;
extern uint32_t _rodata_start;
extern uint32_t _rodata_end;
extern uint32_t _bss_start;
extern uint32_t _bss_end;
extern uint32_t _heap_start;
extern uint32_t _heap_end;
void gc_collect(void);

65
ports/esp32/help.c Normal file
View File

@ -0,0 +1,65 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/builtin.h"
const char esp32_help_text[] =
"Welcome to MicroPython on the ESP32!\n"
"\n"
"For generic online docs please visit http://docs.micropython.org/\n"
"\n"
"For access to the hardware use the 'machine' module:\n"
"\n"
"import machine\n"
"pin12 = machine.Pin(12, machine.Pin.OUT)\n"
"pin12.value(1)\n"
"pin13 = machine.Pin(13, machine.Pin.IN, machine.Pin.PULL_UP)\n"
"print(pin13.value())\n"
"i2c = machine.I2C(scl=machine.Pin(21), sda=machine.Pin(22))\n"
"i2c.scan()\n"
"i2c.writeto(addr, b'1234')\n"
"i2c.readfrom(addr, 4)\n"
"\n"
"Basic WiFi configuration:\n"
"\n"
"import network\n"
"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
"sta_if.scan() # Scan for available access points\n"
"sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n"
"sta_if.isconnected() # Check for successful connection\n"
"\n"
"Control commands:\n"
" CTRL-A -- on a blank line, enter raw REPL mode\n"
" CTRL-B -- on a blank line, enter normal REPL mode\n"
" CTRL-C -- interrupt a running program\n"
" CTRL-D -- on a blank line, do a soft reset of the board\n"
" CTRL-E -- on a blank line, enter paste mode\n"
"\n"
"For further help on a specific object, type help(obj)\n"
"For a list of available modules, type help('modules')\n"
;

132
ports/esp32/machine_adc.c Normal file
View File

@ -0,0 +1,132 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Nick Moore
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
typedef struct _madc_obj_t {
mp_obj_base_t base;
gpio_num_t gpio_id;
adc1_channel_t adc1_id;
} madc_obj_t;
STATIC const madc_obj_t madc_obj[] = {
{{&machine_adc_type}, GPIO_NUM_36, ADC1_CHANNEL_0},
{{&machine_adc_type}, GPIO_NUM_37, ADC1_CHANNEL_1},
{{&machine_adc_type}, GPIO_NUM_38, ADC1_CHANNEL_2},
{{&machine_adc_type}, GPIO_NUM_39, ADC1_CHANNEL_3},
{{&machine_adc_type}, GPIO_NUM_32, ADC1_CHANNEL_4},
{{&machine_adc_type}, GPIO_NUM_33, ADC1_CHANNEL_5},
{{&machine_adc_type}, GPIO_NUM_34, ADC1_CHANNEL_6},
{{&machine_adc_type}, GPIO_NUM_35, ADC1_CHANNEL_7},
};
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);
initialized = 1;
}
mp_arg_check_num(n_args, n_kw, 1, 1, true);
gpio_num_t pin_id = machine_pin_get_id(args[0]);
const madc_obj_t *self = NULL;
for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) {
if (pin_id == madc_obj[i].gpio_id) { self = &madc_obj[i]; break; }
}
if (!self) mp_raise_ValueError("invalid Pin for ADC");
esp_err_t err = adc1_config_channel_atten(self->adc1_id, ADC_ATTEN_0db);
if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
mp_raise_ValueError("Parameter Error");
}
STATIC void madc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
madc_obj_t *self = self_in;
mp_printf(print, "ADC(Pin(%u))", self->gpio_id);
}
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);
if (val == -1) mp_raise_ValueError("Parameter Error");
return MP_OBJ_NEW_SMALL_INT(val);
}
MP_DEFINE_CONST_FUN_OBJ_1(madc_read_obj, madc_read);
STATIC mp_obj_t madc_atten(mp_obj_t self_in, mp_obj_t atten_in) {
madc_obj_t *self = self_in;
adc_atten_t atten = mp_obj_get_int(atten_in);
esp_err_t err = adc1_config_channel_atten(self->adc1_id, atten);
if (err == ESP_OK) return mp_const_none;
mp_raise_ValueError("Parameter Error");
}
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");
}
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), 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) },
{ MP_ROM_QSTR(MP_QSTR_ATTN_0DB), MP_ROM_INT(ADC_ATTEN_0db) },
{ MP_ROM_QSTR(MP_QSTR_ATTN_2_5DB), MP_ROM_INT(ADC_ATTEN_2_5db) },
{ MP_ROM_QSTR(MP_QSTR_ATTN_6DB), MP_ROM_INT(ADC_ATTEN_6db) },
{ MP_ROM_QSTR(MP_QSTR_ATTN_11DB), MP_ROM_INT(ADC_ATTEN_11db) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH_9BIT), MP_ROM_INT(ADC_WIDTH_9Bit) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH_10BIT), MP_ROM_INT(ADC_WIDTH_10Bit) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH_11BIT), MP_ROM_INT(ADC_WIDTH_11Bit) },
{ MP_ROM_QSTR(MP_QSTR_WIDTH_12BIT), MP_ROM_INT(ADC_WIDTH_12Bit) },
};
STATIC MP_DEFINE_CONST_DICT(madc_locals_dict, madc_locals_dict_table);
const mp_obj_type_t machine_adc_type = {
{ &mp_type_type },
.name = MP_QSTR_ADC,
.print = madc_print,
.make_new = madc_make_new,
.locals_dict = (mp_obj_t)&madc_locals_dict,
};

97
ports/esp32/machine_dac.c Normal file
View File

@ -0,0 +1,97 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Nick Moore
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/dac.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
typedef struct _mdac_obj_t {
mp_obj_base_t base;
gpio_num_t gpio_id;
dac_channel_t dac_id;
} mdac_obj_t;
STATIC const mdac_obj_t mdac_obj[] = {
{{&machine_dac_type}, GPIO_NUM_25, DAC_CHANNEL_1},
{{&machine_dac_type}, GPIO_NUM_26, DAC_CHANNEL_2},
};
STATIC mp_obj_t mdac_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, true);
gpio_num_t pin_id = machine_pin_get_id(args[0]);
const mdac_obj_t *self = NULL;
for (int i = 0; i < MP_ARRAY_SIZE(mdac_obj); i++) {
if (pin_id == mdac_obj[i].gpio_id) { self = &mdac_obj[i]; break; }
}
if (!self) mp_raise_ValueError("invalid Pin for DAC");
esp_err_t err = dac_output_enable(self->dac_id);
if (err == ESP_OK) {
err = dac_output_voltage(self->dac_id, 0);
}
if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
mp_raise_ValueError("Parameter Error");
}
STATIC void mdac_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mdac_obj_t *self = self_in;
mp_printf(print, "DAC(Pin(%u))", self->gpio_id);
}
STATIC mp_obj_t mdac_write(mp_obj_t self_in, mp_obj_t value_in) {
mdac_obj_t *self = self_in;
int value = mp_obj_get_int(value_in);
if (value < 0 || value > 255) mp_raise_ValueError("Value out of range");
esp_err_t err = dac_output_voltage(self->dac_id, value);
if (err == ESP_OK) return mp_const_none;
mp_raise_ValueError("Parameter Error");
}
MP_DEFINE_CONST_FUN_OBJ_2(mdac_write_obj, mdac_write);
STATIC const mp_rom_map_elem_t mdac_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mdac_write_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mdac_locals_dict, mdac_locals_dict_table);
const mp_obj_type_t machine_dac_type = {
{ &mp_type_type },
.name = MP_QSTR_DAC,
.print = mdac_print,
.make_new = mdac_make_new,
.locals_dict = (mp_obj_t)&mdac_locals_dict,
};

View File

@ -0,0 +1,390 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
#include "extmod/machine_spi.h"
#include "modmachine.h"
#include "driver/spi_master.h"
#define MP_HW_SPI_MAX_XFER_BYTES (4092)
#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
typedef struct _machine_hw_spi_obj_t {
mp_obj_base_t base;
spi_host_device_t host;
uint32_t baudrate;
uint8_t polarity;
uint8_t phase;
uint8_t bits;
uint8_t firstbit;
int8_t sck;
int8_t mosi;
int8_t miso;
spi_device_handle_t spi;
enum {
MACHINE_HW_SPI_STATE_NONE,
MACHINE_HW_SPI_STATE_INIT,
MACHINE_HW_SPI_STATE_DEINIT
} state;
} machine_hw_spi_obj_t;
STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
switch (spi_bus_remove_device(self->spi)) {
case ESP_ERR_INVALID_ARG:
mp_raise_msg(&mp_type_OSError, "invalid configuration");
return;
case ESP_ERR_INVALID_STATE:
mp_raise_msg(&mp_type_OSError, "SPI device already freed");
return;
}
switch (spi_bus_free(self->host)) {
case ESP_ERR_INVALID_ARG:
mp_raise_msg(&mp_type_OSError, "invalid configuration");
return;
case ESP_ERR_INVALID_STATE:
mp_raise_msg(&mp_type_OSError, "SPI bus already freed");
return;
}
int8_t pins[3] = {self->miso, self->mosi, self->sck};
for (int i = 0; i < 3; i++) {
if (pins[i] != -1) {
gpio_pad_select_gpio(pins[i]);
gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false);
gpio_set_direction(pins[i], GPIO_MODE_INPUT);
}
}
}
STATIC void machine_hw_spi_init_internal(
machine_hw_spi_obj_t *self,
int8_t host,
int32_t baudrate,
int8_t polarity,
int8_t phase,
int8_t bits,
int8_t firstbit,
int8_t sck,
int8_t mosi,
int8_t miso) {
// if we're not initialized, then we're
// implicitly 'changed', since this is the init routine
bool changed = self->state != MACHINE_HW_SPI_STATE_INIT;
esp_err_t ret;
machine_hw_spi_obj_t old_self = *self;
if (host != -1 && host != self->host) {
self->host = host;
changed = true;
}
if (baudrate != -1 && baudrate != self->baudrate) {
self->baudrate = baudrate;
changed = true;
}
if (polarity != -1 && polarity != self->polarity) {
self->polarity = polarity;
changed = true;
}
if (phase != -1 && phase != self->phase) {
self->phase = phase;
changed = true;
}
if (bits != -1 && bits != self->bits) {
self->bits = bits;
changed = true;
}
if (firstbit != -1 && firstbit != self->firstbit) {
self->firstbit = firstbit;
changed = true;
}
if (sck != -2 && sck != self->sck) {
self->sck = sck;
changed = true;
}
if (mosi != -2 && mosi != self->mosi) {
self->mosi = mosi;
changed = true;
}
if (miso != -2 && miso != self->miso) {
self->miso = miso;
changed = true;
}
if (self->host != HSPI_HOST && self->host != VSPI_HOST) {
mp_raise_ValueError("SPI ID must be either HSPI(1) or VSPI(2)");
}
if (changed) {
if (self->state == MACHINE_HW_SPI_STATE_INIT) {
self->state = MACHINE_HW_SPI_STATE_DEINIT;
machine_hw_spi_deinit_internal(&old_self);
}
} else {
return; // no changes
}
spi_bus_config_t buscfg = {
.miso_io_num = self->miso,
.mosi_io_num = self->mosi,
.sclk_io_num = self->sck,
.quadwp_io_num = -1,
.quadhd_io_num = -1
};
spi_device_interface_config_t devcfg = {
.clock_speed_hz = self->baudrate,
.mode = self->phase | (self->polarity << 1),
.spics_io_num = -1, // No CS pin
.queue_size = 1,
.flags = self->firstbit == MICROPY_PY_MACHINE_SPI_LSB ? SPI_DEVICE_TXBIT_LSBFIRST | SPI_DEVICE_RXBIT_LSBFIRST : 0,
.pre_cb = NULL
};
//Initialize the SPI bus
// FIXME: Does the DMA matter? There are two
ret = spi_bus_initialize(self->host, &buscfg, 1);
switch (ret) {
case ESP_ERR_INVALID_ARG:
mp_raise_msg(&mp_type_OSError, "invalid configuration");
return;
case ESP_ERR_INVALID_STATE:
mp_raise_msg(&mp_type_OSError, "SPI device already in use");
return;
}
ret = spi_bus_add_device(self->host, &devcfg, &self->spi);
switch (ret) {
case ESP_ERR_INVALID_ARG:
mp_raise_msg(&mp_type_OSError, "invalid configuration");
spi_bus_free(self->host);
return;
case ESP_ERR_NO_MEM:
mp_raise_msg(&mp_type_OSError, "out of memory");
spi_bus_free(self->host);
return;
case ESP_ERR_NOT_FOUND:
mp_raise_msg(&mp_type_OSError, "no free slots");
spi_bus_free(self->host);
return;
}
self->state = MACHINE_HW_SPI_STATE_INIT;
}
STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) {
machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
if (self->state == MACHINE_HW_SPI_STATE_INIT) {
self->state = MACHINE_HW_SPI_STATE_DEINIT;
machine_hw_spi_deinit_internal(self);
}
}
STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->state == MACHINE_HW_SPI_STATE_DEINIT) {
mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI");
return;
}
struct spi_transaction_t transaction = { 0 };
// Round to nearest whole set of bits
int bits_to_send = len * 8 / self->bits * self->bits;
if (len <= 4) {
if (src != NULL) {
memcpy(&transaction.tx_data, src, len);
}
transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
transaction.length = bits_to_send;
spi_device_transmit(self->spi, &transaction);
if (dest != NULL) {
memcpy(dest, &transaction.rx_data, len);
}
} else {
int offset = 0;
int bits_remaining = bits_to_send;
while (bits_remaining) {
memset(&transaction, 0, sizeof(transaction));
transaction.length =
bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining;
if (src != NULL) {
transaction.tx_buffer = src + offset;
}
if (dest != NULL) {
transaction.rx_buffer = dest + offset;
}
spi_device_transmit(self->spi, &transaction);
bits_remaining -= transaction.length;
// doesn't need ceil(); loop ends when bits_remaining is 0
offset += transaction.length / 8;
}
}
}
/******************************************************************************/
// MicroPython bindings for hw_spi
STATIC void machine_hw_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SPI(id=%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%u, sck=%d, mosi=%d, miso=%d)",
self->host, self->baudrate, self->polarity,
self->phase, self->bits, self->firstbit,
self->sck, self->mosi, self->miso);
}
STATIC void machine_hw_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *) self_in;
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
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);
int8_t sck, mosi, miso;
if (args[ARG_sck].u_obj == MP_OBJ_NULL) {
sck = -2;
} else if (args[ARG_sck].u_obj == mp_const_none) {
sck = -1;
} else {
sck = machine_pin_get_id(args[ARG_sck].u_obj);
}
if (args[ARG_miso].u_obj == MP_OBJ_NULL) {
miso = -2;
} else if (args[ARG_miso].u_obj == mp_const_none) {
miso = -1;
} else {
miso = machine_pin_get_id(args[ARG_miso].u_obj);
}
if (args[ARG_mosi].u_obj == MP_OBJ_NULL) {
mosi = -2;
} else if (args[ARG_mosi].u_obj == mp_const_none) {
mosi = -1;
} else {
mosi = machine_pin_get_id(args[ARG_mosi].u_obj);
}
machine_hw_spi_init_internal(self, args[ARG_id].u_int, args[ARG_baudrate].u_int,
args[ARG_polarity].u_int, args[ARG_phase].u_int, args[ARG_bits].u_int,
args[ARG_firstbit].u_int, sck, mosi, miso);
}
mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
{ MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
machine_hw_spi_obj_t *self = m_new_obj(machine_hw_spi_obj_t);
self->base.type = &machine_hw_spi_type;
machine_hw_spi_init_internal(
self,
args[ARG_id].u_int,
args[ARG_baudrate].u_int,
args[ARG_polarity].u_int,
args[ARG_phase].u_int,
args[ARG_bits].u_int,
args[ARG_firstbit].u_int,
args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj),
args[ARG_mosi].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_mosi].u_obj),
args[ARG_miso].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_miso].u_obj));
return MP_OBJ_FROM_PTR(self);
}
STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
.init = machine_hw_spi_init,
.deinit = machine_hw_spi_deinit,
.transfer = machine_hw_spi_transfer,
};
const mp_obj_type_t machine_hw_spi_type = {
{ &mp_type_type },
.name = MP_QSTR_SPI,
.print = machine_hw_spi_print,
.make_new = machine_hw_spi_make_new,
.protocol = &machine_hw_spi_p,
.locals_dict = (mp_obj_dict_t *) &mp_machine_spi_locals_dict,
};

414
ports/esp32/machine_pin.c Normal file
View File

@ -0,0 +1,414 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include "driver/gpio.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
#include "extmod/virtpin.h"
#include "machine_rtc.h"
#include "modesp32.h"
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
gpio_num_t id;
} machine_pin_obj_t;
typedef struct _machine_pin_irq_obj_t {
mp_obj_base_t base;
gpio_num_t id;
} machine_pin_irq_obj_t;
STATIC const machine_pin_obj_t machine_pin_obj[] = {
{{&machine_pin_type}, GPIO_NUM_0},
{{&machine_pin_type}, GPIO_NUM_1},
{{&machine_pin_type}, GPIO_NUM_2},
{{&machine_pin_type}, GPIO_NUM_3},
{{&machine_pin_type}, GPIO_NUM_4},
{{&machine_pin_type}, GPIO_NUM_5},
{{&machine_pin_type}, GPIO_NUM_6},
{{&machine_pin_type}, GPIO_NUM_7},
{{&machine_pin_type}, GPIO_NUM_8},
{{&machine_pin_type}, GPIO_NUM_9},
{{&machine_pin_type}, GPIO_NUM_10},
{{&machine_pin_type}, GPIO_NUM_11},
{{&machine_pin_type}, GPIO_NUM_12},
{{&machine_pin_type}, GPIO_NUM_13},
{{&machine_pin_type}, GPIO_NUM_14},
{{&machine_pin_type}, GPIO_NUM_15},
{{&machine_pin_type}, GPIO_NUM_16},
{{&machine_pin_type}, GPIO_NUM_17},
{{&machine_pin_type}, GPIO_NUM_18},
{{&machine_pin_type}, GPIO_NUM_19},
{{NULL}, -1},
{{&machine_pin_type}, GPIO_NUM_21},
{{&machine_pin_type}, GPIO_NUM_22},
{{&machine_pin_type}, GPIO_NUM_23},
{{NULL}, -1},
{{&machine_pin_type}, GPIO_NUM_25},
{{&machine_pin_type}, GPIO_NUM_26},
{{&machine_pin_type}, GPIO_NUM_27},
{{NULL}, -1},
{{NULL}, -1},
{{NULL}, -1},
{{NULL}, -1},
{{&machine_pin_type}, GPIO_NUM_32},
{{&machine_pin_type}, GPIO_NUM_33},
{{&machine_pin_type}, GPIO_NUM_34},
{{&machine_pin_type}, GPIO_NUM_35},
{{&machine_pin_type}, GPIO_NUM_36},
{{&machine_pin_type}, GPIO_NUM_37},
{{&machine_pin_type}, GPIO_NUM_38},
{{&machine_pin_type}, GPIO_NUM_39},
};
// forward declaration
STATIC const machine_pin_irq_obj_t machine_pin_irq_object[];
void machine_pins_init(void) {
static bool did_install = false;
if (!did_install) {
gpio_install_isr_service(0);
did_install = true;
}
memset(&MP_STATE_PORT(machine_pin_irq_handler[0]), 0, sizeof(MP_STATE_PORT(machine_pin_irq_handler)));
}
void machine_pins_deinit(void) {
for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
if (machine_pin_obj[i].id != (gpio_num_t)-1) {
gpio_isr_handler_remove(machine_pin_obj[i].id);
}
}
}
STATIC void IRAM_ATTR machine_pin_isr_handler(void *arg) {
machine_pin_obj_t *self = arg;
mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id];
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self));
}
gpio_num_t machine_pin_get_id(mp_obj_t pin_in) {
if (mp_obj_get_type(pin_in) != &machine_pin_type) {
mp_raise_ValueError("expecting a pin");
}
machine_pin_obj_t *self = pin_in;
return self->id;
}
STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pin_obj_t *self = self_in;
mp_printf(print, "Pin(%u)", self->id);
}
// pin.init(mode, pull=None, *, value)
STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_mode, ARG_pull, ARG_value };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = mp_const_none}},
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
};
// parse args
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);
// configure the pin for gpio
gpio_pad_select_gpio(self->id);
// set initial value (do this before configuring mode/pull)
if (args[ARG_value].u_obj != MP_OBJ_NULL) {
gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj));
}
// configure mode
if (args[ARG_mode].u_obj != mp_const_none) {
mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
if (self->id >= 34 && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
mp_raise_ValueError("pin can only be input");
} else {
gpio_set_direction(self->id, pin_io_mode);
}
}
// configure pull
if (args[ARG_pull].u_obj != mp_const_none) {
gpio_set_pull_mode(self->id, mp_obj_get_int(args[ARG_pull].u_obj));
}
return mp_const_none;
}
// constructor(id, ...)
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// get the wanted pin object
int wanted_pin = mp_obj_get_int(args[0]);
const machine_pin_obj_t *self = NULL;
if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
self = (machine_pin_obj_t*)&machine_pin_obj[wanted_pin];
}
if (self == NULL || self->base.type == NULL) {
mp_raise_ValueError("invalid pin");
}
if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args);
}
return MP_OBJ_FROM_PTR(self);
}
// fast method for getting/setting pin value
STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
machine_pin_obj_t *self = self_in;
if (n_args == 0) {
// get pin
return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id));
} else {
// set pin
gpio_set_level(self->id, mp_obj_is_true(args[0]));
return mp_const_none;
}
}
// pin.init(mode, pull)
STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init);
// pin.value([value])
STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
return machine_pin_call(args[0], n_args - 1, 0, args + 1);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING)
STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_handler, ARG_trigger, ARG_wake };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
{ MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (n_args > 1 || kw_args->used != 0) {
// configure irq
mp_obj_t handler = args[ARG_handler].u_obj;
uint32_t trigger = args[ARG_trigger].u_int;
mp_obj_t wake_obj = args[ARG_wake].u_obj;
if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
mp_int_t wake;
if (mp_obj_get_int_maybe(wake_obj, &wake)) {
if (wake < 2 || wake > 7) {
mp_raise_ValueError("bad wake value");
}
} else {
mp_raise_ValueError("bad wake value");
}
if (machine_rtc_config.wake_on_touch) { // not compatible
mp_raise_ValueError("no resources");
}
if (!RTC_IS_VALID_EXT_PIN(self->id)) {
mp_raise_ValueError("invalid pin for wake");
}
if (machine_rtc_config.ext0_pin == -1) {
machine_rtc_config.ext0_pin = self->id;
} else if (machine_rtc_config.ext0_pin != self->id) {
mp_raise_ValueError("no resources");
}
machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1;
machine_rtc_config.ext0_wake_types = wake;
} else {
if (machine_rtc_config.ext0_pin == self->id) {
machine_rtc_config.ext0_pin = -1;
}
if (handler == mp_const_none) {
handler = MP_OBJ_NULL;
trigger = 0;
}
gpio_isr_handler_remove(self->id);
MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler;
gpio_set_intr_type(self->id, trigger);
gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void*)self);
}
}
// return the irq object
return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
// class constants
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) },
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) },
{ MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) },
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULLUP_ONLY) },
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULLDOWN_ONLY) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
{ MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
};
STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
(void)errcode;
machine_pin_obj_t *self = self_in;
switch (request) {
case MP_PIN_READ: {
return gpio_get_level(self->id);
}
case MP_PIN_WRITE: {
gpio_set_level(self->id, arg);
return 0;
}
}
return -1;
}
STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
STATIC const mp_pin_p_t pin_pin_p = {
.ioctl = pin_ioctl,
};
const mp_obj_type_t machine_pin_type = {
{ &mp_type_type },
.name = MP_QSTR_Pin,
.print = machine_pin_print,
.make_new = mp_pin_make_new,
.call = machine_pin_call,
.protocol = &pin_pin_p,
.locals_dict = (mp_obj_t)&machine_pin_locals_dict,
};
/******************************************************************************/
// Pin IRQ object
STATIC const mp_obj_type_t machine_pin_irq_type;
STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
{{&machine_pin_irq_type}, GPIO_NUM_0},
{{&machine_pin_irq_type}, GPIO_NUM_1},
{{&machine_pin_irq_type}, GPIO_NUM_2},
{{&machine_pin_irq_type}, GPIO_NUM_3},
{{&machine_pin_irq_type}, GPIO_NUM_4},
{{&machine_pin_irq_type}, GPIO_NUM_5},
{{&machine_pin_irq_type}, GPIO_NUM_6},
{{&machine_pin_irq_type}, GPIO_NUM_7},
{{&machine_pin_irq_type}, GPIO_NUM_8},
{{&machine_pin_irq_type}, GPIO_NUM_9},
{{&machine_pin_irq_type}, GPIO_NUM_10},
{{&machine_pin_irq_type}, GPIO_NUM_11},
{{&machine_pin_irq_type}, GPIO_NUM_12},
{{&machine_pin_irq_type}, GPIO_NUM_13},
{{&machine_pin_irq_type}, GPIO_NUM_14},
{{&machine_pin_irq_type}, GPIO_NUM_15},
{{&machine_pin_irq_type}, GPIO_NUM_16},
{{&machine_pin_irq_type}, GPIO_NUM_17},
{{&machine_pin_irq_type}, GPIO_NUM_18},
{{&machine_pin_irq_type}, GPIO_NUM_19},
{{NULL}, -1},
{{&machine_pin_irq_type}, GPIO_NUM_21},
{{&machine_pin_irq_type}, GPIO_NUM_22},
{{&machine_pin_irq_type}, GPIO_NUM_23},
{{NULL}, -1},
{{&machine_pin_irq_type}, GPIO_NUM_25},
{{&machine_pin_irq_type}, GPIO_NUM_26},
{{&machine_pin_irq_type}, GPIO_NUM_27},
{{NULL}, -1},
{{NULL}, -1},
{{NULL}, -1},
{{NULL}, -1},
{{&machine_pin_irq_type}, GPIO_NUM_32},
{{&machine_pin_irq_type}, GPIO_NUM_33},
{{&machine_pin_irq_type}, GPIO_NUM_34},
{{&machine_pin_irq_type}, GPIO_NUM_35},
{{&machine_pin_irq_type}, GPIO_NUM_36},
{{&machine_pin_irq_type}, GPIO_NUM_37},
{{&machine_pin_irq_type}, GPIO_NUM_38},
{{&machine_pin_irq_type}, GPIO_NUM_39},
};
STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
machine_pin_irq_obj_t *self = self_in;
mp_arg_check_num(n_args, n_kw, 0, 0, false);
machine_pin_isr_handler((void*)&machine_pin_obj[self->id]);
return mp_const_none;
}
STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
machine_pin_irq_obj_t *self = args[0];
uint32_t orig_trig = GPIO.pin[self->id].int_type;
if (n_args == 2) {
// set trigger
gpio_set_intr_type(self->id, mp_obj_get_int(args[1]));
}
// return original trigger value
return MP_OBJ_NEW_SMALL_INT(orig_trig);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_irq_trigger_obj, 1, 2, machine_pin_irq_trigger);
STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&machine_pin_irq_trigger_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table);
STATIC const mp_obj_type_t machine_pin_irq_type = {
{ &mp_type_type },
.name = MP_QSTR_IRQ,
.call = machine_pin_irq_call,
.locals_dict = (mp_obj_dict_t*)&machine_pin_irq_locals_dict,
};

277
ports/esp32/machine_pwm.c Normal file
View File

@ -0,0 +1,277 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "driver/ledc.h"
#include "esp_err.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "modmachine.h"
#include "mphalport.h"
// Forward dec'l
extern const mp_obj_type_t machine_pwm_type;
typedef struct _esp32_pwm_obj_t {
mp_obj_base_t base;
gpio_num_t pin;
uint8_t active;
uint8_t channel;
} esp32_pwm_obj_t;
// Which channel has which GPIO pin assigned?
// (-1 if not assigned)
STATIC int chan_gpio[LEDC_CHANNEL_MAX];
// Params for PW operation
// 5khz
#define PWFREQ (5000)
// High speed mode
#define PWMODE (LEDC_HIGH_SPEED_MODE)
// 10-bit resolution (compatible with esp8266 PWM)
#define PWRES (LEDC_TIMER_10_BIT)
// Timer 1
#define PWTIMER (LEDC_TIMER_1)
// Config of timer upon which we run all PWM'ed GPIO pins
STATIC bool pwm_inited = false;
STATIC ledc_timer_config_t timer_cfg = {
.bit_num = PWRES,
.freq_hz = PWFREQ,
.speed_mode = PWMODE,
.timer_num = PWTIMER
};
STATIC void pwm_init(void) {
// Initial condition: no channels assigned
for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) {
chan_gpio[x] = -1;
}
// Init with default timer params
ledc_timer_config(&timer_cfg);
}
STATIC int set_freq(int newval) {
int oval = timer_cfg.freq_hz;
timer_cfg.freq_hz = newval;
if (ledc_timer_config(&timer_cfg) != ESP_OK) {
timer_cfg.freq_hz = oval;
return 0;
}
return 1;
}
/******************************************************************************/
// MicroPython bindings for PWM
STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "PWM(%u", self->pin);
if (self->active) {
mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz,
ledc_get_duty(PWMODE, self->channel));
}
mp_printf(print, ")");
}
STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_freq, ARG_duty };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} },
};
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);
int channel;
int avail = -1;
// Find a free PWM channel, also spot if our pin is
// already mentioned.
for (channel = 0; channel < LEDC_CHANNEL_MAX; ++channel) {
if (chan_gpio[channel] == self->pin) {
break;
}
if ((avail == -1) && (chan_gpio[channel] == -1)) {
avail = channel;
}
}
if (channel >= LEDC_CHANNEL_MAX) {
if (avail == -1) {
mp_raise_ValueError("out of PWM channels");
}
channel = avail;
}
self->channel = channel;
// New PWM assignment
self->active = 1;
if (chan_gpio[channel] == -1) {
ledc_channel_config_t cfg = {
.channel = channel,
.duty = (1 << PWRES) / 2,
.gpio_num = self->pin,
.intr_type = LEDC_INTR_DISABLE,
.speed_mode = PWMODE,
.timer_sel = PWTIMER,
};
if (ledc_channel_config(&cfg) != ESP_OK) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"PWM not supported on pin %d", self->pin));
}
chan_gpio[channel] = self->pin;
}
// Maybe change PWM timer
int tval = args[ARG_freq].u_int;
if (tval != -1) {
if (tval != timer_cfg.freq_hz) {
if (!set_freq(tval)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"Bad frequency %d", tval));
}
}
}
// Set duty cycle?
int dval = args[ARG_duty].u_int;
if (dval != -1) {
dval &= ((1 << PWRES)-1);
ledc_set_duty(PWMODE, channel, dval);
ledc_update_duty(PWMODE, channel);
}
}
STATIC mp_obj_t esp32_pwm_make_new(const mp_obj_type_t *type,
size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
gpio_num_t pin_id = machine_pin_get_id(args[0]);
// create PWM object from the given pin
esp32_pwm_obj_t *self = m_new_obj(esp32_pwm_obj_t);
self->base.type = &machine_pwm_type;
self->pin = pin_id;
self->active = 0;
self->channel = -1;
// start the PWM subsystem if it's not already running
if (!pwm_inited) {
pwm_init();
pwm_inited = true;
}
// start the PWM running for this channel
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
esp32_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t esp32_pwm_init(size_t n_args,
const mp_obj_t *args, mp_map_t *kw_args) {
esp32_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(esp32_pwm_init_obj, 1, esp32_pwm_init);
STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
int chan = self->channel;
// Valid channel?
if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) {
// Mark it unused, and tell the hardware to stop routing
chan_gpio[chan] = -1;
ledc_stop(PWMODE, chan, 0);
self->active = 0;
self->channel = -1;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit);
STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// get
return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz);
}
// set
int tval = mp_obj_get_int(args[1]);
if (!set_freq(tval)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"Bad frequency %d", tval));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq);
STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) {
esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
int duty;
if (n_args == 1) {
// get
duty = ledc_get_duty(PWMODE, self->channel);
return MP_OBJ_NEW_SMALL_INT(duty);
}
// set
duty = mp_obj_get_int(args[1]);
duty &= ((1 << PWRES)-1);
ledc_set_duty(PWMODE, self->channel, duty);
ledc_update_duty(PWMODE, self->channel);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_duty_obj,
1, 2, esp32_pwm_duty);
STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp32_pwm_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) },
{ MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) },
};
STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict,
esp32_pwm_locals_dict_table);
const mp_obj_type_t machine_pwm_type = {
{ &mp_type_type },
.name = MP_QSTR_PWM,
.print = esp32_pwm_print,
.make_new = esp32_pwm_make_new,
.locals_dict = (mp_obj_dict_t*)&esp32_pwm_locals_dict,
};

162
ports/esp32/machine_rtc.c Normal file
View File

@ -0,0 +1,162 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
* Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "driver/gpio.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "timeutils.h"
#include "modmachine.h"
#include "machine_rtc.h"
typedef struct _machine_rtc_obj_t {
mp_obj_base_t base;
} machine_rtc_obj_t;
#define MEM_MAGIC 0x75507921
/* There is 8K of rtc_slow_memory, but some is used by the system software
If the USER_MAXLEN is set to high, the following compile error will happen:
region `rtc_slow_seg' overflowed by N bytes
The current system software allows almost 4096 to be used.
To avoid running into issues if the system software uses more, 2048 was picked as a max length
*/
#define MEM_USER_MAXLEN 2048
RTC_DATA_ATTR uint32_t rtc_user_mem_magic;
RTC_DATA_ATTR uint32_t rtc_user_mem_len;
RTC_DATA_ATTR uint8_t rtc_user_mem_data[MEM_USER_MAXLEN];
// singleton RTC object
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
machine_rtc_config_t machine_rtc_config = {
.ext1_pins = 0,
.ext0_pin = -1
};
STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
// return constant object
return (mp_obj_t)&machine_rtc_obj;
}
STATIC mp_obj_t machine_rtc_datetime_helper(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// Get time
struct timeval tv;
gettimeofday(&tv, NULL);
timeutils_struct_time_t tm;
timeutils_seconds_since_2000_to_struct_time(tv.tv_sec, &tm);
mp_obj_t tuple[8] = {
mp_obj_new_int(tm.tm_year),
mp_obj_new_int(tm.tm_mon),
mp_obj_new_int(tm.tm_mday),
mp_obj_new_int(tm.tm_wday),
mp_obj_new_int(tm.tm_hour),
mp_obj_new_int(tm.tm_min),
mp_obj_new_int(tm.tm_sec),
mp_obj_new_int(tv.tv_usec)
};
return mp_obj_new_tuple(8, tuple);
} else {
// Set time
mp_obj_t *items;
mp_obj_get_array_fixed_n(args[1], 8, &items);
struct timeval tv = {0};
tv.tv_sec = timeutils_seconds_since_2000(mp_obj_get_int(items[0]), mp_obj_get_int(items[1]), mp_obj_get_int(items[2]), mp_obj_get_int(items[4]), mp_obj_get_int(items[5]), mp_obj_get_int(items[6]));
settimeofday(&tv, NULL);
return mp_const_none;
}
}
STATIC mp_obj_t machine_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
return machine_rtc_datetime_helper(n_args, args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_datetime_obj, 1, 2, machine_rtc_datetime);
STATIC mp_obj_t machine_rtc_init(mp_obj_t self_in, mp_obj_t date) {
mp_obj_t args[2] = {self_in, date};
machine_rtc_datetime_helper(2, args);
if (rtc_user_mem_magic != MEM_MAGIC) {
rtc_user_mem_magic = MEM_MAGIC;
rtc_user_mem_len = 0;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_rtc_init_obj, machine_rtc_init);
STATIC mp_obj_t machine_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// read RTC memory
uint32_t len = rtc_user_mem_len;
uint8_t rtcram[MEM_USER_MAXLEN];
memcpy( (char *) rtcram, (char *) rtc_user_mem_data, len);
return mp_obj_new_bytes(rtcram, len);
} else {
// write RTC memory
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
if (bufinfo.len > MEM_USER_MAXLEN) {
mp_raise_ValueError("buffer too long");
}
memcpy( (char *) rtc_user_mem_data, (char *) bufinfo.buf, bufinfo.len);
rtc_user_mem_len = bufinfo.len;
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_rtc_memory_obj, 1, 2, machine_rtc_memory);
STATIC const mp_rom_map_elem_t machine_rtc_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_rtc_datetime_obj) },
{ MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&machine_rtc_datetime_obj) },
{ MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&machine_rtc_memory_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_rtc_locals_dict, machine_rtc_locals_dict_table);
const mp_obj_type_t machine_rtc_type = {
{ &mp_type_type },
.name = MP_QSTR_RTC,
.make_new = machine_rtc_make_new,
.locals_dict = (mp_obj_t)&machine_rtc_locals_dict,
};

44
ports/esp32/machine_rtc.h Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
* Copyright (c) 2017 "Tom Manning" <tom@manningetal.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
#define MICROPY_INCLUDED_ESP32_MACHINE_RTC_H
#include "modmachine.h"
typedef struct {
uint64_t ext1_pins; // set bit == pin#
int8_t ext0_pin; // just the pin#, -1 == None
bool wake_on_touch : 1;
bool ext0_level : 1;
wake_type_t ext0_wake_types;
bool ext1_level : 1;
} machine_rtc_config_t;
extern machine_rtc_config_t machine_rtc_config;
#endif

192
ports/esp32/machine_timer.c Normal file
View File

@ -0,0 +1,192 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2015 Damien P. George
* Copyright (c) 2016 Paul Sokolovsky
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* 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 <stdint.h>
#include <stdio.h>
#include "driver/timer.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "modmachine.h"
#define TIMER_INTR_SEL TIMER_INTR_LEVEL
#define TIMER_DIVIDER 40000
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER)
#define TIMER_FLAGS 0
typedef struct _machine_timer_obj_t {
mp_obj_base_t base;
mp_uint_t group;
mp_uint_t index;
mp_uint_t repeat;
mp_uint_t period;
mp_obj_t callback;
intr_handle_t handle;
} machine_timer_obj_t;
const mp_obj_type_t machine_timer_type;
STATIC esp_err_t check_esp_err(esp_err_t code) {
if (code) {
mp_raise_OSError(code);
}
return code;
}
STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_timer_obj_t *self = self_in;
timer_config_t config;
mp_printf(print, "Timer(%p; ", self);
timer_get_config(self->group, self->index, &config);
mp_printf(print, "alarm_en=%d, ", config.alarm_en);
mp_printf(print, "auto_reload=%d, ", config.auto_reload);
mp_printf(print, "counter_en=%d)", config.counter_en);
}
STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);
self->base.type = &machine_timer_type;
self->group = (mp_obj_get_int(args[0]) >> 1) & 1;
self->index = mp_obj_get_int(args[0]) & 1;
return self;
}
STATIC void machine_timer_disable(machine_timer_obj_t *self) {
if (self->handle) {
timer_pause(self->group, self->index);
esp_intr_free(self->handle);
self->handle = NULL;
}
}
STATIC void machine_timer_isr(void *self_in) {
machine_timer_obj_t *self = self_in;
timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0);
device->hw_timer[self->index].update = 1;
if (self->index) {
device->int_clr_timers.t1 = 1;
} else {
device->int_clr_timers.t0 = 1;
}
device->hw_timer[self->index].config.alarm_en = self->repeat;
mp_sched_schedule(self->callback, self);
}
STATIC void machine_timer_enable(machine_timer_obj_t *self) {
timer_config_t config;
config.alarm_en = TIMER_ALARM_EN;
config.auto_reload = self->repeat;
config.counter_dir = TIMER_COUNT_UP;
config.divider = TIMER_DIVIDER;
config.intr_type = TIMER_INTR_LEVEL;
config.counter_en = TIMER_PAUSE;
check_esp_err(timer_init(self->group, self->index, &config));
check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000));
check_esp_err(timer_set_alarm_value(self->group, self->index, self->period));
check_esp_err(timer_enable_intr(self->group, self->index));
check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void*)self, TIMER_FLAGS, &self->handle));
check_esp_err(timer_start(self->group, self->index));
}
STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
machine_timer_disable(self);
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);
// Timer uses an 80MHz base clock, which is divided by the divider/scalar, we then convert to ms.
self->period = (args[0].u_int * TIMER_BASE_CLK) / (1000 * TIMER_DIVIDER);
self->repeat = args[1].u_int;
self->callback = args[2].u_obj;
self->handle = NULL;
machine_timer_enable(self);
return mp_const_none;
}
STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
machine_timer_disable(self_in);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
STATIC mp_obj_t machine_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
machine_timer_obj_t *self = self_in;
double result;
timer_get_counter_time_sec(self->group, self->index, &result);
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) },
{ MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) },
};
STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
const mp_obj_type_t machine_timer_type = {
{ &mp_type_type },
.name = MP_QSTR_Timer,
.print = machine_timer_print,
.make_new = machine_timer_make_new,
.locals_dict = (mp_obj_t)&machine_timer_locals_dict,
};

View File

@ -0,0 +1,110 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Nick Moore
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/touch_pad.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
typedef struct _mtp_obj_t {
mp_obj_base_t base;
gpio_num_t gpio_id;
touch_pad_t touchpad_id;
} mtp_obj_t;
STATIC const mtp_obj_t touchpad_obj[] = {
{{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0},
{{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1},
{{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2},
{{&machine_touchpad_type}, GPIO_NUM_15, TOUCH_PAD_NUM3},
{{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM4},
{{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM5},
{{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM6},
{{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7},
{{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8},
{{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9},
};
STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, true);
gpio_num_t pin_id = machine_pin_get_id(args[0]);
const mtp_obj_t *self = NULL;
for (int i = 0; i < MP_ARRAY_SIZE(touchpad_obj); i++) {
if (pin_id == touchpad_obj[i].gpio_id) { self = &touchpad_obj[i]; break; }
}
if (!self) mp_raise_ValueError("invalid pin for touchpad");
static int initialized = 0;
if (!initialized) {
touch_pad_init();
initialized = 1;
}
esp_err_t err = touch_pad_config(self->touchpad_id, 0);
if (err == ESP_OK) return MP_OBJ_FROM_PTR(self);
mp_raise_ValueError("Touch pad error");
}
STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) {
mtp_obj_t *self = self_in;
uint16_t value = mp_obj_get_int(value_in);
esp_err_t err = touch_pad_config(self->touchpad_id, value);
if (err == ESP_OK) return mp_const_none;
mp_raise_ValueError("Touch pad error");
}
MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config);
STATIC mp_obj_t mtp_read(mp_obj_t self_in) {
mtp_obj_t *self = self_in;
uint16_t value;
esp_err_t err = touch_pad_read(self->touchpad_id, &value);
if (err == ESP_OK) return MP_OBJ_NEW_SMALL_INT(value);
mp_raise_ValueError("Touch pad error");
}
MP_DEFINE_CONST_FUN_OBJ_1(mtp_read_obj, mtp_read);
STATIC const mp_rom_map_elem_t mtp_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&mtp_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mtp_read_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mtp_locals_dict, mtp_locals_dict_table);
const mp_obj_type_t machine_touchpad_type = {
{ &mp_type_type },
.name = MP_QSTR_TouchPad,
.make_new = mtp_make_new,
.locals_dict = (mp_obj_t)&mtp_locals_dict,
};

357
ports/esp32/machine_uart.c Normal file
View File

@ -0,0 +1,357 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "modmachine.h"
typedef struct _machine_uart_obj_t {
mp_obj_base_t base;
uart_port_t uart_num;
uint8_t bits;
uint8_t parity;
uint8_t stop;
int8_t tx;
int8_t rx;
int8_t rts;
int8_t cts;
uint16_t timeout; // timeout waiting for first char (in ms)
uint16_t timeout_char; // timeout waiting between chars (in ms)
} machine_uart_obj_t;
STATIC const char *_parity_name[] = {"None", "1", "0"};
/******************************************************************************/
// MicroPython bindings for UART
STATIC void machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
uint32_t baudrate;
uart_get_baudrate(self->uart_num, &baudrate);
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, tx=%d, rx=%d, rts=%d, cts=%d, timeout=%u, timeout_char=%u)",
self->uart_num, baudrate, self->bits, _parity_name[self->parity],
self->stop, self->tx, self->rx, self->rts, self->cts, self->timeout, self->timeout_char);
}
STATIC void machine_uart_init_helper(machine_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_tx, ARG_rx, ARG_rts, ARG_cts, 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_INT, {.u_int = UART_PIN_NO_CHANGE} },
{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
{ MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
{ MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
{ 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} },
};
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);
// wait for all data to be transmitted before changing settings
uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000));
// set baudrate
uint32_t baudrate = 115200;
if (args[ARG_baudrate].u_int > 0) {
uart_set_baudrate(self->uart_num, args[ARG_baudrate].u_int);
uart_get_baudrate(self->uart_num, &baudrate);
}
uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int);
if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) {
self->tx = args[ARG_tx].u_int;
}
if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) {
self->rx = args[ARG_rx].u_int;
}
if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) {
self->rts = args[ARG_rts].u_int;
}
if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) {
self->cts = args[ARG_cts].u_int;
}
// set data bits
switch (args[ARG_bits].u_int) {
case 0:
break;
case 5:
uart_set_word_length(self->uart_num, UART_DATA_5_BITS);
self->bits = 5;
break;
case 6:
uart_set_word_length(self->uart_num, UART_DATA_6_BITS);
self->bits = 6;
break;
case 7:
uart_set_word_length(self->uart_num, UART_DATA_7_BITS);
self->bits = 7;
break;
case 8:
uart_set_word_length(self->uart_num, UART_DATA_8_BITS);
self->bits = 8;
break;
default:
mp_raise_ValueError("invalid data bits");
break;
}
// set parity
if (args[ARG_parity].u_obj != MP_OBJ_NULL) {
if (args[ARG_parity].u_obj == mp_const_none) {
uart_set_parity(self->uart_num, UART_PARITY_DISABLE);
self->parity = 0;
} else {
mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj);
if (parity & 1) {
uart_set_parity(self->uart_num, UART_PARITY_ODD);
self->parity = 1;
} else {
uart_set_parity(self->uart_num, UART_PARITY_EVEN);
self->parity = 2;
}
}
}
// set stop bits
switch (args[ARG_stop].u_int) {
// FIXME: ESP32 also supports 1.5 stop bits
case 0:
break;
case 1:
uart_set_stop_bits(self->uart_num, UART_STOP_BITS_1);
self->stop = 1;
break;
case 2:
uart_set_stop_bits(self->uart_num, UART_STOP_BITS_2);
self->stop = 2;
break;
default:
mp_raise_ValueError("invalid stop bits");
break;
}
// set timeout
self->timeout = args[ARG_timeout].u_int;
// set timeout_char
// make sure it is at least as long as a whole character (13 bits to be safe)
self->timeout_char = args[ARG_timeout_char].u_int;
uint32_t min_timeout_char = 13000 / baudrate + 1;
if (self->timeout_char < min_timeout_char) {
self->timeout_char = min_timeout_char;
}
}
STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// get uart id
mp_int_t uart_num = mp_obj_get_int(args[0]);
if (uart_num < 0 || uart_num >= UART_NUM_MAX) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_num));
}
// Attempts to use UART0 from Python has resulted in all sorts of fun errors.
// FIXME: UART0 is disabled for now.
if (uart_num == UART_NUM_0) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) is disabled (dedicated to REPL)", uart_num));
}
// Defaults
uart_config_t uartcfg = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0
};
// create instance
machine_uart_obj_t *self = m_new_obj(machine_uart_obj_t);
self->base.type = &machine_uart_type;
self->uart_num = uart_num;
self->bits = 8;
self->parity = 0;
self->stop = 1;
self->rts = UART_PIN_NO_CHANGE;
self->cts = UART_PIN_NO_CHANGE;
self->timeout = 0;
self->timeout_char = 0;
switch (uart_num) {
case UART_NUM_0:
self->rx = UART_PIN_NO_CHANGE; // GPIO 3
self->tx = UART_PIN_NO_CHANGE; // GPIO 1
break;
case UART_NUM_1:
self->rx = 9;
self->tx = 10;
break;
case UART_NUM_2:
self->rx = 16;
self->tx = 17;
break;
}
// Remove any existing configuration
uart_driver_delete(self->uart_num);
// init the peripheral
// Setup
uart_param_config(self->uart_num, &uartcfg);
// RX and TX buffers are currently hardcoded at 256 bytes each (IDF minimum).
uart_driver_install(uart_num, 256, 256, 0, NULL, 0);
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
machine_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
// Make sure pins are connected.
uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t machine_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
machine_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_uart_init_obj, 1, machine_uart_init);
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
size_t rxbufsize;
uart_get_buffered_data_len(self->uart_num, &rxbufsize);
return MP_OBJ_NEW_SMALL_INT(rxbufsize);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
STATIC const mp_rom_map_elem_t machine_uart_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_uart_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_uart_locals_dict, machine_uart_locals_dict_table);
STATIC mp_uint_t machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
// make sure we want at least 1 char
if (size == 0) {
return 0;
}
TickType_t time_to_wait;
if (self->timeout == 0) {
time_to_wait = 0;
} else {
time_to_wait = pdMS_TO_TICKS(self->timeout);
}
int bytes_read = uart_read_bytes(self->uart_num, buf_in, size, time_to_wait);
if (bytes_read <= 0) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
return bytes_read;
}
STATIC mp_uint_t machine_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
int bytes_written = uart_write_bytes(self->uart_num, buf_in, size);
if (bytes_written < 0) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
// return number of bytes written
return bytes_written;
}
STATIC mp_uint_t machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
machine_uart_obj_t *self = self_in;
mp_uint_t ret;
if (request == MP_STREAM_POLL) {
mp_uint_t flags = arg;
ret = 0;
size_t rxbufsize;
uart_get_buffered_data_len(self->uart_num, &rxbufsize);
if ((flags & MP_STREAM_POLL_RD) && rxbufsize > 0) {
ret |= MP_STREAM_POLL_RD;
}
if ((flags & MP_STREAM_POLL_WR) && 1) { // FIXME: uart_tx_any_room(self->uart_num)
ret |= MP_STREAM_POLL_WR;
}
} else {
*errcode = MP_EINVAL;
ret = MP_STREAM_ERROR;
}
return ret;
}
STATIC const mp_stream_p_t uart_stream_p = {
.read = machine_uart_read,
.write = machine_uart_write,
.ioctl = machine_uart_ioctl,
.is_text = false,
};
const mp_obj_type_t machine_uart_type = {
{ &mp_type_type },
.name = MP_QSTR_UART,
.print = machine_uart_print,
.make_new = machine_uart_make_new,
.getiter = mp_identity_getiter,
.iternext = mp_stream_unbuffered_iter,
.protocol = &uart_stream_p,
.locals_dict = (mp_obj_dict_t*)&machine_uart_locals_dict,
};

78
ports/esp32/machine_wdt.c Normal file
View File

@ -0,0 +1,78 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Paul Sokolovsky
* Copyright (c) 2017 Eric Poulsen
*
* 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/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "esp_task_wdt.h"
const mp_obj_type_t machine_wdt_type;
typedef struct _machine_wdt_obj_t {
mp_obj_base_t base;
} machine_wdt_obj_t;
STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}};
STATIC mp_obj_t machine_wdt_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, 0, 1, false);
mp_int_t id = 0;
if (n_args > 0) {
id = mp_obj_get_int(args[0]);
}
switch (id) {
case 0:
esp_task_wdt_add(NULL);
return &wdt_default;
default:
mp_raise_ValueError(NULL);
}
}
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
(void)self_in;
esp_task_wdt_reset();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
};
STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
const mp_obj_type_t machine_wdt_type = {
{ &mp_type_type },
.name = MP_QSTR_WDT,
.make_new = machine_wdt_make_new,
.locals_dict = (mp_obj_t)&machine_wdt_locals_dict,
};

146
ports/esp32/main.c Normal file
View File

@ -0,0 +1,146 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Development of the code in this file was sponsored by Microbric Pty Ltd
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_task.h"
#include "soc/cpu.h"
#include "esp_log.h"
#include "py/stackctrl.h"
#include "py/nlr.h"
#include "py/compile.h"
#include "py/runtime.h"
#include "py/repl.h"
#include "py/gc.h"
#include "py/mphal.h"
#include "lib/mp-readline/readline.h"
#include "lib/utils/pyexec.h"
#include "uart.h"
#include "modmachine.h"
#include "modnetwork.h"
#include "mpthreadport.h"
// MicroPython runs as a task under FreeRTOS
#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
#define MP_TASK_STACK_SIZE (16 * 1024)
#define MP_TASK_STACK_LEN (MP_TASK_STACK_SIZE / sizeof(StackType_t))
STATIC StaticTask_t mp_task_tcb;
STATIC StackType_t mp_task_stack[MP_TASK_STACK_LEN] __attribute__((aligned (8)));
int vprintf_null(const char *format, va_list ap) {
// do nothing: this is used as a log target during raw repl mode
return 0;
}
void mp_task(void *pvParameter) {
volatile uint32_t sp = (uint32_t)get_sp();
#if MICROPY_PY_THREAD
mp_thread_init(&mp_task_stack[0], MP_TASK_STACK_LEN);
#endif
uart_init();
// Allocate the uPy heap using malloc and get the largest available region
size_t mp_task_heap_size = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
void *mp_task_heap = malloc(mp_task_heap_size);
soft_reset:
// initialise the stack pointer for the main thread
mp_stack_set_top((void *)sp);
mp_stack_set_limit(MP_TASK_STACK_SIZE - 1024);
gc_init(mp_task_heap, mp_task_heap + mp_task_heap_size);
mp_init();
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
mp_obj_list_init(mp_sys_argv, 0);
readline_init0();
// initialise peripherals
machine_pins_init();
// run boot-up scripts
pyexec_frozen_module("_boot.py");
pyexec_file("boot.py");
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
pyexec_file("main.py");
}
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
if (pyexec_raw_repl() != 0) {
break;
}
esp_log_set_vprintf(vprintf_log);
} else {
if (pyexec_friendly_repl() != 0) {
break;
}
}
}
#if MICROPY_PY_THREAD
mp_thread_deinit();
#endif
gc_sweep_all();
mp_hal_stdout_tx_str("PYB: soft reboot\r\n");
// deinitialise peripherals
machine_pins_deinit();
usocket_events_deinit();
mp_deinit();
fflush(stdout);
goto soft_reset;
}
void app_main(void) {
nvs_flash_init();
xTaskCreateStaticPinnedToCore(mp_task, "mp_task", MP_TASK_STACK_LEN, NULL, MP_TASK_PRIORITY,
&mp_task_stack[0], &mp_task_tcb, 0);
}
void nlr_jump_fail(void *val) {
printf("NLR jump failed, val=%p\n", val);
esp_restart();
}
// modussl_mbedtls uses this function but it's not enabled in ESP IDF
void mbedtls_debug_set_threshold(int threshold) {
(void)threshold;
}

25
ports/esp32/makeimg.py Normal file
View File

@ -0,0 +1,25 @@
import sys
OFFSET_BOOTLOADER = 0x1000
OFFSET_PARTITIONS = 0x8000
OFFSET_APPLICATION = 0x10000
files_in = [
('bootloader', OFFSET_BOOTLOADER, sys.argv[1]),
('partitions', OFFSET_PARTITIONS, sys.argv[2]),
('application', OFFSET_APPLICATION, sys.argv[3]),
]
file_out = sys.argv[4]
cur_offset = OFFSET_BOOTLOADER
with open(file_out, 'wb') as fout:
for name, offset, file_in in files_in:
assert offset >= cur_offset
fout.write(b'\xff' * (offset - cur_offset))
cur_offset = offset
with open(file_in, 'rb') as fin:
data = fin.read()
fout.write(data)
cur_offset += len(data)
print('%-12s% 8d' % (name, len(data)))
print('%-12s% 8d' % ('total', cur_offset))

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