Merge branch 'master' into nrf52840_usb_hid
This commit is contained in:
commit
1e524f1b98
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -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
2
.gitmodules
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
1
conf.py
1
conf.py
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
57
drivers/bus/qspi.h
Normal 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
203
drivers/bus/softqspi.c
Normal 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
105
drivers/bus/softspi.c
Normal 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
55
drivers/bus/spi.h
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) },
|
||||
};
|
||||
|
188
extmod/modlwip.c
188
extmod/modlwip.c
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) },
|
||||
|
@ -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);
|
||||
|
@ -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} },
|
||||
};
|
||||
|
@ -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 = {
|
||||
|
@ -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));
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
46
extmod/vfs.c
46
extmod/vfs.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
120
extmod/vfs_fat.c
120
extmod/vfs_fat.c
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
363
extmod/vfs_posix.c
Normal 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
|
@ -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
261
extmod/vfs_posix_file.c
Normal 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
|
@ -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
|
@ -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
|
||||
|
@ -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? */
|
||||
|
@ -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) {
|
126
lib/upytesthelper/upytesthelper.c
Normal file
126
lib/upytesthelper/upytesthelper.c
Normal 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();
|
||||
}
|
37
lib/upytesthelper/upytesthelper.h
Normal file
37
lib/upytesthelper/upytesthelper.h
Normal 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);
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
38
ports/atmel-samd/boards/hallowing_m0_express/board.c
Normal file
38
ports/atmel-samd/boards/hallowing_m0_express/board.c
Normal 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) {
|
||||
}
|
63
ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h
Normal file
63
ports/atmel-samd/boards/hallowing_m0_express/mpconfigboard.h
Normal 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
|
@ -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
|
60
ports/atmel-samd/boards/hallowing_m0_express/pins.c
Normal file
60
ports/atmel-samd/boards/hallowing_m0_express/pins.c
Normal 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);
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) },
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
786
ports/esp32/Makefile
Normal 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
202
ports/esp32/README.md
Normal 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
126
ports/esp32/README.ulp.md
Normal 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)
|
||||
```
|
254
ports/esp32/esp32.custom_common.ld
Normal file
254
ports/esp32/esp32.custom_common.ld
Normal 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
97
ports/esp32/esp32_ulp.c
Normal 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
53
ports/esp32/espneopixel.c
Normal 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
80
ports/esp32/esponewire.c
Normal 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
41
ports/esp32/fatfs_port.c
Normal 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
66
ports/esp32/gccollect.c
Normal 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
42
ports/esp32/gccollect.h
Normal 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
65
ports/esp32/help.c
Normal 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
132
ports/esp32/machine_adc.c
Normal 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
97
ports/esp32/machine_dac.c
Normal 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,
|
||||
};
|
390
ports/esp32/machine_hw_spi.c
Normal file
390
ports/esp32/machine_hw_spi.c
Normal 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
414
ports/esp32/machine_pin.c
Normal 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
277
ports/esp32/machine_pwm.c
Normal 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
162
ports/esp32/machine_rtc.c
Normal 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
44
ports/esp32/machine_rtc.h
Normal 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
192
ports/esp32/machine_timer.c
Normal 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,
|
||||
};
|
110
ports/esp32/machine_touchpad.c
Normal file
110
ports/esp32/machine_touchpad.c
Normal 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
357
ports/esp32/machine_uart.c
Normal 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
78
ports/esp32/machine_wdt.c
Normal 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
146
ports/esp32/main.c
Normal 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
25
ports/esp32/makeimg.py
Normal 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
Loading…
Reference in New Issue
Block a user