Compare commits

..

403 Commits
v1.6 ... v1.7

Author SHA1 Message Date
Damien George
9b0a150bd6 docs: Bump version to 1.7. 2016-04-11 12:18:10 +01:00
Paul Sokolovsky
f8fb4470a0 extmod/modwebsocket: write(): Support write size beyond 125 bytes. 2016-04-11 14:07:57 +03:00
Paul Sokolovsky
7063210014 extmod/modlwip: Fix for loss of data in unaccepted incoming sockets.
When lwIP creates a incoming connection socket of a listen socket, it
sets its recv callback to one which discards incoming data. We set
proper callback only in accept() call, when we allocate Python-level
socket where we can queue incoming data. So, in lwIP accept callback
be sure to set recv callback to one which tells lwIP to not discard
incoming data.
2016-04-11 01:21:34 +03:00
Paul Sokolovsky
1cc81ed449 esp8266/modesp: Add freemem() and meminfo() functions.
They call into vendor SDK functions system_get_free_heap_size() and
system_print_meminfo() respectively.
2016-04-11 01:16:38 +03:00
Paul Sokolovsky
c734de490a esp8266/main: mp_builtin_open(): Implement, using vfs_proxy_call(). 2016-04-10 16:59:19 +03:00
Damien George
358e5d8bad py/stream: Move uPy func obj wrappers to below their respective funcs. 2016-04-10 12:41:28 +01:00
Damien George
657aef66ff py/stream: Simplify arg extraction logic for stream_ioctl.
Saves 16 bytes of code.

Also, use mp_obj_get_int_truncated to allow integers as big as a machine
word to be passed as the value.
2016-04-10 12:37:59 +01:00
Damien George
6e87aeb841 esp8266: Implement multistage bootstrap sequence.
Upon start-up, _boot module is executed from frozen files to do early
initialization, e.g. create and mount the flash filesystem. Then
"boot.py" is executed if it exists in the filesystem. Finally, "main.py"
is executed if exists to allow start-on-boot user applications.

This allows a user to make a custom boot file or startup application
without recompiling the firmware, while letting to do early initialization
in Python code.

Based on RFC https://github.com/micropython/micropython/issues/1955.
2016-04-10 14:24:41 +03:00
Paul Sokolovsky
b69f798c92 extmod/modwebsocket.h: Split websocket-related defines for reuse. 2016-04-10 13:42:51 +03:00
Paul Sokolovsky
558fd5d228 py/stream: ioctl(): Properly support 2-arg form. 2016-04-10 13:36:44 +03:00
Paul Sokolovsky
6c3db26ab7 py/stream: Fix signed comparison issue. 2016-04-10 13:31:52 +03:00
Paul Sokolovsky
d6236e85c2 extmod/modwebsocket: Implement MP_STREAM_SET_DATA_OPTS ioctl.
Allows to set fragment type (txt/bin/etc.) for output records.
2016-04-10 13:19:26 +03:00
Paul Sokolovsky
6837dba6b8 extmod/modwebsocket: Allow to get type of last read data using ioctl(). 2016-04-10 12:50:46 +03:00
Paul Sokolovsky
0c97e4c414 py/stream: Add Python-level ioctl() method.
Will call underlying C virtual methods of stream interface. This isn't
intended to be added to every stream object (it's not in CPython), but
is convenient way to expose extra operation on Python side without
adding bunch of Python-level methods.
2016-04-10 12:45:46 +03:00
Paul Sokolovsky
a45e280c58 py/stream.h: Add bigger inventory of stream ioctl's. 2016-04-10 12:42:41 +03:00
Paul Sokolovsky
f38e8f5217 extmod/modwebsocket: Record current fragment type (binary/text/etc.)
Also, handle continuation frames (untested).
2016-04-09 16:14:47 +03:00
Paul Sokolovsky
5b1c221785 extmod/modwebsocket: Add option for blocking writes to non-blk sockets.
This is strange asymmetry which is sometimes needed, e.g. for WebREPL: we
want to process only available input and no more; but for output, we want
to get rid of all of it, because there's no other place to buffer/store
it. This asymmetry is akin to CPython's asyncio asymmetry, where reads are
asynchronous, but writes are synchronous (asyncio doesn't expect them to
block, instead expects there to be (unlimited) buffering for any sync write
to completely immediately).
2016-04-09 16:03:38 +03:00
Paul Sokolovsky
397b705647 extmod/modwebsocket: Reset mask between packets. 2016-04-09 12:29:18 +03:00
Paul Sokolovsky
7e9182f3aa extmod/modwebsocket: Make sure to propagate EOF. 2016-04-08 20:26:54 +03:00
pohmelie
b32b0d38fe unix: freedos strip and size names for binaries
After this you need only one path for build (path/to/djgpp/bin). Original patch made by @dhylands
2016-04-08 20:15:37 +03:00
Tom Sparks
20d9bc2d76 extmod/modure: re_exec() renamed to ure_exec() due to collison in 4.3BSD.
Addresses issue #1972.
2016-04-08 20:12:03 +03:00
Paul Sokolovsky
05ba2433f6 extmod/modwebsocket: Properly check number of args to constructor. 2016-04-08 16:05:48 +03:00
Paul Sokolovsky
5e919b7ef8 lib/axtls: Update to the latest upstream master. 2016-04-08 15:19:57 +03:00
Paul Sokolovsky
9c04299da1 docs: esp8266: Enable "machine" module docs.
The docs are still heavily biased towards WiPy, so will need a lot of
exclusions.
2016-04-07 16:44:10 +03:00
Paul Sokolovsky
5e7fa7c80c docs/ubinascii: Document non-standard "sep" argument to hexlify(). 2016-04-07 12:39:00 +03:00
Martin Fischer
8a8e775035 stmhal: Consistently enable USB SOF Irqs for all USB modes (FS and HS).
SOF irqs are now standard for rx/tx USB transfers, so enable them for both
FS and HS modes.  Fixes #1944.
2016-04-07 09:23:33 +01:00
Damien George
04d5e644fc py/objarray: Fix array.append so it doesn't extend if append fails.
Addresses issue #1965.
2016-04-07 09:03:33 +01:00
Damien George
2c915e1ae6 py: Implement basic with support in native emitter. 2016-04-07 08:53:24 +01:00
Damien George
ce8b4e8749 py: Combine continuous block of emit steps into with_cleanup emit call.
Because different emitters need to handle with-cleanup in different ways.
2016-04-07 08:50:38 +01:00
Damien George
2c407bcf20 esp8266: Switch from terse error messages to normal ones.
Adds 2k to the code size.
2016-04-07 00:38:08 +03:00
Paul Sokolovsky
d85439fd19 esp8266/README: Add short troubleshooting section. 2016-04-07 00:21:04 +03:00
Damien George
1a0a323ca8 esp8266: Add initial implementation of machine.UART.
Currently UART(0) and UART(1) are exposed and only uart.write works.
2016-04-06 19:45:52 +03:00
Paul Sokolovsky
4e51a3038c cc3200/mods/modwlan: Include stream.h after recent refactor. 2016-04-06 01:18:39 +03:00
Damien George
96eca22322 esp8266: Make destination for vendor OS debug output soft-configurable.
Use esp.osdebug(None) to disable, or esp.osdebug(uart_id) to send output
to a UART.
2016-04-06 00:12:58 +03:00
Paul Sokolovsky
e6a4d4e23c py: Move stream-related declarations from obj.h to stream.h. 2016-04-05 22:06:52 +03:00
Paul Sokolovsky
e4cb7c6158 docs/esp8266/quickref: Add note about physical vs logical pin numbers. 2016-04-05 16:30:51 +03:00
Paul Sokolovsky
2c8356c482 esp8266/modnetwork: require_if(): Report the actual interface required. 2016-04-05 16:09:03 +03:00
Paul Sokolovsky
f81ea6307c docs/ubinascii: Document a2b_base64(), b2a_base64(). 2016-04-05 14:00:12 +03:00
Paul Sokolovsky
de12502d89 esp8266: Move pyb.unique_id() to machine.unique_id(). 2016-04-05 00:57:49 +03:00
Paul Sokolovsky
81fd5685fc esp8266: Move pyb.hard_reset() to machine.reset(). 2016-04-05 00:20:25 +03:00
Paul Sokolovsky
1b811b946e unix/modsocket: Use mp_const_empty_map instead of creating empty map. 2016-04-04 23:43:16 +03:00
Paul Sokolovsky
069654f2be py/obj.h: Add comment why mp_fun_kw_t takes non-const mp_map_t*.
mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing
this arg to mp_map_lookup(), which may modify its arg, depending on
flags.
2016-04-04 15:37:19 +03:00
pohmelie
cee888255b unix: djgpp errno.h have no ENOTSUP, so define it to Linux value. 2016-04-03 23:23:01 +03:00
Paul Sokolovsky
28d4b94dce docs/machine: Change wording to be a bit more port-neutral. 2016-04-03 20:49:29 +03:00
Paul Sokolovsky
69b702276b docs/os: Change wording to be a bit more port-neutral. 2016-04-03 20:49:25 +03:00
Paul Sokolovsky
e24674d44e docs: esp8266: esp.socket is deprecated, remove from docs. 2016-04-03 20:19:39 +03:00
Paul Sokolovsky
69256ac0b1 esp8266: Bump heap size to 24k. 2016-04-03 19:55:45 +03:00
Paul Sokolovsky
debbaac1bd esp8266: Update flashing instructions in README. 2016-04-03 16:04:18 +03:00
Paul Sokolovsky
919b70b7ec esp8266: Switch back to flashing combined firmware (single file).
With gap between segments minimized, there's not much padding to flash,
so no big speed overhead.
2016-04-03 15:48:46 +03:00
Paul Sokolovsky
8d2bcaf3cd esp8266: Minimize gap between Inst/DataRAM segments and FlashROM segment.
With .rodata being in FlashROM now, gap can be much smaller now. InstRAM
can be max 32K, and with segment headers, that already makes it more than
32K. Then there's some .data still, and the next Flash page boundary is
0x9000. That figure should be more or less future-proof.

TODO: Refactor makeimg to take FlashROM segment offset from file name.
2016-04-03 15:45:14 +03:00
Paul Sokolovsky
9698a60591 esp8266/ets_alt_task: Comment out debug output. 2016-04-03 01:04:01 +03:00
Paul Sokolovsky
fcd6862597 esp8266: Bump iROM size to 512k.
Needed for frozen scripts, and for future growth of binary.
2016-04-03 00:57:27 +03:00
Paul Sokolovsky
ef0c5db2ed esp8266: Move .rodata where it belongs with -mforce-l32 help. 2016-04-03 00:51:51 +03:00
Paul Sokolovsky
254a5646c1 docs: Update copyright notice. 2016-04-03 00:05:23 +03:00
Paul Sokolovsky
333a63efaa esp8266/README: Add link to docs. 2016-04-03 00:01:31 +03:00
Paul Sokolovsky
4f2d59e82f examples/http_client_ssl.py: HTTPS client example. 2016-04-02 23:19:03 +03:00
Paul Sokolovsky
ec5f8db49d examples/http_server.py: Bind to 0.0.0.0, to be accessible from other hosts.
This is helpful when running on deeply embedded targets, but may be
"security risk". Caveat emptor.
2016-04-02 23:14:19 +03:00
Paul Sokolovsky
c07a03a36d examples/http_server.py: Introduce main() function.
Allows to re-run code if it was imported as a module (e.g., on bare-metal
ports).
2016-04-02 20:57:58 +03:00
Paul Sokolovsky
aa3fb7b387 examples/http_server.py: Refactor/simplify for Python 3.5. 2016-04-02 20:53:29 +03:00
Paul Sokolovsky
fd2b71f972 examples/http_client.py: Introduce main() function.
Allows to re-run code if it was imported as a module (e.g., on bare-metal
ports).
2016-04-02 19:13:39 +03:00
Paul Sokolovsky
a5d07c3aba examples/http_client.py: Improve CPython compatibility in stream mode. 2016-04-02 17:28:42 +03:00
Paul Sokolovsky
a5d2af7949 unix/file: "encoding" arg to open() isn't kw-only.
And with "buffering" arg introduced, it's non possible to make it
non-kwonly.
2016-04-02 17:23:51 +03:00
Paul Sokolovsky
e5fa163a4c unix/file: Parse "buffering" argument of open() builtin.
It's ignored (unbuffered, raw I/O is used), but least makes it compatible
with CPython.
2016-04-02 17:23:46 +03:00
Damien George
a0cb4eda9a esp8266: Use VM_HOOK to call ets_loop_iter within the VM.
Starting with a divisor of 10, pystone_lowmem gives a score of 256.
2016-04-02 01:34:32 +03:00
Paul Sokolovsky
cef073877b example/http_client.py: Remove unused code. 2016-04-01 21:10:06 +03:00
Paul Sokolovsky
cf4b72bf13 examples: http_client.py, http_server.py aren't just unix, move to network/. 2016-04-01 20:53:23 +03:00
Stephen Kyle
b475327ffa py/map: Prevent map resize failure from destroying map. 2016-04-01 16:36:00 +03:00
Damien George
6a051a8e0b esp8266/uart: Get ctrl-C working now that event-based REPL is disabled. 2016-04-01 14:53:01 +03:00
Damien George
fb6cc96951 esp8266/uart: Comment out old, unused rx buffering code.
This was originally used for non-event based REPL processing.  Then it
was unused when event-based processing was activated.  But now that event
based is disabled, and non-event based is back, there has been new ring
buffer code to process the chars.
2016-04-01 14:30:47 +03:00
Paul Sokolovsky
fc4c43a72e esp8266: Switch to non event-driven REPL to support paste mode. 2016-04-01 14:22:28 +03:00
Paul Sokolovsky
785cf9a61f esp8266: Support dedicated REPL loop (aka pull-style).
Event-driven loop (push-style) is still supported and default (controlled
by MICROPY_REPL_EVENT_DRIVEN setting, as expected).

Dedicated loop worked even without adding ets_loop_iter(), though that
needs to be revisited later.
2016-04-01 14:02:36 +03:00
Paul Sokolovsky
777232c9a5 esp8266: Disallow recursive calls to REPL.
Before this change, if REPL blocked executing some code, it was possible
to still input new statememts and excuting them, all leading to weird,
and portentially dangerous interaction.

TODO: Current implementation may have issues processing input accumulated
while REPL was blocked.
2016-04-01 12:53:50 +03:00
Pavol Rusnak
3d4a535208 unix: implement -i option (inspect - start REPL after script is finished) 2016-04-01 12:35:45 +03:00
Paul Sokolovsky
5531437941 esp8266: Move PHY mode constants from modesp to modnetwork. 2016-04-01 12:10:11 +03:00
Damien George
4b597a1c1a esp8266: Reset term_obj on reboot.
Also, term_obj can be NULL if socket enables REPL duplication signalling
before os.dupterm is called, so it should be checked.
2016-03-31 19:56:52 +03:00
Paul Sokolovsky
98af891610 esp8266: Implement input part of dupterm handling.
The idea is following: underlying interrupt-driven or push-style data source
signals that more data is available for dupterm processing via call to
mp_hal_signal_dupterm_input(). This triggers a task which pumps data between
actual dupterm object (which may perform additional processing on data from
low-level data source) and input ring buffer.
2016-03-31 19:49:55 +03:00
Paul Sokolovsky
61fa7c8152 esp8266: Switch back to accumulating input data via ring buffer.
But now it's generic ring buffer implemented via ringbuf.h, and is intended
for any type of input, including dupterm's, not just UART. The general
process work like this: an interrupt-driven input source puts data into
input_buf, and then signals new data available via call to
mp_hal_signal_input().
2016-03-30 18:50:38 +03:00
Paul Sokolovsky
2e75a17bab esp8266: Fix issue when current repl line was garbage-collected.
Reference it from root pointers section.
2016-03-30 18:13:03 +03:00
Paul Sokolovsky
b1dfdaf6cb py/ringbuf.h: Add reusable ring buffer class.
Features inline get/put operations for the highest performance. Locking
is not part of implementation, operation should be wrapped with locking
externally as needed.
2016-03-30 14:48:31 +03:00
Paul Sokolovsky
f50d9477c1 docs: network: esp8266: .scan() is now synchronous and returns result list. 2016-03-30 11:56:20 +03:00
Paul Sokolovsky
d7019d0628 docs: network: esp8266: status is WLAN object method. 2016-03-30 11:53:45 +03:00
Damien George
9475cc59e6 esp8266: Support synchronous wifi scanning.
That is: aps = if0.scan()

TODO: make sure that returned list has tuple with values in "standard"
order (whatever that standard is).
2016-03-30 11:35:03 +03:00
Damien George
2599672384 py/parsenum: Use pow function to apply exponent to decimal number.
Pow is already a dependency when compiling with floats, so may as well
use it here to reduce code size and speed up the conversion for most
cases.
2016-03-29 22:12:07 +01:00
Damien George
e1e7657277 py/formatfloat: Fix further cases of buffer overflow in formatting.
Includes extensive test cases to catch hopefully all cases where
buffer might overflow.
2016-03-29 22:07:15 +01:00
Damien George
03b8bb7ec9 py/formatfloat: Fix case of float format where leading digit was "10".
When taking the logarithm of the float to determine the exponent, there
are some edge cases that finish the log loop too large.  Eg for an
input value of 1e32-epsilon, this is actually less than 1e32 from the
log-loop table and finishes as 10.0e31 when it should be 1.0e32.  It
is thus rendered as :e32 (: comes after 9 in ascii).

There was the same problem with numbers less than 1.
2016-03-29 22:03:13 +01:00
Paul Sokolovsky
d88250c06e esp8266: Reduce heap size for now to avoid random segfaults on WiFi connect. 2016-03-29 21:14:41 +03:00
Paul Sokolovsky
c4506ed869 esp8266: Let esp8266 "os" messages go to standard (REPL) UART.
That's definitely helpful for debugging.
2016-03-29 21:10:10 +03:00
Paul Sokolovsky
402a743821 esp8266/esp_mphal: Add support for debug UART-only output.
Helpful when debugging dupterm support (because otherwise all output is
spooled to dupterm too).

To use:

mp_printf(&mp_debug_print, "...");
2016-03-29 11:48:43 +03:00
Paul Sokolovsky
8fc5e56a6a esp8266: Enable uos.dupterm() method. 2016-03-29 11:41:23 +03:00
Paul Sokolovsky
c961889e34 esp8266: Add basic support for duplicating REPL output. 2016-03-29 11:13:32 +03:00
Damien George
6ca17c1922 esp8266: Implement os.urandom function.
Uses what is suspected to be a hardware random number generator.
2016-03-29 10:29:57 +03:00
Paul Sokolovsky
b4070ee8a4 esp8266: Allow to build without FatFs support again. 2016-03-28 21:35:41 +03:00
Paul Sokolovsky
2f02302e22 esp8266: Support importing modules from filesystem. 2016-03-28 18:39:34 +03:00
danicampora
193795398d docs: Correct pin interrupt example code for the WiPy. 2016-03-28 13:12:58 +02:00
Damien George
71d40f132d esp8266: Zero out fs_user_mount state on (soft) reset.
Otherwise device stays mounted on soft reset and leads to corruption
(since block device object is now gone).
2016-03-28 13:28:41 +03:00
Paul Sokolovsky
9edd736ee6 esp8266/moduos: Add os.remove(), proxying to VFS object. 2016-03-28 12:50:07 +03:00
Paul Sokolovsky
e8e116e7fc esp8266/moduos: Factor out VFS method proxy helper. 2016-03-28 12:44:36 +03:00
Paul Sokolovsky
8b08a0d9ed esp8266/moduos: Add listdir() proxy for MP_STATE_PORT(fs_user_mount)[0].
I.e. os.listdir(...) will redirect to
MP_STATE_PORT(fs_user_mount)[0].listdir(...).
2016-03-28 12:29:47 +03:00
Damien George
61230e007d esp8266/moduos: Use mp_rom_map_elem_t for static const dictionary. 2016-03-28 12:08:36 +03:00
Paul Sokolovsky
b01a373adb esp8266: deploy: Use --flash_size=8m option to esptool.py.
Most esp8266 modules have at least 1MB (8Mbit) of flash. If not set, vendor
functions allow to access only first 512K.
2016-03-28 11:28:16 +03:00
Paul Sokolovsky
cd6194aefc esp8266/esp8266.ld: Put FatFs to FlashROM. 2016-03-27 17:15:25 +03:00
Paul Sokolovsky
374654f2b8 esp8266: Enable FatFs support. 2016-03-27 17:13:47 +03:00
Paul Sokolovsky
fe9bc0c573 esp8266/README: Update for the current status of the port. 2016-03-27 16:10:58 +03:00
Paul Sokolovsky
bbc65d4eda esp8266/modesp: flash_read(): Accept buffer to read to as a second argument. 2016-03-27 15:34:35 +03:00
Paul Sokolovsky
fd86bf5917 esp8266/modesp: flash_write(): Writes in multiples of 4 bytes. 2016-03-27 15:32:58 +03:00
Paul Sokolovsky
53302f1616 esp8266: Set up UART handling task soon into init process.
Otherwise, events may be posted to non-initialized task, which leads to
segfaults.
2016-03-27 14:33:17 +03:00
Paul Sokolovsky
651a188299 extmod/vfs_fat_diskio: Actually support sectors != 512 with Python blockdevs. 2016-03-27 14:21:06 +03:00
Paul Sokolovsky
13394a632d unix/unix_mphal: Hack to make uos.dupterm() actually work.
See https://github.com/micropython/micropython/issues/1736 for the
list of complications. This workaround instead of duplicating REPL
to another stream, switches to it, because read(STDIN) we use otherwise
is blocking call, so it and custom REPL stream can't be used together.
2016-03-27 14:02:03 +03:00
Paul Sokolovsky
53ad5edc01 py/stream: Fix stupid thinko with variable naming/shadowing. 2016-03-27 12:58:33 +03:00
Paul Sokolovsky
87c783b454 docs/esp8266: esp.mac() replaced with network.WLAN.mac(). 2016-03-27 06:59:39 +03:00
Paul Sokolovsky
679fe0abae docs/esp8266: esp.wifi_mode() replaced with network.WLAN.active(). 2016-03-27 06:59:00 +03:00
Paul Sokolovsky
eda8746324 docs/esp8266: phy_mode() moved to network module. 2016-03-27 06:58:06 +03:00
Paul Sokolovsky
935e021250 esp8266: Put modpybi2c.o to FlashROM. 2016-03-26 10:59:25 +02:00
Damien George
c33a76059f esp8266/tests: Add neopixel.py test. 2016-03-26 10:55:29 +02:00
Damien George
3962766be0 esp8266: Add esp.neopixel_write function to bit-bang WS2812 data. 2016-03-26 10:55:21 +02:00
Damien George
b62beadae0 esp8266: Link ADC class into machine module. 2016-03-26 00:41:37 +02:00
Paul Sokolovsky
f71c0699a5 esp8266: Put utils.o to FlashROM. 2016-03-26 00:39:51 +02:00
Paul Sokolovsky
9c7e3353e5 esp8266: Put lexerstr32.o into FlashROM. 2016-03-26 00:39:02 +02:00
Paul Sokolovsky
ba640bde55 esp8266/esppwm.c: Fix IRQ handler prototype. 2016-03-26 00:34:28 +02:00
Damien George
632d8efa05 esp8266: Add PWM support.
PWM implementation uses a timer and interrupts (FRC1), taken from
Espressif's/NodeMCU's implementation and adapted for our use.

8 channels are supported, on pins 0, 2, 4, 5, 12, 13, 14, 15.

Usage:

    import machine
    pwm0 = machine.PWM(machine.Pin(0))
    pwm0.freq(1000)
    pwm0.duty(500)

Frequency is shared (ie the same) for all channels.  Frequency is
between 1 and 1000.  Duty is between 0 and 1023.
2016-03-26 00:32:37 +02:00
Damien George
82b95f625e esp8266: Implement software SPI class.
Supports speeds up to 500k baud, polarity=0/1, phase=0/1, and using any
pins.  Only supports MSB output at the moment.
2016-03-25 23:28:13 +02:00
Paul Sokolovsky
91031a75a1 extmod/modlwip: lwip_socket_setsockopt: Handle option value properly. 2016-03-25 20:53:52 +02:00
Paul Sokolovsky
4332d72fd8 extmod/modlwip: Add lwip->POSIX error map for lwIP 1.4.0.
Between 1.4.0 and 1.4.1, lwIP errors were renumbered.
2016-03-25 20:32:01 +02:00
Paul Sokolovsky
de0c84ebf1 extmod/modlwip: lwip_tcp_send: Handle properly send buffer full condition.
Per POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html :
"If space is not available at the sending socket to hold the message to be
transmitted, and the socket file descriptor does not have O_NONBLOCK set,
send() shall block until space is available. If space is not available at the
sending socket to hold the message to be transmitted, and the socket file
descriptor does have O_NONBLOCK set, send() shall fail [with EAGAIN]."
2016-03-25 18:38:13 +02:00
Paul Sokolovsky
5e75f335e6 extmod/modlwip: Implement setsocketopt(SO_REUSEADDR). 2016-03-25 17:44:24 +02:00
Paul Sokolovsky
0cb10b5220 docs/esp8266/quickref: Add note about GPIO16. 2016-03-25 16:48:15 +02:00
Paul Sokolovsky
159f1aaca8 docs/esp8266/quickref: Note that timers supported are virtual ones. 2016-03-25 16:44:13 +02:00
Paul Sokolovsky
e589cddcd4 docs/esp: Remove getaddrinfo(), now in socket module as expected. 2016-03-25 16:39:18 +02:00
Paul Sokolovsky
6e6488530e docs: More standard modules for esp8266. 2016-03-25 16:33:05 +02:00
Paul Sokolovsky
4b5606bc09 docs/network: esp8266: Update docs on WLAN constructor. 2016-03-25 16:30:06 +02:00
Paul Sokolovsky
ee6fcc6f91 docs: Add standard modules list for esp8266. 2016-03-25 15:17:55 +02:00
Paul Sokolovsky
96a644076d docs/topindex.html: Refer to "pyb" module only for pyboard. 2016-03-25 15:12:26 +02:00
Paul Sokolovsky
8f1854ad2d extmod/modlwip: Add SOL_SOCKET and SO_REUSEADDR constants for setsockopt(). 2016-03-25 15:06:12 +02:00
Paul Sokolovsky
ac671546d1 esp8266/README: Remove outdated reference to initial port heap size. 2016-03-25 15:02:23 +02:00
Paul Sokolovsky
88f60de914 tests: Add test for io.BufferedWriter. 2016-03-25 15:01:19 +02:00
Paul Sokolovsky
2c81b9be28 py/modio: io.BufferedWriter: Describe flushing policy. 2016-03-25 14:59:30 +02:00
Paul Sokolovsky
063e6e7d0a py/modio: Implement io.BufferedWriter.flush(). 2016-03-25 14:33:38 +02:00
Paul Sokolovsky
5d93dfbc2c py/modio: Initial implementation of io.BufferedWriter class.
Just .write() method implemented currently.
2016-03-25 01:10:49 +02:00
Paul Sokolovsky
3dbd2ee926 extmod/modwebsocket: Implement read support. 2016-03-25 00:51:51 +02:00
Paul Sokolovsky
4a02a8f74d py/stream: Fix object vs ptr usecase in mp_stream_writeall(). 2016-03-24 19:43:08 +02:00
Paul Sokolovsky
24342dd65e extmod/modwebsocket: Start module for WebSocket helper functions.
Currently, only write support is implemented (of limited buffer size).
2016-03-24 19:16:00 +02:00
Paul Sokolovsky
d4c8e626f2 py/stream: Add mp_stream_writeall() helper function.
Spools entire output buffer to a blocking stream (chunk by chunk if
needed).
2016-03-24 19:09:00 +02:00
Damien George
a5d48b1162 esp8266: Add tests/onewire.py as a driver and test code for ds18b20 dev. 2016-03-24 17:35:26 +02:00
Damien George
78d0dde562 esp8266: Add onewire helper functions as C module.
Includes functions to read and write bits and bytes.
2016-03-24 17:33:42 +02:00
Damien George
0cdbd356fd esp8266: Implement bit-bang I2C read, and add i2c.readfrom method.
I2C reading tested with TSL2561 luminosity sensor.
2016-03-24 11:46:05 +02:00
Damien George
5b9f361824 esp8266: Clean up bit-bang I2C implementation.
Changed from using set_sda_scl function to independent set_sda and
set_scl functions.
2016-03-24 11:37:52 +02:00
Paul Sokolovsky
667d64b430 esp8266/modpybi2c: Add missing include. 2016-03-24 11:21:36 +02:00
Damien George
dd32f02cc3 esp8266: Add basic I2C driver, with init and writeto methods.
Tested and working with SSD1306 I2C display.
2016-03-24 11:17:17 +02:00
Damien George
7059c8c23c esp8266: Expose pin object as a public structure for use as C pin API.
This is an initial attempt at making a simple C pin API for writing
things like I2C drivers in C.
2016-03-24 11:07:41 +02:00
Paul Sokolovsky
a1d072df81 esp8266: Enable auto-indent in REPL. 2016-03-23 16:30:29 +02:00
Paul Sokolovsky
df1f6783f2 esp8266: Add "socket" and "usocket" aliases for lwip module. 2016-03-23 16:25:55 +02:00
Paul Sokolovsky
494aea3e86 esp8266: Enable non-blocking stream support. 2016-03-23 16:15:49 +02:00
Damien George
5bc9398d9d esp8266: Enable more extmod's: uheapq, ure, uzlib. 2016-03-23 14:19:14 +02:00
Damien George
8000d51b68 esp8266: Add module weak link from json to ujson. 2016-03-23 14:16:46 +02:00
Paul Sokolovsky
1a0adf49df esp8266: Enable urandom module. 2016-03-23 13:33:17 +02:00
Damien George
e673714cfe esp8266: Make mp_hal_delay_us work with new event framework. 2016-03-23 13:01:21 +02:00
Paul Sokolovsky
58e2ad42ae esp8266: Update README with the latest features. 2016-03-23 12:08:15 +02:00
Damien George
b894551772 extmod/uctypes: Change param type from void* to byte*. 2016-03-19 22:13:17 +00:00
Damien George
da161fd9f0 extmod/uctypes: Finish support for FLOAT32 and FLOAT64 types. 2016-03-19 21:59:42 +00:00
Damien George
12154b1774 extmod/uctypes: Use mp_binary_get_val helper when extracting value.
It handles more cases than mp_binary_get_int.
2016-03-19 21:41:01 +00:00
Damien George
8d4d6731f5 py/parse: When looking up consts, check they exist before checking type. 2016-03-19 21:36:32 +00:00
Peter Hinch
2b302dad51 docs: Update pyb.UART.any() to mention that it returns character count. 2016-03-17 20:19:36 +00:00
Peter Hinch
6d5a549067 docs: Mention that pyb.SPI constructor accepts "X" and "Y" arguments. 2016-03-17 20:19:08 +00:00
Peter Hinch
b8133c4c0f docs: Update pyb.I2C constructor to reflect changes in Pyboard Lite. 2016-03-17 20:18:36 +00:00
Peter Hinch
4a6cac4643 docs: Update asm tutorial, maximum number of allowed args is now 4. 2016-03-17 20:17:40 +00:00
Damien George
99146ea444 tests/io: Remove "testfile" at end of open_plus test. 2016-03-17 20:09:33 +00:00
Damien George
556a1df6fd esp8266/ets_alt_task: Make FIRST_PRIO=0 to cover all task priorities.
FIRST_PRIO=2 works but using 0 is hopefully safer, and can anyway be
optimised in the future.
2016-03-17 16:28:06 +00:00
Paul Sokolovsky
9d7b871f58 esp8266: Store frozen modules in FlashROM.
Requires special lexer to access their contents.
2016-03-17 23:06:47 +08:00
Damien George
2466cb67f8 docs/esp8266: Update quick reference: i2c.readfrom and neopixel example. 2016-03-16 13:37:39 +00:00
Damien George
3acaa28b52 py: Don't allocate an extra parse node for power exponent.
Previous to this patch, the "**b" in "a**b" had its own parse node with
just one item (the "b").  Now, the "b" is just the last element of the
power parse-node.  This saves (a tiny bit of) RAM when compiling.
2016-03-16 13:04:51 +00:00
Paul Sokolovsky
52e062ef33 py/frozenmod: Allow port to override lexer to use for frozen modules. 2016-03-16 17:42:37 +07:00
Damien George
664f03f466 tests: Add a test for argument passing to inline-asm functions. 2016-03-16 08:24:07 +00:00
Damien George
9a58316de2 py/objfun: Allow inline-asm functions to be called with 4 arguments. 2016-03-16 08:22:26 +00:00
Damien George
be989be861 qemu-arm: Enable builtin override feature, and enable more tests.
Hopefully these tests run reliably on Travis.
2016-03-15 13:45:32 +00:00
Damien George
1ded19d4b3 qemu-arm: Reinitialise uPy heap and runtime at start of each test.
Previous to this patch, all qemu-arm tests were running in the same
session, and global variables could be left over from the previous test.
This patch makes it so that the heap and runtime are reinitialised at
the start of each test.
2016-03-15 13:42:36 +00:00
Damien George
157056ecdf tests: Add new subdir "stress/" specifically for stress tests. 2016-03-15 13:20:18 +00:00
Damien George
ab69ed7dac tests: Split large tests into smaller files, to run with a small heap.
All tests in basics/ directory can now run and pass using 64-bit unix
port with only a 16k heap (./run-tests --heapsize 16k).  Tests in this
directory should remain small so they can be used for ports with a
small heap.
2016-03-15 13:07:41 +00:00
Damien George
9996adc37d tests/run-tests: Add cmd line option "--heapsize".
This allows you to specify the heapsize that unix will use when running
the test suite, eg: ./run-tests --heapsize 16k
2016-03-15 13:04:43 +00:00
Damien George
cea6cf8a5e py/formatfloat: Fix buffer overflow when formatting tiny numbers. 2016-03-15 12:21:56 +00:00
Damien George
0d1f8868b6 py: For mp_buffer_info_t, change len type from mp_uint_t to size_t. 2016-03-15 12:20:57 +00:00
Damien George
77f85db41e py/objarray: Fix array slice assignment when array is reallocated.
Addresses issue #1898.
2016-03-14 23:12:54 +00:00
Damien George
06b398489e py/parsenum: Fix compiler warnings for no decl and signed comparison. 2016-03-14 22:52:52 +00:00
Damien George
0be6359f39 py: When printf'ing an object as a pointer, pass the concrete pointer. 2016-03-14 22:41:14 +00:00
Damien George
2a1cca20b1 py: Fix passing of some wide int types to printf varg format list.
Passing an mp_uint_t to a %d printf format is incorrect for builds where
mp_uint_t is larger than word size (eg a nanboxing build).  This patch
adds some simple casting to int in these cases.
2016-03-14 22:40:39 +00:00
Damien George
e7cd1699df py/argcheck: Use size_t instead of mp_uint_t to count number of args. 2016-03-14 22:35:48 +00:00
Damien George
dddb98db8b py/parsenum: Use size_t to count bytes, and int for type of base arg.
size_t is the proper type to count number of bytes in a string.  The base
argument does not need to be a full mp_uint_t, int is enough.
2016-03-14 22:34:03 +00:00
Dave Hylands
99fc0d120a stmhal: NUCELO_F401RE cleanup
Added definitions for SPI1, SPI2, and SPI3
Removed USB stuff (that could be removed)
Updated BOARD name defintion
2016-03-13 12:36:39 +00:00
Dave Hylands
00f921ce02 stmhal: Rename STM32F401NUCLEO to NUCLEO_F401RE
This makes the board match the name printed on the board (and
agree with the documentation)
2016-03-13 12:36:39 +00:00
Dave Hylands
031fadd10e stmhal: Add board definition files for NUCLEO_F411RE 2016-03-12 16:16:15 -08:00
Paul Sokolovsky
e5c39a3a9e esp8266: Switch to lwIP built from source.
Using https://github.com/pfalcon/esp-open-lwip project.
2016-03-12 11:45:53 +07:00
Paul Sokolovsky
0779409d0d extmod/modlwip: lwip_tcp_receive: Properly map lwIP error to POSIX errno. 2016-03-12 11:42:15 +07:00
Paul Sokolovsky
ba8f7d5171 extmod/modlwip: Add socket.setblocking() method. 2016-03-12 10:52:50 +07:00
Paul Sokolovsky
09ed5bcbbb extmod/modlwip: Rework getaddrinfo() data passing.
The code is based on Damien George's implementation for esp8266 port,
avoids use of global variables and associated re-entrancy issues, and
fixes returning stale data in some cases.
2016-03-12 10:50:51 +07:00
Peter Hinch
21b74604f9 docs: Add Python speed optimisation guide, including minimal viper ref. 2016-03-11 16:33:36 +00:00
Peter Hinch
85d3b6165a docs: Update details on using ADCAll object for vref/vbat channels. 2016-03-11 16:33:09 +00:00
Peter Hinch
70f32f0f73 docs: Update asm_thumb2_hints_tips re return type of asm funcs. 2016-03-11 16:32:42 +00:00
Christopher Arndt
3d0e3a3d3e esp8266: Mention git submodule in build instructions for esp8266 port. 2016-03-11 10:07:02 +00:00
Damien George
932f07ccf5 esp8266: Rejig Makefile so extmod/modlwip.o is placed under build/. 2016-03-11 12:00:01 +07:00
Paul Sokolovsky
4c2cb7e384 esp8266: Define MICROPY_EVENT_POLL_HOOK for the port. 2016-03-11 10:41:10 +07:00
Paul Sokolovsky
6e5c31c947 esp8266: Be sure to build ets_alt_task. 2016-03-11 09:43:39 +07:00
Paul Sokolovsky
a099bfe89c esp8266/esp_mphal: Add higher-level event polling function.
ets_event_poll() polls both system events and uPy pending exception.
2016-03-11 09:42:03 +07:00
Paul Sokolovsky
e5b047369b extmod/modlwip: Use MICROPY_EVENT_POLL_HOOK for event polling if defined.
Instead of just delaying 100ms if event isn't yet ready.

So far applies only to default, "infinite" socket timeout.
2016-03-11 09:32:07 +07:00
Paul Sokolovsky
54fc247f9b esp8266/ets_alt_task: Update for vendor SDK 1.5.0.
SDK 1.5.0 has a task with priority 3: ets_task(401001f4, 3, 3fff9808, 4).
Recognizing SDK version requires the latets esp-open-sdk build.
2016-03-11 09:17:57 +07:00
Paul Sokolovsky
97375f4576 esp8266/ets_alt_task: Be sure to "pop" event before calling its handler.
Otherwise, if handler calls recursive event loop, there's infinite
recursion (because the loop calls the same handler on same event again).
2016-03-11 09:16:34 +07:00
Damien George
7261f17b9e esp8266: Feed WDT in ets_loop_iter(). 2016-03-11 09:15:06 +07:00
Paul Sokolovsky
97c2628900 esp8266: Add alternative event loop implementation.
This implementation provides the same interface and uses the same
datastructures as used by BootROM, i.e. is a drop-in replacement for it.
But it offers one advantage: it allows to run single iteration of
event-pumping loop.

Original BootROM function are renamed, prefixed with underscore. There's
a switch which allows to use forward calls to them, for compatibility
testing.

The implementation also includes workarounds for hardware timer handler,
and these workarounds may be SDK version specific.
2016-03-11 09:13:31 +07:00
Damien George
9ae51257bd py: Use MP_SMALL_INT_POSITIVE_MASK to check if uint fits in a small int.
Using the original WORD_MSBIT_HIGH-logic resulted in errors when the
object model is not REPR_A or REPR_C.
2016-03-10 21:52:56 +00:00
Paul Sokolovsky
5239a8a82b esp8266/modnetwork: Add symbolic names for network interfaces: STA_IF & AP_IF.
These are expected to be passed to network.WLAN() to instantiate network
interface objects.
2016-03-10 10:44:15 +07:00
Paul Sokolovsky
a49c16069c esp8266/modnetwork: Introduce interface .config() method.
Allows to set (in case keyword args are given) or query (in case a single
"symbolic keyword" (a string, value is the same as keyword)) arbitrary
interface paramters (i.e. extensible and adaptable to various hardware).

Example usage:

ap_if = network.WLAN(1)
ap_if.config(essid="MicroPython on Air")
print(ap_if.config("essid"))
2016-03-10 10:41:55 +07:00
Paul Sokolovsky
d5a12a6608 esp8266/modnetwork: Move config defines to the top. 2016-03-10 10:39:52 +07:00
Paul Sokolovsky
1c43a0fbf8 esp8266/modnetwork: Add per-interface .active() method.
Allows to up/down interface when called with a boolean, or query current
state if called without args. This per-interface method is intended to
supersede adhoc network.wifi_mode() function.
2016-03-10 09:31:23 +07:00
Paul Sokolovsky
7378c50b2f esp8266: Move wifi_mode() and phy_mode() to network module. 2016-03-10 09:29:21 +07:00
Paul Sokolovsky
9e8396accb esp8266/modnetwork: Allow to configure STA and AP interfaces separately.
On ESP8266, there're 2 different interfaces. Pretending it's not the case
desn't make sense. So, network.WLAN() now takes interface id, and returns
interface object. Individual operations are then methods of interface
object. Some operations require i/f of specific type (e.g. .connect()
makes sense only for STA), other are defined for any (e.g. .ifconfig(),
.mac()).
2016-03-10 09:24:54 +07:00
Christopher Arndt
9b5e05a7c7 stmhal: Add makefile target and configuration to deploy via OpenOCD. 2016-03-09 23:00:17 +00:00
Ryan Shaw
ad725a6661 stmhal: Add support for generic STM32F439 board (non DISCO). 2016-03-09 22:46:41 +00:00
Damien George
853fb08d0d mpy-cross: Remove setting of MICROPY_FORCE_32BIT=1 from Makefile.
Building in 32-bit mode was only to reduce binary size on 64-bit machines
and is otherwise not needed.  Having it forced to 32-bit meant an
unnecessary dependency on 32-bit libraries that is now removed.
2016-03-09 15:56:11 +00:00
Christopher Arndt
07554486ee stmhal: Add makefile target to deploy stmhal build via ST-LINK. 2016-03-09 13:26:23 +00:00
Damien George
6b80ebe32e docs/esp8266: Fix indent errors, typos, and add info about REPL UART. 2016-03-09 13:01:32 +00:00
Damien George
42ef5a1567 docs: Allow list of versions to be specified by environment variable. 2016-03-09 12:43:22 +00:00
Damien George
5b74bba3a3 docs: Add versions.html template and support code for a version sidebar. 2016-03-09 12:15:47 +00:00
Damien George
4b6077b3fe docs/esp8266: Minor tweaks to quickref, Timer and I2C classes. 2016-03-09 11:02:38 +00:00
Paul Sokolovsky
43d497592f extmod/modlwip: Factor out "socket connected" check to a function.
Same code repeated for each send*() and recv*() function.
2016-03-09 12:43:09 +07:00
Paul Sokolovsky
fda874e406 extmod/modlwip: Support non-blocking recv(). 2016-03-09 12:39:33 +07:00
Paul Sokolovsky
7379be3673 extmod/modlwip: Add .write() stream method. 2016-03-09 12:35:43 +07:00
Damien George
4f64f6bfd3 extmod/modlwip: Still process remaining incoming data of a closed socket.
It can happen that a socket gets closed while the pbuf is not completely
drained by the application.  It can also happen that a new pbuf comes in
via the recv callback, and then a "peer closed" event comes via the same
callback (pbuf=NULL) before the previous event has been handled.  In both
cases the socket is closed but there is remaining data.  This patch makes
sure such data is passed to the application.
2016-03-09 12:31:25 +07:00
Damien George
6d2e9e70b3 extmod/modlwip: Check for state change during recv busy-wait loop.
For example, the peer may close the connection while recv is waiting for
incoming data.
2016-03-09 12:29:40 +07:00
Paul Sokolovsky
6185dc5f3d extmod/modlwip: Add stream .read() and .readline() methods. 2016-03-09 09:20:22 +07:00
Paul Sokolovsky
f1919b7c98 extmod/modlwip: Add dummy .makefile() method. 2016-03-09 09:14:45 +07:00
Paul Sokolovsky
c7fb87caff extmod/modlwip: Add stream protocol read method. 2016-03-09 09:12:32 +07:00
Damien George
f7be80398e esp8266: Move pyb.freq to machine.freq. 2016-03-09 09:03:59 +07:00
Damien George
809fbeefb7 docs: Add esp8266 quick reference page, with basic info. 2016-03-08 23:06:15 +00:00
Damien George
dcdf8f2d14 py/objboundmeth: Allocate arg state on stack if heap alloc fails.
If the heap is locked, or memory allocation fails, then calling a bound
method will still succeed by allocating the argument state on the stack.

The new code also allocates less stack than before if less than 4
arguments are passed.  It's also a tiny bit smaller in code size.

This was done as part of the ESA project.
2016-03-08 15:36:53 +00:00
Damien George
bb293e6bcf stmhal: Add stmhal-specific README.md with extra details for this port. 2016-03-08 12:00:38 +00:00
Damien George
2c72ae5c29 stmhal: Switch from dfu-util to tools/pydfu.py for deflt deploy method.
tools/pydfu.py is now the recommended way of deploying a DFU file.  Old
behaviour of dfu-util can be obtained by passing USE_PYDFU=0 when invoking
make.

The main README.md file has been updated to reflect this change.
2016-03-08 11:58:39 +00:00
Damien George
f0e2d13fd2 tests/run-tests: Simplify handling of newline in output from tests.
Now, all output has newlines converted to \n, regardless of port or
platform.
2016-03-08 10:20:38 +00:00
Paul Sokolovsky
ed593780bf extmod/modlwip: Implement dummy setsockopt(). 2016-03-08 14:24:49 +07:00
Paul Sokolovsky
a0cd118b14 esp8266/main: Module to run on boot is "boot", not "main". 2016-03-08 12:37:24 +07:00
Paul Sokolovsky
f8d42da104 extmod/modlwip: Add .print() method. 2016-03-08 11:37:15 +07:00
Damien George
3fbbbecec9 esp8266: Put more code in iROM section.
Also explicitly name the py/*.o files in the linker file, to enable easy
testing of putting certain ones in iRAM.
2016-03-08 11:31:39 +07:00
Paul Sokolovsky
04a9ac7f38 extmod/modlwip: Update make_new() arguments for recent refactor. 2016-03-08 10:31:21 +07:00
Paul Sokolovsky
d684f872bd esp8266/Makefile: Add define for ESP8266 lwIP. 2016-03-08 10:29:05 +07:00
Damien George
05dda0ee9e esp8266: Enable modlwip. 2016-03-08 10:21:50 +07:00
Paul Sokolovsky
88b0490945 esp8266: Don't gc-collect BSS.
None of the other ports do, since introduction of mp_state_ctx_t. In
the case of current esp8266 port, heap is inside BSS, so scanning it
picked up a lot of dead pointers.
2016-03-08 10:16:06 +07:00
Markus Fix
4f0080346b py/emitglue: Get persistent bytecode working on Linux ARM platform. 2016-03-07 15:15:23 +00:00
Dave Hylands
484a471f9b stmhal: Fix some typos in stm32f411 files, regarding FS layout and CSV. 2016-03-07 12:42:30 +00:00
Dave Hylands
367c084c4b stmhal: Fix typo in stm32f401.ld file, regarding flash size. 2016-03-07 12:38:57 +00:00
Dave Hylands
0edfb7a115 stmhal: Make spi use mp_hal_gpio_set_af 2016-03-07 12:24:53 +00:00
Damien George
d964873e56 tests/run-tests: Fix logic when selecting test-dirs for a given target. 2016-03-07 12:00:16 +00:00
Pavol Rusnak
ce3beb1672 stmhal: Unify comments in stm32f4xx_hal_conf.h across all boards.
To make it easier to spot differences.
2016-03-07 11:28:36 +00:00
Paul Sokolovsky
b86c20676e tests/recursive_iternext.py: Make low-heap friendly. 2016-03-07 15:30:02 +07:00
Paul Sokolovsky
db984b73f3 esp8266: Enable stack overflow checking. 2016-03-07 14:15:00 +07:00
Paul Sokolovsky
1d5d4f49d9 py/stackctrl: Add mp_stack_set_top() to explicitly set stack top value.
Useful for embedded targets with fixed stack layout.
2016-03-07 14:12:24 +07:00
Paul Sokolovsky
419bb26ddc tests/print_exception: Use exception which prints the same regardless of config.
NameError may either include offending name or not. Unfortunately, this
change makes test float-dependent. And using integer division leads to
different error message than CPython.
2016-03-07 14:10:06 +07:00
Paul Sokolovsky
d973c1bc12 test/string_format_fp30: Variant of string_format for 30-bit stuffed float. 2016-03-06 06:10:40 +02:00
Paul Sokolovsky
50e0a7b9d4 test/float2int_fp30: Variant of float2int for 30-bit stuffed float. 2016-03-06 06:08:38 +02:00
Damien George
fbb3c190f9 tests: Remove commented out tests so test script is not too big. 2016-03-06 06:00:28 +02:00
Damien George
14848ffa12 tests: Reduce large object allocations so tests can run with small heap. 2016-03-06 05:59:46 +02:00
Damien George
52d7685d9a esp8266: Allow Makefile's BAUD variable to be overridden. 2016-03-06 05:57:36 +02:00
Paul Sokolovsky
d9d4a72679 esp8266/uart: Add uart_flush() function. 2016-03-05 22:13:26 +02:00
Paul Sokolovsky
d3a4d39687 esp8266: Support raising KeyboardInterrupt on Ctrl+C. 2016-03-05 22:01:27 +02:00
Damien George
077448328a esp8266/etshal.h: More prototypes of ESP8266 SDK/BootROM functions. 2016-03-05 21:56:32 +02:00
Paul Sokolovsky
26f0616e8f esp8266/modmachine: Add Pin class from modpyb. 2016-03-05 21:43:11 +02:00
Paul Sokolovsky
eb247eacd8 esp8266/modpybpin: Add support for GPIO16.
GPIO16 is actually special-function I/O, though some boards have LED there.
2016-03-05 21:37:55 +02:00
Damien George
342d903a13 esp8266: Expose simple pin API at C level. 2016-03-05 21:36:32 +02:00
Damien George
cdad2b6f4d esp8266: Implement Pin.__call__() and Pin.OPEN_DRAIN mode.
OPEN_DRAIN is of course synthesised.  All pin modes are tested and
working.
2016-03-05 21:35:32 +02:00
Paul Sokolovsky
8ab16b6af0 esp8266: Add custom _assert() function.
Enabling standard assert() (by removing -DNDEBUG) produces non-bootable
binary (because all messages go to .rodata which silently overflows).
So, for once-off debugging, have a custom _assert().
2016-03-05 11:30:15 +02:00
Paul Sokolovsky
c70637bc00 esp8266/modmachine: Timer: Add ONE_SHOT and PERIODIC symbolic constants. 2016-03-04 22:26:59 +02:00
Paul Sokolovsky
98b727c931 esp8266/modmachine: Use etshal.h. 2016-03-04 19:41:15 +02:00
Paul Sokolovsky
f22a4f8e0a esp8266/etshal.h: Add timer functions prototypes. 2016-03-04 19:39:24 +02:00
Paul Sokolovsky
f39bcb304b esp8266/modmachine: Changing params of a timer requires disarming it first. 2016-03-04 18:41:37 +02:00
Paul Sokolovsky
7193086c03 esp8266/modmachine: Basic implementation of Timer for OS virtual timers. 2016-03-04 18:40:35 +02:00
Paul Sokolovsky
4284b3811f esp8266: Enable modmachine. 2016-03-04 17:37:13 +02:00
Paul Sokolovsky
5d7c408ba8 esp8266: Add modmachine with mem* arrays. 2016-03-04 17:34:25 +02:00
Paul Sokolovsky
6abafca1aa esp8266/modutime: Support float argument to time.sleep(). 2016-03-04 16:52:30 +02:00
Paul Sokolovsky
a4c8ef9d16 esp8266: Reset "virtual RTC" on power on.
Initialize RTC period coefficients, etc. if RTC RAM doesn't contain valid
values. time.time() then will return number of seconds since power-on, unless
set to different timebase.

This reuses MEM_MAGIC for the purpose beyond its initial purpose (but the whole
modpybrtc.c need to be eventually reworked completely anyway).
2016-03-04 16:49:01 +02:00
Damien George
57884996b9 esp8266: Add time.{sleep_ms,sleep_us,ticks_ms,ticks_us,ticks_diff}.
Framework for time.ticks_cpu added, but not implemented.
2016-03-04 09:25:53 +02:00
Damien George
b41a14a4b9 esp8266: Add mp_hal_delay_us function. 2016-03-04 09:25:05 +02:00
Damien George
f70873db23 esp8266: Enable more features in mpconfigport.h.
This is to get the test suite running and passing.
2016-03-03 23:34:31 +02:00
Paul Sokolovsky
7480ee5892 esp8266: Enable uhashlib module. 2016-03-03 20:14:50 +02:00
Paul Sokolovsky
70fb9ee99b esp8266: Enable config settings helpful for debugging. 2016-03-03 20:12:26 +02:00
Paul Sokolovsky
2382d30318 tests/run-tests: Skips for esp8266. 2016-03-03 15:38:43 +02:00
Paul Sokolovsky
259f1344ca esp8266/esp8266.ld: Link in SDK version section.
Otherwise, os.uname() returns empty string for SDK version.
2016-03-03 15:37:19 +02:00
Paul Sokolovsky
ff69a1d27d esp8266: Enable ujson, ubinascii, and uctypes modules. 2016-03-03 15:35:29 +02:00
Paul Sokolovsky
65405247a0 extmod/vfs_fat_lexer: Add func prototype for pedantic warnings. 2016-03-03 14:53:36 +02:00
Paul Sokolovsky
3aa0f2eed3 extmod/vfs_fat_lexer: Make conditional on FatFs support enabled. 2016-03-03 14:08:27 +02:00
Paul Sokolovsky
453a2a3d7c extmod/vfs_fat: Add lexer, move from stmhal port for reuse. 2016-03-03 13:25:44 +02:00
Paul Sokolovsky
701c4152c1 tarvis: Unbreak build by ignoring lack of i386 arch in some repos.
For some reason, Travis now has Google Chrome PPA included in the builder
image, that lacks i386 arch, that leads to apt-get update error. So, ignore
it (this is not ideal as may lead to actual repo update failures to be missed,
leading to installation of old package, leading to weird errors; let's keep
that in mind).
2016-03-03 11:06:36 +02:00
Damien George
02ea74d8f5 esp8266: Add network.ifconfig(). 2016-03-02 23:04:21 +02:00
Damien George
1febaf3ac3 esp8266: Change "soft reboot" message to work with pyboard.py. 2016-03-02 22:58:48 +02:00
Damien George
d083d7d610 esp8266: Allow Makefile's PORT variable to be overridden. 2016-03-02 22:50:55 +02:00
Damien George
6f4357c28e esp8266: Enable math module. 2016-03-02 22:43:10 +02:00
Damien George
6d0629bddc esp8266: Enable float support, using 30-bit stuffed floats.
No complex numbers though.
2016-03-02 22:43:10 +02:00
Damien George
ecd1272d16 esp8266: Switch bignum implementation from long-long to mpz. 2016-03-02 22:43:10 +02:00
Damien George
3d1d92acfc mpy-cross: Give a more sensible error message when file doesn't exist. 2016-03-02 16:12:00 +00:00
Noah Rosamilia
6bb9d3ea3e docs/uctypes.rst: Fix typo (steamlined -> streamlined). 2016-03-02 00:25:10 +02:00
Paul Sokolovsky
dc320164d8 unix/modsocket: Add comment regarding close() error checking (which is none). 2016-03-02 00:20:48 +02:00
Damien George
4f72aa86bf py/qstrdefs: Add mkdir and remove qstrs for user-mountable filesystems. 2016-02-29 10:54:00 +00:00
Paul Sokolovsky
2740dd85f2 tests/vfs_fat_ramdisk: Add testcase for .rename(). 2016-02-29 01:24:18 +02:00
Paul Sokolovsky
e0821830b0 extmod/vfs_fat: Add .rename() method. 2016-02-29 01:23:53 +02:00
Paul Sokolovsky
09e363316f extmod/vfs_fat_misc: Fix cc3200 port build. 2016-02-29 01:15:19 +02:00
Paul Sokolovsky
9fb36af9af tests/vfs_fat_ramdisk: Allow to run in native mode (don't use "with"). 2016-02-29 01:03:32 +02:00
Paul Sokolovsky
08fed6992f extmod/vfs_fat_misc: Add func prototype for pedantic warnings. 2016-02-29 00:48:45 +02:00
Paul Sokolovsky
6ef65e70af extmod/vfs_fat: Add fat_vfs_import_stat(), reusable import stat routine.
Moved from stmhal.
2016-02-29 00:44:32 +02:00
Paul Sokolovsky
eaa96a7610 tests/vfs_fat_ramdisk: Add testcase for .mkdir(). 2016-02-29 00:06:44 +02:00
Paul Sokolovsky
bbe832a0b2 extmod/vfs_fat: Add .mkdir() method. 2016-02-29 00:03:20 +02:00
Paul Sokolovsky
6f469209e9 extmod/vfs_fat: Fix unused param warning/error. 2016-02-28 20:45:51 +02:00
Paul Sokolovsky
57425b648f tests/vfs_fat_ramdisk: Add testcase for .remove(). 2016-02-28 20:30:59 +02:00
Paul Sokolovsky
19749db7bf extmod/vfs_fat: Add .remove() method.
Based on stmhal implementation - rather small, so just duplicating.
2016-02-28 20:30:07 +02:00
Paul Sokolovsky
9c081b740b tests/vfs_fat_ramdisk: Add .listdir() testcase. 2016-02-28 17:19:12 +02:00
Paul Sokolovsky
cd6d189f48 extmod/vfs_fat: Move listdir() method from stmhal for reuse. 2016-02-28 17:17:24 +02:00
danicampora
8a18084571 cc3200: Update WiPy software version to 1.2.0 2016-02-27 00:19:53 +01:00
Damien George
ac23662550 unix: Enabled importing of persistent bytecode (.mpy files). 2016-02-25 10:12:30 +00:00
Damien George
476c15290d stmhal: Enabled importing of persistent bytecode (.mpy files). 2016-02-25 10:12:30 +00:00
Damien George
56f76b873a mpy-cross: Add new component, a cross compiler for MicroPython bytecode.
This component allows to generate .mpy files (pre compiled bytecode)
which can be executed within any MicroPython runtime/VM.
2016-02-25 10:12:21 +00:00
Damien George
ea23520403 py: Add MICROPY_DYNAMIC_COMPILER option to config compiler at runtime.
This new compile-time option allows to make the bytecode compiler
configurable at runtime by setting the fields in the mp_dynamic_compiler
structure.  By using this feature, the compiler can generate bytecode
that targets any MicroPython runtime/VM, regardless of the host and
target compile-time settings.

Options so far that fall under this dynamic setting are:
- maximum number of bits that a small int can hold;
- whether caching of lookups is used in the bytecode;
- whether to use unicode strings or not (lexer behaviour differs, and
  therefore generated string constants differ).
2016-02-25 10:05:46 +00:00
danicampora
57b96a7be2 docs: Correct machine.Timer code examples related to duty cycle. 2016-02-23 20:22:26 +01:00
danicampora
8e1fdf2eb3 docs: Add note on machine.Timer class regarding PWM output pins. 2016-02-23 19:53:59 +01:00
Damien George
28adab36c7 py/emitinlinethumb: Use qstrs instead of char* for names of asm ops.
Reduces code size by 112 bytes on Thumb2 arch, and makes assembler faster
because comparison can be a simple equals instead of a string compare.

Not all ops have been converted, only those that were simple to convert
and reduced code size.
2016-02-23 15:20:39 +00:00
Damien George
e9d1a94bf0 py/malloc: Provide a proper malloc-based implementation of realloc_ext. 2016-02-23 13:53:38 +00:00
Damien George
d6c558c0aa py/parse: Use m_renew_maybe to ensure that memory is shrunk in-place.
The chunks of memory that the parser allocates contain parse nodes and
are pointed to from many places, so these chunks cannot be relocated
by the memory manager.  This patch makes it so that when a chunk is
shrunk to fit, it is not relocated.
2016-02-23 13:44:29 +00:00
danicampora
add930c4b5 cc3200: Rename 'server' class to 'Server' for consistency. 2016-02-22 22:54:34 +01:00
danicampora
12547ce737 docs: Minor change to improve clarity in machine.Timer docs. 2016-02-22 19:16:30 +01:00
danicampora
cc7a4d7db2 tests/wipy: Correct machine test expected result. 2016-02-22 00:42:05 +01:00
danicampora
5148860332 tests: Skip uctypes and urandom tests not supported byt the WiPy. 2016-02-21 22:30:35 +01:00
danicampora
495e7cfebc cc3200: Improve robustness of WLAN during sleep modes. 2016-02-21 22:01:18 +01:00
danicampora
f5248a087a cc3200: Fix "debug" build. 2016-02-21 21:53:21 +01:00
danicampora
0d210a0be8 docs: Correct WiPy Timer docs. 2016-02-21 21:53:20 +01:00
danicampora
fe9620a2bd test/wipy: Add Timer class tests. 2016-02-21 21:53:20 +01:00
danicampora
73c9f85b4c cc3200: Simplify the Timer API and correct the documents.
Make the PWM duty cycle configurable from 0.00 to 100.00 by
accepting values from 0 to 10000.
Add automatic Pin assignment when operating in PWM mode.
2016-02-21 21:53:16 +01:00
danicampora
562bcffd3a cc3200: Improve robustness of the I2C driver.
When scanning for devices, try reading then writing. Increase the
timeout of the transactions from 10 to 20 ms.
2016-02-21 21:41:06 +01:00
danicampora
ed8db2e371 cc3200: Finally fix the Timer class API.
Properly calculate the period and the prescaler, this now allows to
set the PWM frequency down to 5Hz. Make Timer IDs go from 0 to 3.
Add the trigger definitions for the channel IRQ.
2016-02-21 21:41:06 +01:00
Damien George
53fec1ef48 README.md: Add link to micropython.org. 2016-02-17 23:01:49 +00:00
Damien George
40d8430ee3 py/vm: Add macros to hook into various points in the VM.
These can be used to insert arbitrary checks, polling, etc into the VM.
They are left general because the VM is a highly tuned loop and it should
be up to a given port how that port wants to modify the VM internals.

One common use would be to insert a polling check, but only done after
a certain number of opcodes were executed, so as not to slow down the VM
too much.  For example:

 #define MICROPY_VM_HOOK_COUNT (30)
 #define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT
 #define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \
     vm_hook_divisor = MICROPY_VM_HOOK_COUNT;
     extern void vm_hook_function(void);
     vm_hook_function();
 }
 #define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL
 #define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL
2016-02-17 09:02:19 +00:00
Alex March
69d9e7d27d py/repl: Check for an identifier char after the keyword.
- As described in the #1850.
- Add cmdline tests.
2016-02-17 08:56:15 +00:00
Paul Sokolovsky
dfc35afba1 tests/vfs_fat_ramdisk: Skip test if can't allocate ramdisk. 2016-02-15 17:27:57 +02:00
Paul Sokolovsky
6cee869feb py/qstrdefs.h: qstrs for VfsFat. 2016-02-15 12:49:32 +02:00
Dave Hylands
ec37239e53 stmhal: Improvements to the STM32F4DISC UART config settings. 2016-02-15 10:11:29 +00:00
Dave Hylands
4b2938a4b0 stmhal: Some NETDUINO_PLUS_2 cleanup
- Put the I2C bus on the corect pins
- Add the appropriate board_init to power the shield
2016-02-15 10:07:27 +00:00
Damien George
9598f36a84 py/emitnative: Add check that RHS of viper store is of integral type. 2016-02-15 09:38:02 +00:00
Damien George
94e4bd456f py/asmx64: Support all 16 regs in reg to memory move instructions. 2016-02-15 09:05:50 +00:00
Damien George
46fc7a3d75 py/asmx64: Add helper macro for generating REX_[WRXB] bits from a reg64. 2016-02-15 09:02:13 +00:00
Paul Sokolovsky
4cd45f48b1 cc3200: Fix breakage after VfsFat refactor. 2016-02-15 10:39:56 +02:00
Paul Sokolovsky
46a0ac02c5 extmod/vfs_fat_ffconf: Reusable FatFs module, move from stmhal/ffconf.
TODO: Probably merge into vfs_fat_diskio.
2016-02-15 00:19:27 +02:00
Paul Sokolovsky
6b0c88256b extmod/vfs_fat_file: Reusable FatFs module, move from stmhal/file. 2016-02-15 00:16:46 +02:00
Paul Sokolovsky
8cb78e0e53 extmod/vfs_fat_diskio: Reusable FatFs module, move from stmhal/diskio. 2016-02-15 00:08:37 +02:00
Paul Sokolovsky
72085a669b py/mpstate.h: fs_user_mount is now standard, reusable uPy functionality. 2016-02-15 00:02:03 +02:00
Paul Sokolovsky
9fdac9144d tests/vfs_fat_ramdisk: Allow to override sector size. 2016-02-14 20:52:38 +02:00
Paul Sokolovsky
9d0525182d tests/vfs_fat_ramdisk: Switch to ioctl-based blockdev API. 2016-02-14 20:45:08 +02:00
Paul Sokolovsky
9e0478a902 stmhal/diskio: Add provision for default returns for ioctl INIT/SEC_SIZE.
If None was returned for such requests (which likely means that user simply
didn't handle them), it means successful init and default sector size of 512
bytes respectively. This makes only BP_IOCTL_SEC_COUNT a mandatory request,
and thus re-establishes parity with old interface, where only .count() is
mandatory().
2016-02-14 20:34:30 +02:00
Paul Sokolovsky
0ee1d0f407 tests/vfs_fat_ramdisk: Add test for VfsFat. 2016-02-14 19:15:22 +02:00
Paul Sokolovsky
e3c66a5a67 stmhal/file: Paranoid compiler warnings cleanness. 2016-02-14 19:15:22 +02:00
Paul Sokolovsky
baf47c84c4 stmhal/diskio,file: Nanbox cleanness. 2016-02-14 19:15:22 +02:00
Paul Sokolovsky
1bb15ca427 extmod/fsusermount,vfs_fat: Nanbox cleanness. 2016-02-14 19:15:22 +02:00
Paul Sokolovsky
8a43a41b3a unix: Enable VfsFat support. 2016-02-14 19:15:22 +02:00
Paul Sokolovsky
e9be6a378c extmod/vfs_fat: Object-oriented encapsulation of FatFs VFS.
This implements OO interface based on existing fsusermount code and with
minimal changes to it, to serve as a proof of concept of OO interface.

Examle of usage:

bdev = RAMFS(48)
uos.VfsFat.mkfs(bdev)
vfs = uos.VfsFat(bdev, "/ramdisk")
f = vfs.open("foo", "w")
f.write("hello!")
f.close()
2016-02-14 19:15:21 +02:00
Paul Sokolovsky
dc3eb55e6a py/obj.h: If not float support is enabled, define mp_obj_is_float(o) to false.
We have so many configuration options, that finally having shortcuts like
this is helpful and cuts on number of ifdef's.
2016-02-14 19:12:57 +02:00
Paul Sokolovsky
e5cff5b223 tests/bytearray1: Add testcases for "in" operator. 2016-02-14 18:57:18 +02:00
Paul Sokolovsky
c38809e26b py/objarray: Implement "in" operator for bytearray. 2016-02-14 18:57:11 +02:00
Paul Sokolovsky
609a9c6b71 eagle.rom.addr.v6.ld: More symbols from SDK 1.5.0. 2016-02-14 13:09:42 +02:00
Paul Sokolovsky
bf904b238d extmod/fsusermount: umount: Add NULL pointer checks. 2016-02-13 22:55:35 +02:00
Paul Sokolovsky
d4315a6caf float/string_format: Split large test in 2. 2016-02-13 17:18:55 +02:00
Paul Sokolovsky
2850e7cd97 tests/run-tests: Add esp8266 target. 2016-02-13 17:03:12 +02:00
Paul Sokolovsky
dc587a3623 test/float2int: Make test output clearer. 2016-02-13 17:03:02 +02:00
Paul Sokolovsky
a2e39a756c esp8266/modpybrtc: Simplify multiplication by fixed-point value. 2016-02-12 23:20:52 +02:00
Dave Hylands
32b7e93535 stmhal: NUCLEO 401 - Add definitions for I2C2 and I2C3 2016-02-10 21:26:14 -08:00
Dave Hylands
f791e14750 stmhal: CERB40 - Add pins defines for I2C3 2016-02-10 21:25:30 -08:00
Dave Hylands
38ac23c942 stmhal: NUCLEO 401 - Add a bunch of missing pins and reorder the pins
This groups the pins for a port together and puts them in numerical
order. It also adds ARDUINO pin names.
2016-02-10 21:23:45 -08:00
Dave Hylands
7bb501ef9f stmhal: Add a function for setting the pin alternate function
mp_hal_gpio_set_af will search for a given function and unit
and set the alternate function to the alternate function index
found.
2016-02-10 21:20:14 -08:00
Damien George
e372e83b30 extmod/fsusermount: Move BP_IOCTL_xxx constants to fsusermount.h. 2016-02-10 23:40:35 +00:00
Damien George
b33a770596 extmod/fsusermount: Support mounting of multiple block devices.
This patch adds support to fsusermount for multiple block devices
(instead of just one).  The maximum allowed is fixed at compile time by
the size of the fs_user_mount array accessed via MP_STATE_PORT, which
in turn is set by MICROPY_FATFS_VOLUMES.

With this patch, stmhal (which is still tightly coupled to fsusermount)
is also modified to support mounting multiple devices   And the flash and
SD card are now just two block devices that are mounted at start up if
they exist (and they have special native code to make them more
efficient).
2016-02-10 23:40:10 +00:00
Damien George
34023eb673 stmhal: Add mount/umount/mkfs to os module. 2016-02-10 23:40:10 +00:00
Damien George
0e0ce47e65 extmod/fsusermount: Expose umount as a public function. 2016-02-10 23:40:10 +00:00
Damien George
3770cd2e70 stmhal: Expose flash and SD card as proper objects with block protocol.
You can now create (singleton) objects representing the flash and SD
card, using:

    flash = pyb.Flash()
    sdcard = pyb.SDCard()

These objects provide the block protocol.
2016-02-10 23:40:10 +00:00
Damien George
f7e5e677df tests/pyb: Add simple test for stm module on pyboard. 2016-02-10 17:06:07 +00:00
Damien George
3a042fb921 extmod/modmachine: Truncate integers that are to be stored using mem*.
Addresses issue #1835.
2016-02-10 17:05:03 +00:00
Dave Hylands
a888d5ab91 stmhal: Improve NUCLEO-F401RE build, with UART2 as REPL.
This enables MICROPY_HW_HAS_FLASH which got missed.

The HW has UART2 on the 401 connected to the STLINK procesor
which exposes it as USB serial. This connects that up so that
you can get a REPL using the USB serial.
2016-02-10 16:50:05 +00:00
Damien George
13a4c120ce lib/fatfs: Add support for sector sizes larger than 512 bytes.
If MICROPY_FATFS_MAX_SS is defined to power of 2 value between 1024 and
4096, support for dynamic sector size in FatFs will be enabled.  Note
that FatFs reserves static buffer of MICROPY_FATFS_MAX_SS size for each
filesystem in use, so that value should be set sparingly.

Initial patch provided by @pfalcon.
2016-02-10 08:59:58 +00:00
Damien George
c33ad60a67 extmod/fsusermount: Change block protocol to support ioctl method.
The new block protocol is:
- readblocks(self, n, buf)
- writeblocks(self, n, buf)
- ioctl(self, cmd, arg)

The new ioctl method handles the old sync and count methods, as well as
a new "get sector size" method.

The old protocol is still supported, and used if the device doesn't have
the ioctl method.
2016-02-10 08:59:31 +00:00
Paul Sokolovsky
3846fd56c1 extmod/fsusermount: Implement separate umount() function. 2016-02-10 00:51:47 +02:00
Paul Sokolovsky
5b85a86ce3 extmod/fsusermount: Introduce separate mkfs() function.
Per the previously discussed plan. mount() still stays backward-compatible,
and new mkfs() is rought and takes more args than needed. But is a step
in a forward direction.
2016-02-10 00:50:07 +02:00
Damien George
a2e5e4c3d8 py/viper: Allow uint as index to load/store, and give better error msg. 2016-02-09 13:46:49 +00:00
Damien George
3e02b1d19a py/viper: Allow casting of Python integers to viper pointers.
This allows you to pass a number (being an address) to a viper function
that expects a pointer, and also allows casting of integers to pointers
within viper functions.

This was actually the original behaviour, but it regressed due to native
type identifiers being promoted to 4 bits in width.
2016-02-09 13:29:20 +00:00
Paul Sokolovsky
9e78ab4b86 esp8266/README: Add hint about adding toolchain to PATH. 2016-02-08 22:35:24 +02:00
Paul Sokolovsky
814b1ae3a9 esp8266/modpybrtc: pyb_rtc_memory(): Fix copy-paste error. 2016-02-08 21:39:33 +02:00
Alex March
81407729a5 esp8266/modesp: Implement flash_write(), flash_erase(). 2016-02-08 11:42:24 +02:00
Paul Sokolovsky
96688de601 cc3200: Add stmhal/builtin_open.c to build. 2016-02-07 01:26:01 +02:00
Paul Sokolovsky
ab0e36b3da stmhal/file: For self-contained usecase, don't define global types.
If MICROPY_VFS_FAT is defined, mp_type_fileio & mp_type_textio won't be
defined, as these may be alredy defined elsewhere. The idea is to have
compartmentalized VFS FatFs class, which can work in parallel with some
other "main" filesystem. E.g., for unix port, mp_type_fileio, etc. will
be defined for the main POSIX filesystem, while stmhal/file.c will be
a self-contained VFS file class.
2016-02-07 01:25:28 +02:00
Paul Sokolovsky
350ab0f570 stmhal/file: Recast as "FatFs file" class, to support other VFS types.
Move definition of mp_builtin_open_obj to a separate module, then file.c
becomes more or less compartmentalized FatFs file class, which can be used
together with file class implementations for other (V)FSes.
2016-02-07 01:25:28 +02:00
Paul Sokolovsky
103fbaaf27 extmod/fsusermount: Common subexpression elimination.
Don't repeat MP_STATE_PORT(fs_user_mount), use local var.
2016-02-06 22:26:34 +02:00
Paul Sokolovsky
5bf6eba845 tests/open_plus: Add tests for "r+", "w+" open modes. 2016-02-06 21:59:54 +02:00
Paul Sokolovsky
a63a4761cd unix/file: Stop assuming that O_RDWR == O_RDONLY | O_WRONLY.
That's not true e.g. on Linux.
2016-02-06 21:59:44 +02:00
Paul Sokolovsky
71206f02c3 stmhal: Move stmhal-specific FatFs routines/structs to fatfs_port.c. 2016-02-06 15:31:00 +02:00
Paul Sokolovsky
97a0846af9 stmhal/diskio: Introduce MICROPY_HW_HAS_FLASH setting.
To allow to reuse stmhal/diskio for ports which don't have flash but have
other storage devices.
2016-02-06 15:07:01 +02:00
Damien George
ff1a96ce2c py/mpz: Add commented-out mpz_pow3_inpl function, to compute (x**y)%z.
This function computes (x**y)%z in an efficient way.  For large arguments
this operation is otherwise not computable by doing x**y and then %z.

It's currently not used, but is added in case it's useful one day.
2016-02-03 22:30:49 +00:00
Doug Currie
2e2e15cec2 py/mpz: Complete implementation of mpz_{and,or,xor} for negative args.
For these 3 bitwise operations there are now fast functions for
positive-only arguments, and general functions for arbitrary sign
arguments (the fast functions are the existing implementation).

By default the fast functions are not used (to save space) and instead
the general functions are used for all operations.

Enable MICROPY_OPT_MPZ_BITWISE to use the fast functions for positive
arguments.
2016-02-03 22:13:39 +00:00
Damien George
5f3e005b67 py: Extend native type-sig to use 4 bits, so uint is separate to ptr.
Before this patch, the native types for uint and ptr/ptr8/ptr16/ptr32
all overlapped and it was possible to make a mistake in casting.  Now,
these types are all separate and any coding mistakes will be raised
as runtime errors.
2016-02-02 23:16:05 +00:00
Damien George
086d98cbde py/objstr: Make mp_obj_str_format_helper static. 2016-02-02 16:51:52 +00:00
Damien George
87e07ea943 py/objstr: For str.format, don't allocate on the heap for field name. 2016-02-02 16:26:21 +00:00
pohmelie
e3a29de1dc py/objstr: For str.format, add nested/computed fields support.
Eg: '{:{}}'.format(123, '>20')

@pohmelie was the original author of this patch, but @dpgeorge made
significant changes to reduce code size and improve efficiency.
2016-02-02 16:25:24 +00:00
Peter Hinch
2bd758fe96 drivers/sdcard: Add support for multi-block read/write; add SD test. 2016-02-02 11:16:15 +00:00
Paul Sokolovsky
67e8108345 extmod: Update uzlib to 1.2.2.
Fixes use of uninitialized structure field by tinf_uncompress().
2016-02-01 23:05:45 +02:00
Damien George
93bb7dffd2 py/vm: Fix popping of exception block in UNWIND_JUMP opcode.
Fixes issue #1812.
2016-02-01 16:07:21 +00:00
Damien George
9e677114e4 py/mpprint: Fix sign extension when printf'ing %u, %x and %X. 2016-02-01 15:08:42 +00:00
306 changed files with 12123 additions and 2970 deletions

View File

@@ -11,7 +11,7 @@ before_script:
# - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
- sudo dpkg --add-architecture i386
- sudo apt-get update -qq
- sudo apt-get update -qq || true
- sudo apt-get install -y python3 gcc-multilib gcc-arm-none-eabi pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32
# For teensy build
- sudo apt-get install realpath

View File

@@ -16,6 +16,7 @@ The MicroPython project
This is the MicroPython project, which aims to put an implementation
of Python 3.x on microcontrollers and small embedded systems.
You can find the official website at [micropython.org](http://www.micropython.org).
WARNING: this project is in beta stage and is subject to changes of the
code-base, including project-wide name changes and API changes.
@@ -129,7 +130,7 @@ The STM version
The "stmhal" port requires an ARM compiler, arm-none-eabi-gcc, and associated
bin-utils. For those using Arch Linux, you need arm-none-eabi-binutils and
arm-none-eabi-gcc packages from the AUR. Otherwise, try here:
arm-none-eabi-gcc packages. Otherwise, try here:
https://launchpad.net/gcc-arm-embedded
To build:
@@ -145,9 +146,7 @@ Then to flash the code via USB DFU to your device:
$ make deploy
You will need the dfu-util program, on Arch Linux it's dfu-util-git in the
AUR. If the above does not work it may be because you don't have the
correct permissions. Try then:
$ sudo dfu-util -a 0 -d 0483:df11 -D build-PYBV10/firmware.dfu
This will use the included `tools/pydfu.py` script. If flashing the firmware
does not work it may be because you don't have the correct permissions, and
need to use `sudo make deploy`.
See the README.md file in the stmhal/ directory for further details.

View File

@@ -17,7 +17,7 @@ include ../py/mkenv.mk
CROSS_COMPILE ?= arm-none-eabi-
CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -march=armv7e-m -mabi=aapcs -mcpu=cortex-m4 -msoft-float -mfloat-abi=soft -fsingle-precision-constant -Wdouble-promotion
CFLAGS = -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4)
CFLAGS = -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_CORTEX_M4) -Os
CFLAGS += -g -ffunction-sections -fdata-sections -fno-common -fsigned-char -mno-unaligned-access
CFLAGS += -Iboards/$(BOARD)

View File

@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/
__stack_size__ = 3K; /* interrupts are handled within this stack */
__stack_size__ = 2K; /* interrupts are handled within this stack */
__min_heap_size__ = 8K;
MEMORY

View File

@@ -157,7 +157,7 @@ APP_LIB_SRC_C = $(addprefix lib/,\
APP_STM_SRC_C = $(addprefix stmhal/,\
bufhelper.c \
file.c \
builtin_open.c \
import.c \
input.c \
irq.c \
@@ -183,31 +183,10 @@ $(BUILD)/drivers/cc3100/src/driver.o: CFLAGS += -fno-strict-aliasing
# Check if we would like to debug the port code
ifeq ($(BTYPE), release)
# Optimize everything and define the NDEBUG flag
CFLAGS += -Os -DNDEBUG
CFLAGS += -DNDEBUG
else
ifeq ($(BTYPE), debug)
# Define the DEBUG flag
CFLAGS += -DDEBUG=DEBUG
# Optimize the stable sources only
$(BUILD)/extmod/%.o: CFLAGS += -Os
$(BUILD)/lib/%.o: CFLAGS += -Os
$(BUILD)/fatfs/src/%.o: CFLAGS += -Os
$(BUILD)/FreeRTOS/Source/%.o: CFLAGS += -Os
$(BUILD)/ftp/%.o: CFLAGS += -Os
$(BUILD)/hal/%.o: CFLAGS += -Os
$(BUILD)/misc/%.o: CFLAGS += -Os
$(BUILD)/mods/%.o: CFLAGS += -Os
$(BUILD)/py/%.o: CFLAGS += -Os
$(BUILD)/simplelink/%.o: CFLAGS += -Os
$(BUILD)/drivers/cc3100/%.o: CFLAGS += -Os
$(BUILD)/stmhal/%.o: CFLAGS += -Os
$(BUILD)/telnet/%.o: CFLAGS += -Os
$(BUILD)/util/%.o: CFLAGS += -Os
$(BUILD)/pins.o: CFLAGS += -Os
$(BUILD)/main.o: CFLAGS += -Os
$(BUILD)/mptask.o: CFLAGS += -Os
$(BUILD)/servertask.o: CFLAGS += -Os
CFLAGS += -DNDEBUG
else
$(error Invalid BTYPE specified)
endif

View File

@@ -1,11 +1,11 @@
Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,ADC
1,GP10,GP10,GP10,I2C0_SCL,,TIM3_PWM0,,,SD0_CLK,UART1_TX,,,,,TIM0_CC1,,,,
2,GP11,GP11,GP11,I2C0_SDA,,TIM3_PWM1,pXCLK(XVCLK),,SD0_CMD,UART1_RX,,,,,TIM1_CC0,I2S0_FS,,,
3,GP12,GP12,GP12,,,I2S0_CLK,pVS(VSYNC),I2C0_SCL,,UART0_TX,,,,,TIM1_CC1,,,,
4,GP13,GP13,GP13,,,,pHS(HSYNC),I2C0_SDA,,UART0_RX,,,,,TIM2_CC0,,,,
5,GP14,GP14,GP14,,,,pDATA8(CAM_D4),I2C0_SCL,,SPI0_CLK,,,,,TIM2_CC1,,,,
6,GP15,GP15,GP15,,,,pDATA9(CAM_D5),I2C0_SDA,,SPI0_MISO,SD0_DAT0,,,,,TIM3_CC0,,,
7,GP16,GP16,GP16,,,,pDATA10(CAM_D6),UART1_TX,,SPI0_MOSI,SD0_CLK,,,,,TIM3_CC1,,,
1,GP10,GP10,GP10,I2C0_SCL,,TIM3_PWM,,,SD0_CLK,UART1_TX,,,,,TIM0_CC,,,,
2,GP11,GP11,GP11,I2C0_SDA,,TIM3_PWM,pXCLK(XVCLK),,SD0_CMD,UART1_RX,,,,,TIM1_CC,I2S0_FS,,,
3,GP12,GP12,GP12,,,I2S0_CLK,pVS(VSYNC),I2C0_SCL,,UART0_TX,,,,,TIM1_CC,,,,
4,GP13,GP13,GP13,,,,pHS(HSYNC),I2C0_SDA,,UART0_RX,,,,,TIM2_CC,,,,
5,GP14,GP14,GP14,,,,pDATA8(CAM_D4),I2C0_SCL,,SPI0_CLK,,,,,TIM2_CC,,,,
6,GP15,GP15,GP15,,,,pDATA9(CAM_D5),I2C0_SDA,,SPI0_MISO,SD0_DAT0,,,,,TIM3_CC,,,
7,GP16,GP16,GP16,,,,pDATA10(CAM_D6),UART1_TX,,SPI0_MOSI,SD0_CLK,,,,,TIM3_CC,,,
8,GP17,GP17,GP17,,,,pDATA11(CAM_D7),UART1_RX,,SPI0_CS0,SD0_CMD,,,,,,,,
9,VDD_DIG1,VDD_DIG1,VDD_DIG1,,,,,,,,,,,,,,,,
10,VIN_IO1,VIN_IO1,VIN_IO1,,,,,,,,,,,,,,,,
@@ -13,13 +13,13 @@ Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF1
12,FLASH_SPI_DOUT,FLASH_SPI_DOUT,FLASH_SPI_DOUT,,,,,,,,,,,,,,,,
13,FLASH_SPI_DIN,FLASH_SPI_DIN,FLASH_SPI_DIN,,,,,,,,,,,,,,,,
14,FLASH_SPI_CS,FLASH_SPI_CS,FLASH_SPI_CS,,,,,,,,,,,,,,,,
15,GP22,GP22,GP22,,,,,TIM2_CC0,,I2S0_FS,,,,,,,,,
15,GP22,GP22,GP22,,,,,TIM2_CC,,I2S0_FS,,,,,,,,,
16,GP23,TDI,GP23,TDI,UART1_TX,,,,,,,I2C0_SCL,,,,,,,
17,GP24,TDO,GP24,TDO,UART1_RX,,TIM3_CC0,TIM0_PWM0,I2S0_FS,,,I2C0_SDA,,,,,,,
17,GP24,TDO,GP24,TDO,UART1_RX,,TIM3_CC,TIM0_PWM,I2S0_FS,,,I2C0_SDA,,,,,,,
18,GP28,GP28,GP28,,,,,,,,,,,,,,,,
19,TCK,TCK,,TCK,,,,,,,TIM1_PWM2,,,,,,,,
19,TCK,TCK,,TCK,,,,,,,TIM1_PWM,,,,,,,,
20,GP29,TMS,GP29,TMS,,,,,,,,,,,,,,,
21,GP25,SOP2,GP25,,I2S0_FS,,,,,,,TIM1_PWM0,,,,,,,
21,GP25,SOP2,GP25,,I2S0_FS,,,,,,,TIM1_PWM,,,,,,,
22,WLAN_XTAL_N,WLAN_XTAL_N,WLAN_XTAL_N,,,,,,,,,,,,,,,,
23,WLAN_XTAL_P,WLAN_XTAL_P,WLAN_XTAL_P,,,,,,,,,,,,,,,,
24,VDD_PLL,VDD_PLL,VDD_PLL,,,,,,,,,,,,,,,,
@@ -48,19 +48,19 @@ Pin,Name,Default,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF1
47,VDD_ANA2,VDD_ANA2,VDD_ANA2,,,,,,,,,,,,,,,,
48,VDD_ANA1,VDD_ANA1,VDD_ANA1,,,,,,,,,,,,,,,,
49,VDD_RAM,VDD_RAM,VDD_RAM,,,,,,,,,,,,,,,,
50,GP0,GP0,GP0,,,UART0_RTS,I2S0_DAT0,,I2S0_DAT1,TIM0_CC0,,SPI0_CS0,UART1_RTS,,UART0_CTS,,,,
50,GP0,GP0,GP0,,,UART0_RTS,I2S0_DAT0,,I2S0_DAT1,TIM0_CC,,SPI0_CS0,UART1_RTS,,UART0_CTS,,,,
51,RTC_XTAL_P,RTC_XTAL_P,RTC_XTAL_P,,,,,,,,,,,,,,,,
52,RTC_XTAL_N,RTC_XTAL_N,GP32,,I2S0_CLK,,I2S0_DAT0,,UART0_RTS,,SPI0_MOSI,,,,,,,,
53,GP30,GP30,GP30,,I2S0_CLK,I2S0_FS,TIM2_CC1,,,SPI0_MISO,,UART0_TX,,,,,,,
53,GP30,GP30,GP30,,I2S0_CLK,I2S0_FS,TIM2_CC,,,SPI0_MISO,,UART0_TX,,,,,,,
54,VIN_IO2,VIN_IO2,VIN_IO2,,,,,,,,,,,,,,,,
55,GP1,GP1,GP1,,,UART0_TX,pCLK (PIXCLK),,UART1_TX,TIM0_CC1,,,,,,,,,
55,GP1,GP1,GP1,,,UART0_TX,pCLK (PIXCLK),,UART1_TX,TIM0_CC,,,,,,,,,
56,VDD_DIG2,VDD_DIG2,VDD_DIG2,,,,,,,,,,,,,,,,
57,GP2,GP2,GP2,,,UART0_RX,,,UART1_RX,TIM1_CC0,,,,,,,,,ADC0_CH0
57,GP2,GP2,GP2,,,UART0_RX,,,UART1_RX,TIM1_CC,,,,,,,,,ADC0_CH0
58,GP3,GP3,GP3,,,,pDATA7(CAM_D3),,UART1_TX,,,,,,,,,,ADC0_CH1
59,GP4,GP4,GP4,,,,pDATA6(CAM_D2),,UART1_RX,,,,,,,,,,ADC0_CH2
60,GP5,GP5,GP5,,,,pDATA5(CAM_D1),,I2S0_DAT1,TIM2_CC1,,,,,,,,,ADC0_CH3
61,GP6,GP6,GP6,,,UART1_CTS,pDATA4(CAM_D0),UART0_RTS,UART0_CTS,TIM3_CC0,,,,,,,,,
60,GP5,GP5,GP5,,,,pDATA5(CAM_D1),,I2S0_DAT1,TIM2_CC,,,,,,,,,ADC0_CH3
61,GP6,GP6,GP6,,,UART1_CTS,pDATA4(CAM_D0),UART0_RTS,UART0_CTS,TIM3_CC,,,,,,,,,
62,GP7,GP7,GP7,,,UART1_RTS,,,,,,,UART0_RTS,UART0_TX,,I2S0_CLK,,,
63,GP8,GP8,GP8,,,,,,SD0_IRQ,I2S0_FS,,,,,TIM3_CC0,,,,
64,GP9,GP9,GP9,,,TIM2_PWM1,,,SD0_DAT0,I2S0_DAT0,,,,,TIM0_CC0,,,,
63,GP8,GP8,GP8,,,,,,SD0_IRQ,I2S0_FS,,,,,TIM3_CC,,,,
64,GP9,GP9,GP9,,,TIM2_PWM,,,SD0_DAT0,I2S0_DAT0,,,,,TIM0_CC,,,,
65,GND_TAB,GND_TAB,GND_TAB,,,,,,,,,,,,,,,,
1 Pin Name Default AF0 AF1 AF2 AF3 AF4 AF5 AF6 AF7 AF8 AF9 AF10 AF11 AF12 AF13 AF14 AF15 ADC
2 1 GP10 GP10 GP10 I2C0_SCL TIM3_PWM0 TIM3_PWM SD0_CLK UART1_TX TIM0_CC1 TIM0_CC
3 2 GP11 GP11 GP11 I2C0_SDA TIM3_PWM1 TIM3_PWM pXCLK(XVCLK) SD0_CMD UART1_RX TIM1_CC0 TIM1_CC I2S0_FS
4 3 GP12 GP12 GP12 I2S0_CLK pVS(VSYNC) I2C0_SCL UART0_TX TIM1_CC1 TIM1_CC
5 4 GP13 GP13 GP13 pHS(HSYNC) I2C0_SDA UART0_RX TIM2_CC0 TIM2_CC
6 5 GP14 GP14 GP14 pDATA8(CAM_D4) I2C0_SCL SPI0_CLK TIM2_CC1 TIM2_CC
7 6 GP15 GP15 GP15 pDATA9(CAM_D5) I2C0_SDA SPI0_MISO SD0_DAT0 TIM3_CC0 TIM3_CC
8 7 GP16 GP16 GP16 pDATA10(CAM_D6) UART1_TX SPI0_MOSI SD0_CLK TIM3_CC1 TIM3_CC
9 8 GP17 GP17 GP17 pDATA11(CAM_D7) UART1_RX SPI0_CS0 SD0_CMD
10 9 VDD_DIG1 VDD_DIG1 VDD_DIG1
11 10 VIN_IO1 VIN_IO1 VIN_IO1
13 12 FLASH_SPI_DOUT FLASH_SPI_DOUT FLASH_SPI_DOUT
14 13 FLASH_SPI_DIN FLASH_SPI_DIN FLASH_SPI_DIN
15 14 FLASH_SPI_CS FLASH_SPI_CS FLASH_SPI_CS
16 15 GP22 GP22 GP22 TIM2_CC0 TIM2_CC I2S0_FS
17 16 GP23 TDI GP23 TDI UART1_TX I2C0_SCL
18 17 GP24 TDO GP24 TDO UART1_RX TIM3_CC0 TIM3_CC TIM0_PWM0 TIM0_PWM I2S0_FS I2C0_SDA
19 18 GP28 GP28 GP28
20 19 TCK TCK TCK TIM1_PWM2 TIM1_PWM
21 20 GP29 TMS GP29 TMS
22 21 GP25 SOP2 GP25 I2S0_FS TIM1_PWM0 TIM1_PWM
23 22 WLAN_XTAL_N WLAN_XTAL_N WLAN_XTAL_N
24 23 WLAN_XTAL_P WLAN_XTAL_P WLAN_XTAL_P
25 24 VDD_PLL VDD_PLL VDD_PLL
48 47 VDD_ANA2 VDD_ANA2 VDD_ANA2
49 48 VDD_ANA1 VDD_ANA1 VDD_ANA1
50 49 VDD_RAM VDD_RAM VDD_RAM
51 50 GP0 GP0 GP0 UART0_RTS I2S0_DAT0 I2S0_DAT1 TIM0_CC0 TIM0_CC SPI0_CS0 UART1_RTS UART0_CTS
52 51 RTC_XTAL_P RTC_XTAL_P RTC_XTAL_P
53 52 RTC_XTAL_N RTC_XTAL_N GP32 I2S0_CLK I2S0_DAT0 UART0_RTS SPI0_MOSI
54 53 GP30 GP30 GP30 I2S0_CLK I2S0_FS TIM2_CC1 TIM2_CC SPI0_MISO UART0_TX
55 54 VIN_IO2 VIN_IO2 VIN_IO2
56 55 GP1 GP1 GP1 UART0_TX pCLK (PIXCLK) UART1_TX TIM0_CC1 TIM0_CC
57 56 VDD_DIG2 VDD_DIG2 VDD_DIG2
58 57 GP2 GP2 GP2 UART0_RX UART1_RX TIM1_CC0 TIM1_CC ADC0_CH0
59 58 GP3 GP3 GP3 pDATA7(CAM_D3) UART1_TX ADC0_CH1
60 59 GP4 GP4 GP4 pDATA6(CAM_D2) UART1_RX ADC0_CH2
61 60 GP5 GP5 GP5 pDATA5(CAM_D1) I2S0_DAT1 TIM2_CC1 TIM2_CC ADC0_CH3
62 61 GP6 GP6 GP6 UART1_CTS pDATA4(CAM_D0) UART0_RTS UART0_CTS TIM3_CC0 TIM3_CC
63 62 GP7 GP7 GP7 UART1_RTS UART0_RTS UART0_TX I2S0_CLK
64 63 GP8 GP8 GP8 SD0_IRQ I2S0_FS TIM3_CC0 TIM3_CC
65 64 GP9 GP9 GP9 TIM2_PWM1 TIM2_PWM SD0_DAT0 I2S0_DAT0 TIM0_CC0 TIM0_CC
66 65 GND_TAB GND_TAB GND_TAB

View File

@@ -12,7 +12,7 @@ SUPPORTED_AFS = { 'UART': ('TX', 'RX', 'RTS', 'CTS'),
'SPI': ('CLK', 'MOSI', 'MISO', 'CS0'),
#'I2S': ('CLK', 'FS', 'DAT0', 'DAT1'),
'I2C': ('SDA', 'SCL'),
'TIM': ('PWM0', 'PWM1', 'CC0', 'CC1'),
'TIM': ('PWM'),
'SD': ('CLK', 'CMD', 'DAT0'),
'ADC': ('CH0', 'CH1', 'CH2', 'CH3')
}
@@ -44,6 +44,7 @@ class AF:
def print(self):
print (' AF({:16s}, {:4d}, {:8s}, {:4d}, {:8s}), // {}'.format(self.name, self.idx, self.fn, self.unit, self.type, self.name))
class Pin:
"""Holds the information associated with a pin."""
def __init__(self, name, port, gpio_bit, pin_num):

View File

@@ -196,6 +196,10 @@ void nlr_jump_fail(void *val) {
void mperror_enable_heartbeat (bool enable) {
if (enable) {
#ifndef BOOTLOADER
// configure the led again
pin_config ((pin_obj_t *)&MICROPY_SYS_LED_GPIO, PIN_MODE_0, GPIO_DIR_MODE_OUT, PIN_TYPE_STD, 0, PIN_STRENGTH_6MA);
#endif
mperror_heart_beat.enabled = true;
mperror_heart_beat.do_disable = false;
mperror_heartbeat_switch_off();

View File

@@ -153,7 +153,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&mod_network_nic_type_wlan },
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
{ MP_OBJ_NEW_QSTR(MP_QSTR_server), (mp_obj_t)&network_server_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Server), (mp_obj_t)&network_server_type },
#endif
};
@@ -177,7 +177,7 @@ STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_di
STATIC const mp_obj_type_t network_server_type = {
{ &mp_type_type },
.name = MP_QSTR_server,
.name = MP_QSTR_Server,
.make_new = network_server_make_new,
.locals_dict = (mp_obj_t)&network_server_locals_dict,
};

View File

@@ -37,7 +37,7 @@
#include "moduos.h"
#include "diskio.h"
#include "sflash_diskio.h"
#include "file.h"
#include "extmod/vfs_fat_file.h"
#include "random.h"
#include "mpexception.h"
#include "version.h"

View File

@@ -106,8 +106,10 @@ void modusocket_enter_sleep (void) {
}
}
// wait for any of the sockets to become ready...
sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
if (maxfd > 0) {
// wait for any of the sockets to become ready...
sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
}
}
void modusocket_close_all_user_sockets (void) {

View File

@@ -33,6 +33,7 @@
#include "py/obj.h"
#include "py/objstr.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mphal.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
@@ -149,8 +150,8 @@ STATIC wlan_obj_t wlan_obj = {
.ssid = MICROPY_PORT_WLAN_AP_SSID,
.key = MICROPY_PORT_WLAN_AP_KEY,
.mac = {0},
.ssid_o = {0},
.bssid = {0},
//.ssid_o = {0},
//.bssid = {0},
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
.servers_enabled = false,
#endif
@@ -210,11 +211,11 @@ void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) {
{
case SL_WLAN_CONNECT_EVENT:
{
slWlanConnectAsyncResponse_t *pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected;
//slWlanConnectAsyncResponse_t *pEventData = &pWlanEvent->EventData.STAandP2PModeWlanConnected;
// copy the new connection data
memcpy(wlan_obj.bssid, pEventData->bssid, SL_BSSID_LENGTH);
memcpy(wlan_obj.ssid_o, pEventData->ssid_name, pEventData->ssid_len);
wlan_obj.ssid_o[pEventData->ssid_len] = '\0';
//memcpy(wlan_obj.bssid, pEventData->bssid, SL_BSSID_LENGTH);
//memcpy(wlan_obj.ssid_o, pEventData->ssid_name, pEventData->ssid_len);
//wlan_obj.ssid_o[pEventData->ssid_len] = '\0';
SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION);
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
// we must reset the servers in case that the last connection
@@ -228,15 +229,16 @@ void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) {
CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_IP_ACQUIRED);
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
servers_reset();
servers_wlan_cycle_power();
#endif
break;
case SL_WLAN_STA_CONNECTED_EVENT:
{
slPeerInfoAsyncResponse_t *pEventData = &pWlanEvent->EventData.APModeStaConnected;
//slPeerInfoAsyncResponse_t *pEventData = &pWlanEvent->EventData.APModeStaConnected;
// get the mac address and name of the connected device
memcpy(wlan_obj.bssid, pEventData->mac, SL_BSSID_LENGTH);
memcpy(wlan_obj.ssid_o, pEventData->go_peer_device_name, pEventData->go_peer_device_name_len);
wlan_obj.ssid_o[pEventData->go_peer_device_name_len] = '\0';
//memcpy(wlan_obj.bssid, pEventData->mac, SL_BSSID_LENGTH);
//memcpy(wlan_obj.ssid_o, pEventData->go_peer_device_name, pEventData->go_peer_device_name_len);
//wlan_obj.ssid_o[pEventData->go_peer_device_name_len] = '\0';
SET_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION);
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
// we must reset the servers in case that the last connection
@@ -249,6 +251,7 @@ void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) {
CLR_STATUS_BIT(wlan_obj.status, STATUS_BIT_CONNECTION);
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
servers_reset();
servers_wlan_cycle_power();
#endif
break;
case SL_WLAN_P2P_DEV_FOUND_EVENT:
@@ -547,6 +550,12 @@ void wlan_set_current_time (uint32_t seconds_since_2000) {
sl_DevSet(SL_DEVICE_GENERAL_CONFIGURATION, SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME, sizeof(SlDateTime_t), (_u8 *)(&sl_datetime));
}
void wlan_off_on (void) {
// no need to lock the WLAN object on every API call since the servers and the MicroPtyhon
// task have the same priority
wlan_reenable(wlan_obj.mode);
}
//*****************************************************************************
// DEFINE STATIC FUNCTIONS
//*****************************************************************************
@@ -554,8 +563,8 @@ void wlan_set_current_time (uint32_t seconds_since_2000) {
STATIC void wlan_clear_data (void) {
CLR_STATUS_BIT_ALL(wlan_obj.status);
wlan_obj.ip = 0;
memset(wlan_obj.ssid_o, 0, sizeof(wlan_obj.ssid));
memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid));
//memset(wlan_obj.ssid_o, 0, sizeof(wlan_obj.ssid));
//memset(wlan_obj.bssid, 0, sizeof(wlan_obj.bssid));
}
STATIC void wlan_reenable (SlWlanMode_t mode) {

View File

@@ -95,6 +95,7 @@ extern void wlan_get_mac (uint8_t *macAddress);
extern void wlan_get_ip (uint32_t *ip);
extern bool wlan_is_connected (void);
extern void wlan_set_current_time (uint32_t seconds_since_2000);
extern void wlan_off_on (void);
extern int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family);
extern int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno);

View File

@@ -63,7 +63,7 @@ typedef struct _pyb_i2c_obj_t {
#define PYBI2C_MIN_BAUD_RATE_HZ (50000)
#define PYBI2C_MAX_BAUD_RATE_HZ (400000)
#define PYBI2C_TRANSC_TIMEOUT_MS (10)
#define PYBI2C_TRANSC_TIMEOUT_MS (20)
#define PYBI2C_TRANSAC_WAIT_DELAY_US (10)
#define PYBI2C_TIMEOUT_TO_COUNT(to_us, baud) (((baud) * to_us) / 16000000)
@@ -78,9 +78,13 @@ typedef struct _pyb_i2c_obj_t {
DECLARE PRIVATE DATA
******************************************************************************/
STATIC pyb_i2c_obj_t pyb_i2c_obj = {.baudrate = 0};
STATIC const mp_obj_t pyb_i2c_def_pin[2] = {&pin_GP13, &pin_GP23};
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC bool pyb_i2c_write(byte addr, byte *data, uint len, bool stop);
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
@@ -107,13 +111,13 @@ STATIC bool pyb_i2c_transaction(uint cmd) {
// Wait until the current byte has been transferred.
// Poll on the raw interrupt status.
while ((MAP_I2CMasterIntStatusEx(I2CA0_BASE, false) & (I2C_MASTER_INT_DATA | I2C_MASTER_INT_TIMEOUT)) == 0) {
// wait for a few microseconds
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US));
timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US;
if (timeout < 0) {
// the peripheral is not responding, so stop
return false;
}
// wait for a few microseconds
UtilsDelay(UTILS_DELAY_US_TO_COUNT(PYBI2C_TRANSAC_WAIT_DELAY_US));
timeout -= PYBI2C_TRANSAC_WAIT_DELAY_US;
}
// Check for any errors in the transfer
@@ -145,13 +149,22 @@ STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) {
}
STATIC bool pyb_i2c_scan_device(byte devAddr) {
// Set I2C codec slave address
bool ret = false;
// Set the I2C slave address
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE, devAddr, true);
// Initiate the transfer.
RET_IF_ERR(pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE));
// Since this is a hack, send the stop bit anyway
if (pyb_i2c_transaction(I2C_MASTER_CMD_SINGLE_RECEIVE)) {
ret = true;
}
// Send the stop bit to cancel the read transaction
MAP_I2CMasterControl(I2CA0_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
return true;
if (!ret) {
uint8_t data = 0;
if (pyb_i2c_write(devAddr, &data, sizeof(data), true)) {
ret = true;
}
}
return ret;
}
STATIC bool pyb_i2c_mem_addr_write (byte addr, byte *mem_addr, uint mem_addr_len) {
@@ -365,7 +378,7 @@ STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) {
pyb_i2c_check_init(&pyb_i2c_obj);
mp_obj_t list = mp_obj_new_list(0, NULL);
for (uint addr = 1; addr <= 127; addr++) {
for (int i = 0; i < 7; i++) {
for (int i = 0; i < 3; i++) {
if (pyb_i2c_scan_device(addr)) {
mp_obj_list_append(list, mp_obj_new_int(addr));
break;

View File

@@ -60,7 +60,6 @@ DECLARE PRIVATE FUNCTIONS
STATIC pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name);
STATIC pin_obj_t *pin_find_pin_by_port_bit (const mp_obj_dict_t *named_pins, uint port, uint bit);
STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);
STATIC int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);
STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type);
STATIC void pin_deassign (pin_obj_t* pin);
STATIC void pin_obj_configure (const pin_obj_t *self);
@@ -199,6 +198,14 @@ uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit)
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) {
int8_t af = pin_obj_find_af(pin, fn, unit, type);
if (af < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
return af;
}
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
@@ -231,14 +238,6 @@ STATIC int8_t pin_obj_find_af (const pin_obj_t* pin, uint8_t fn, uint8_t unit, u
return -1;
}
STATIC int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) {
int8_t af = pin_obj_find_af(pin, fn, unit, type);
if (af < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
return af;
}
STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type) {
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
for (uint i = 0; i < named_map->used - 1; i++) {
@@ -248,7 +247,7 @@ STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type) {
// check if the pin supports the target af
int af = pin_obj_find_af(pin, fn, unit, type);
if (af > 0 && af == pin->af) {
// the pin is assigned to the target af, de-assign it
// the pin supports the target af, de-assign it
pin_deassign (pin);
}
}

View File

@@ -72,10 +72,7 @@ enum {
};
enum {
PIN_TYPE_TIM_PWM0 = 0,
PIN_TYPE_TIM_PWM1,
PIN_TYPE_TIM_CC0,
PIN_TYPE_TIM_CC1,
PIN_TYPE_TIM_PWM = 0,
};
enum {
@@ -139,5 +136,6 @@ pin_obj_t *pin_find(mp_obj_t user_obj);
void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit);
uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type);
uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit);
int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type);;
#endif // PYBPIN_H_

View File

@@ -43,7 +43,10 @@
#include "interrupt.h"
#include "prcm.h"
#include "timer.h"
#include "pin.h"
#include "pybtimer.h"
#include "pybpin.h"
#include "pins.h"
#include "mpirq.h"
#include "pybsleep.h"
#include "mpexception.h"
@@ -55,30 +58,8 @@
/// Each timer consists of a counter that counts up at a certain rate. The rate
/// at which it counts is the peripheral clock frequency (in Hz) divided by the
/// timer prescaler. When the counter reaches the timer period it triggers an
/// event, and the counter resets back to zero. By using the callback method,
/// event, and the counter resets back to zero. By using the irq method,
/// the timer event can call a Python function.
///
/// Example usage to toggle an LED at a fixed frequency:
///
/// tim = pyb.Timer(4) # create a timer object using timer 4
/// tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
/// tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
/// tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
///
/// Further examples:
///
/// tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
/// tim2 = pyb.Timer(1, mode=Timer.PWM) # initialize it in PWM mode
/// tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
/// tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
/// tim_ch.time() # get the current time in usec (can also be set)
/// tim_ch.freq(20) # set the frequency (can also get)
/// tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
/// tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
/// tim_ch.event_count() # get the number of captured events
/// tim_ch.event_time() # get the the time of the last captured event
/// tim_ch.period(2000000) # change the period to 2 seconds
///
/******************************************************************************
DECLARE PRIVATE CONSTANTS
@@ -87,6 +68,9 @@
#define PYBTIMER_POLARITY_POS (0x01)
#define PYBTIMER_POLARITY_NEG (0x02)
#define PYBTIMER_TIMEOUT_TRIGGER (0x01)
#define PYBTIMER_MATCH_TRIGGER (0x02)
#define PYBTIMER_SRC_FREQ_HZ HAL_FCPU_HZ
/******************************************************************************
@@ -108,8 +92,8 @@ typedef struct _pyb_timer_channel_obj_t {
uint32_t frequency;
uint32_t period;
uint16_t channel;
uint16_t duty_cycle;
uint8_t polarity;
uint8_t duty_cycle;
} pyb_timer_channel_obj_t;
/******************************************************************************
@@ -121,12 +105,14 @@ STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_B
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
{.timer = TIMERA3_BASE, .peripheral = PRCM_TIMERA3}};
STATIC const mp_obj_type_t pyb_timer_channel_type;
STATIC const mp_obj_t pyb_timer_pwm_pin[8] = {&pin_GP24, MP_OBJ_NULL, &pin_GP25, MP_OBJ_NULL, MP_OBJ_NULL, &pin_GP9, &pin_GP10, &pin_GP11};
/******************************************************************************
DECLARE PRIVATE FUNCTIONS
******************************************************************************/
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
STATIC void timer_disable (pyb_timer_obj_t *tim);
STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch);
STATIC void TIMER0AIntHandler(void);
STATIC void TIMER0BIntHandler(void);
STATIC void TIMER1AIntHandler(void);
@@ -177,6 +163,8 @@ STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
pyb_timer_channel_obj_t *channel;
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
// unregister it with the sleep module
pyb_sleep_remove((const mp_obj_t)channel);
}
}
@@ -184,6 +172,8 @@ STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
// remove it in case it already exists
pyb_timer_channel_remove(ch);
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
// register it with the sleep module
pyb_sleep_add((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
}
STATIC void timer_disable (pyb_timer_obj_t *tim) {
@@ -191,8 +181,15 @@ STATIC void timer_disable (pyb_timer_obj_t *tim) {
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
pyb_timer_channel_obj_t *ch;
// disable its channels
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_A))) {
pyb_sleep_remove(ch);
}
if ((ch = pyb_timer_channel_find (tim->timer, TIMER_B))) {
pyb_sleep_remove(ch);
}
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
}
// computes prescaler period and match value so timer triggers at freq-Hz
@@ -205,20 +202,23 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t
if (period_c == 0) {
goto error;
}
prescaler = period_c >> 16;
prescaler = period_c >> 16; // The prescaler is an extension of the timer counter
*period_out = period_c;
if (prescaler > 0xFF && maxcount == 0xFFFF) {
goto error;
}
// check limit values for the duty cycle
if (ch->duty_cycle == 0) {
*match_out = period_c - 1;
}
else {
*match_out = period_c - ((period_c * ch->duty_cycle) / 100);
}
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM && (*match_out > 0xFFFF)) {
goto error;
} else {
if (period_c > 0xFFFF) {
uint32_t match = (period_c * 100) / 10000;
*match_out = period_c - ((match * ch->duty_cycle) / 100);
} else {
*match_out = period_c - ((period_c * ch->duty_cycle) / 10000);
}
}
return prescaler;
@@ -250,17 +250,7 @@ STATIC void timer_channel_init (pyb_timer_channel_obj_t *ch) {
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
// set the match value (which is simply the duty cycle translated to ticks)
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
}
// configure the event edge type if we are in such mode
else if ((ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_COUNT || (ch->timer->config & 0x0F) == TIMER_CFG_A_CAP_TIME) {
uint32_t polarity = TIMER_EVENT_BOTH_EDGES;
if (ch->polarity == PYBTIMER_POLARITY_POS) {
polarity = TIMER_EVENT_POS_EDGE;
}
else if (ch->polarity == PYBTIMER_POLARITY_NEG) {
polarity = TIMER_EVENT_NEG_EDGE;
}
MAP_TimerControlEvent(ch->timer->timer, ch->channel, polarity);
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
}
#ifdef DEBUG
@@ -282,37 +272,18 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
// timer mode
qstr mode_qst = MP_QSTR_PWM;
switch(mode) {
case TIMER_CFG_A_ONE_SHOT:
case TIMER_CFG_A_ONE_SHOT_UP:
mode_qst = MP_QSTR_ONE_SHOT;
break;
case TIMER_CFG_A_PERIODIC:
case TIMER_CFG_A_PERIODIC_UP:
mode_qst = MP_QSTR_PERIODIC;
break;
case TIMER_CFG_A_CAP_COUNT:
mode_qst = MP_QSTR_EDGE_COUNT;
break;
case TIMER_CFG_A_CAP_TIME:
mode_qst = MP_QSTR_EDGE_TIME;
break;
default:
break;
}
mp_printf(print, "<Timer%u, mode=Timer.%q>", (tim->id + 1), mode_qst);
mp_printf(print, "Timer(%u, mode=Timer.%q)", tim->id, mode_qst);
}
/// \method init(mode, *, width)
/// Initialise the timer. Initialisation must give the desired mode
/// and an optional timer width
///
/// tim.init(mode=Timer.ONE_SHOT, width=32) # one shot mode
/// tim.init(mode=Timer.PERIODIC) # configure in free running periodic mode
/// split into two 16-bit independent timers
///
/// Keyword arguments:
///
/// - `width` - specifies the width of the timer. Default is 32 bit mode. When in 16 bit mode
/// the timer is splitted into 2 independent channels.
///
STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, 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_mode, MP_ARG_REQUIRED | MP_ARG_INT, },
@@ -325,8 +296,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
// check the mode
uint32_t _mode = args[0].u_int;
if (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC && _mode != TIMER_CFG_A_CAP_COUNT &&
_mode != TIMER_CFG_A_CAP_TIME && _mode != TIMER_CFG_A_PWM) {
if (_mode != TIMER_CFG_A_ONE_SHOT_UP && _mode != TIMER_CFG_A_PERIODIC_UP && _mode != TIMER_CFG_A_PWM) {
goto error;
}
@@ -336,7 +306,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
}
bool is16bit = (args[1].u_int == 16);
if (!is16bit && (_mode != TIMER_CFG_A_ONE_SHOT && _mode != TIMER_CFG_A_PERIODIC)) {
if (!is16bit && _mode == TIMER_CFG_A_PWM) {
// 32-bit mode is only available when in free running modes
goto error;
}
@@ -352,16 +322,12 @@ error:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
/// \classmethod \constructor(id, ...)
/// Construct a new timer object of the given id. If additional
/// arguments are given, then the timer is initialised by `init(...)`.
/// `id` can be 1 to 4
STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// create a new Timer object
int32_t timer_idx = mp_obj_get_int(args[0]) - 1;
int32_t timer_idx = mp_obj_get_int(args[0]);
if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
}
@@ -379,15 +345,11 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args,
return (mp_obj_t)tim;
}
// \method init()
/// initializes the timer
STATIC mp_obj_t pyb_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return pyb_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init);
// \method deinit()
/// disables the timer
STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
pyb_timer_obj_t *self = self_in;
timer_disable(self);
@@ -395,24 +357,6 @@ STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
/// \method channel(channel, *, freq, period, polarity, duty_cycle)
/// Initialise the timer channel. Initialization requires at least a frequency param. With no
/// extra params given besides the channel id, the channel is returned with the previous configuration
/// os 'None', if it hasn't been initialized before.
///
/// tim1.channel(Timer.A, freq=1000) # set channel A frequency to 1KHz
/// tim2.channel(Timer.AB, freq=10) # both channels (because it's a 32 bit timer) combined to create a 10Hz timer
///
/// when initialiazing the channel of a 32-bit timer, channel ID MUST be = Timer.AB
///
/// Keyword arguments:
///
/// - `freq` - specifies the frequency in Hz.
/// - `period` - specifies the period in microseconds.
/// - `polarity` - in PWM specifies the polarity of the pulse. In capture mode specifies the edge to capture.
/// in order to capture on both negative and positive edges, make it = Timer.POSITIVE | Timer.NEGATIVE.
/// - `duty_cycle` - sets the duty cycle value
///
STATIC mp_obj_t pyb_timer_channel(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_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
@@ -474,12 +418,21 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
ch->frequency = args[0].u_int;
ch->period = args[1].u_int;
ch->polarity = args[2].u_int;
ch->duty_cycle = MIN(100, MAX(0, args[3].u_int));
ch->duty_cycle = MIN(10000, MAX(0, args[3].u_int));
timer_channel_init(ch);
// register it with the sleep module
pyb_sleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
// assign the pin
if ((ch->timer->config & 0x0F) == TIMER_CFG_A_PWM) {
uint32_t ch_idx = (ch->channel == TIMER_A) ? 0 : 1;
// use the default pin if available
mp_obj_t pin_o = (mp_obj_t)pyb_timer_pwm_pin[(ch->timer->id * 2) + ch_idx];
if (pin_o != MP_OBJ_NULL) {
pin_obj_t *pin = pin_find(pin_o);
pin_config (pin, pin_find_af_index(pin, PIN_FN_TIM, ch->timer->id, PIN_TYPE_TIM_PWM),
0, PIN_TYPE_STD, -1, PIN_STRENGTH_4MA);
}
}
// add the timer to the list
pyb_timer_channel_add(ch);
@@ -500,13 +453,13 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_A), MP_OBJ_NEW_SMALL_INT(TIMER_A) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_B), MP_OBJ_NEW_SMALL_INT(TIMER_B) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_COUNT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_COUNT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_EDGE_TIME), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_CAP_TIME) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_ONE_SHOT_UP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PERIODIC_UP) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWM), MP_OBJ_NEW_SMALL_INT(TIMER_CFG_A_PWM) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_POSITIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_POS) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_NEGATIVE), MP_OBJ_NEW_SMALL_INT(PYBTIMER_POLARITY_NEG) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_TIMEOUT), MP_OBJ_NEW_SMALL_INT(PYBTIMER_TIMEOUT_TRIGGER) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MATCH), MP_OBJ_NEW_SMALL_INT(PYBTIMER_MATCH_TRIGGER) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_timer_locals_dict, pyb_timer_locals_dict_table);
@@ -528,7 +481,6 @@ STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
pyb_timer_channel_obj_t *self;
uint32_t status;
if ((self = pyb_timer_channel_find(timer, channel))) {
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
MAP_TimerIntClear(self->timer->timer, status);
@@ -574,16 +526,14 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
// timer channel
if (ch->channel == TIMER_A) {
ch_id = "A";
}
else if (ch->channel == TIMER_B) {
} else if (ch->channel == TIMER_B) {
ch_id = "B";
}
mp_printf(print, "<%q %s, timer=%u, %q=%u", MP_QSTR_TimerChannel,
ch_id, (ch->timer->id + 1), MP_QSTR_freq, ch->frequency);
mp_printf(print, "timer.channel(Timer.%s, %q=%u", ch_id, MP_QSTR_freq, ch->frequency);
uint32_t mode = ch->timer->config & 0xFF;
if (mode == TIMER_CFG_A_CAP_COUNT || mode == TIMER_CFG_A_CAP_TIME || mode == TIMER_CFG_A_PWM) {
if (mode == TIMER_CFG_A_PWM) {
mp_printf(print, ", %q=Timer.", MP_QSTR_polarity);
switch (ch->polarity) {
case PYBTIMER_POLARITY_POS:
@@ -596,15 +546,11 @@ STATIC void pyb_timer_channel_print(const mp_print_t *print, mp_obj_t self_in, m
mp_printf(print, "BOTH");
break;
}
if (mode == TIMER_CFG_A_PWM) {
mp_printf(print, ", %q=%u", MP_QSTR_duty_cycle, ch->duty_cycle);
}
mp_printf(print, ", %q=%u.%02u", MP_QSTR_duty_cycle, ch->duty_cycle / 100, ch->duty_cycle % 100);
}
mp_printf(print, ">");
mp_printf(print, ")");
}
/// \method freq([value])
/// get or set the frequency of the timer channel
STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
pyb_timer_channel_obj_t *ch = args[0];
if (n_args == 1) {
@@ -624,8 +570,6 @@ STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_freq_obj, 1, 2, pyb_timer_channel_freq);
/// \method period([value])
/// get or set the period of the timer channel in microseconds
STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args) {
pyb_timer_channel_obj_t *ch = args[0];
if (n_args == 1) {
@@ -645,74 +589,17 @@ STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_period_obj, 1, 2, pyb_timer_channel_period);
/// \method time([value])
/// get or set the value of the timer channel in microseconds
STATIC mp_obj_t pyb_timer_channel_time(mp_uint_t n_args, const mp_obj_t *args) {
pyb_timer_channel_obj_t *ch = args[0];
uint32_t value;
// calculate the period, the prescaler and the match value
uint32_t period_c;
uint32_t match;
(void)compute_prescaler_period_and_match_value(ch, &period_c, &match);
if (n_args == 1) {
// get
value = (ch->channel == TIMER_B) ? HWREG(ch->timer->timer + TIMER_O_TBV) : HWREG(ch->timer->timer + TIMER_O_TAV);
// return the current timer value in microseconds
// substract value to period since we are always operating in count-down mode
uint32_t time_t = (1000 * (period_c - value)) / period_c;
return mp_obj_new_int((time_t * 1000) / ch->frequency);
}
else {
// set
value = (mp_obj_get_int(args[1]) * ((ch->frequency * period_c) / 1000)) / 1000;
if ((value > 0xFFFF) && (ch->timer->config & TIMER_CFG_SPLIT_PAIR)) {
// this exceeds the maximum value of a 16-bit timer
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
}
// write period minus value since we are always operating in count-down mode
TimerValueSet (ch->timer->timer, ch->channel, (period_c - value));
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_time_obj, 1, 2, pyb_timer_channel_time);
/// \method event_count()
/// get the number of events triggered by the configured edge
STATIC mp_obj_t pyb_timer_channel_event_count(mp_obj_t self_in) {
pyb_timer_channel_obj_t *ch = self_in;
return mp_obj_new_int(MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_count_obj, pyb_timer_channel_event_count);
/// \method event_time()
/// get the time at which the last event was triggered
STATIC mp_obj_t pyb_timer_channel_event_time(mp_obj_t self_in) {
pyb_timer_channel_obj_t *ch = self_in;
// calculate the period, the prescaler and the match value
uint32_t period_c;
uint32_t match;
(void)compute_prescaler_period_and_match_value(ch, &period_c, &match);
uint32_t value = MAP_TimerValueGet(ch->timer->timer, ch->channel == (TIMER_A | TIMER_B) ? TIMER_A : ch->channel);
// substract value to period since we are always operating in count-down mode
uint32_t time_t = (1000 * (period_c - value)) / period_c;
return mp_obj_new_int((time_t * 1000) / ch->frequency);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_time_obj, pyb_timer_channel_event_time);
/// \method duty_cycle()
/// get or set the duty cycle when in PWM mode
STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *args) {
pyb_timer_channel_obj_t *ch = args[0];
if (n_args == 1) {
// get
return mp_obj_new_int(ch->duty_cycle);
}
else {
} else {
// duty cycle must be converted from percentage to ticks
// calculate the period, the prescaler and the match value
uint32_t period_c;
uint32_t match;
ch->duty_cycle = MIN(100, MAX(0, mp_obj_get_int(args[1])));
ch->duty_cycle = MIN(10000, MAX(0, mp_obj_get_int(args[1])));
compute_prescaler_period_and_match_value(ch, &period_c, &match);
if (n_args == 3) {
// set the new polarity if requested
@@ -720,13 +607,12 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
MAP_TimerControlLevel(ch->timer->timer, ch->channel, (ch->polarity == PYBTIMER_POLARITY_NEG) ? true : false);
}
MAP_TimerMatchSet(ch->timer->timer, ch->channel, match);
MAP_TimerPrescaleMatchSet(ch->timer->timer, ch->channel, match >> 16);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
/// \method irq(trigger, priority, handler, wake)
/// FIXME triggers!!
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
@@ -741,25 +627,28 @@ STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_arg
goto invalid_args;
}
// get the trigger
uint trigger = mp_obj_get_int(args[0].u_obj);
// disable the callback first
pyb_timer_channel_irq_disable(ch);
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
switch (_config) {
case TIMER_CFG_A_ONE_SHOT:
case TIMER_CFG_A_PERIODIC:
case TIMER_CFG_A_ONE_SHOT_UP:
case TIMER_CFG_A_PERIODIC_UP:
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
break;
case TIMER_CFG_A_CAP_COUNT:
ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift;
break;
case TIMER_CFG_A_CAP_TIME:
ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift;
if (trigger != PYBTIMER_TIMEOUT_TRIGGER) {
goto invalid_args;
}
break;
case TIMER_CFG_A_PWM:
// special case for the PWM match interrupt
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
if (trigger != PYBTIMER_MATCH_TRIGGER) {
goto invalid_args;
}
break;
default:
break;
@@ -831,9 +720,6 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
// instance methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_timer_channel_freq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_period), (mp_obj_t)&pyb_timer_channel_period_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&pyb_timer_channel_time_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
};

View File

@@ -70,6 +70,7 @@
#define MICROPY_FATFS_REENTRANT (1)
#define MICROPY_FATFS_TIMEOUT (2500)
#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t
#define MICROPY_FSUSERMOUNT_ADHOC (1)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_MODULE_WEAK_LINKS (1)

View File

@@ -279,7 +279,7 @@ Q(CERT_REQUIRED)
// for network class
Q(network)
Q(server)
Q(Server)
Q(init)
Q(deinit)
Q(login)
@@ -365,18 +365,15 @@ Q(width)
Q(channel)
Q(polarity)
Q(duty_cycle)
Q(time)
Q(event_count)
Q(event_time)
Q(A)
Q(B)
Q(ONE_SHOT)
Q(PERIODIC)
Q(EDGE_COUNT)
Q(EDGE_TIME)
Q(PWM)
Q(POSITIVE)
Q(NEGATIVE)
Q(TIMEOUT)
Q(MATCH)
// for uhashlib module
//Q(uhashlib)

View File

@@ -39,7 +39,8 @@
#include "pybwdt.h"
#include "modusocket.h"
#include "mpexception.h"
#include "modnetwork.h"
#include "modwlan.h"
/******************************************************************************
DEFINE PRIVATE TYPES
@@ -50,13 +51,13 @@ typedef struct {
bool do_disable;
bool do_enable;
bool do_reset;
bool do_wlan_cycle_power;
} servers_data_t;
/******************************************************************************
DECLARE PRIVATE DATA
******************************************************************************/
static servers_data_t servers_data = {.timeout = SERVERS_DEF_TIMEOUT_MS, .enabled = false, .do_disable = false,
.do_enable = false, .do_reset = false};
static servers_data_t servers_data = {.timeout = SERVERS_DEF_TIMEOUT_MS};
static volatile bool sleep_sockets = false;
/******************************************************************************
@@ -120,10 +121,16 @@ void TASK_Servers (void *pvParameters) {
}
if (sleep_sockets) {
sleep_sockets = false;
pybwdt_srv_sleeping(true);
modusocket_enter_sleep();
pybwdt_srv_sleeping(false);
mp_hal_delay_ms(SERVERS_CYCLE_TIME_MS * 2);
if (servers_data.do_wlan_cycle_power) {
servers_data.do_wlan_cycle_power = false;
wlan_off_on();
}
sleep_sockets = false;
}
// set the alive flag for the wdt
@@ -152,6 +159,10 @@ void servers_reset (void) {
servers_data.do_reset = true;
}
void servers_wlan_cycle_power (void) {
servers_data.do_wlan_cycle_power = true;
}
bool servers_are_enabled (void) {
return servers_data.enabled;
}

View File

@@ -62,6 +62,7 @@ extern void TASK_Servers (void *pvParameters);
extern void servers_start (void);
extern void servers_stop (void);
extern void servers_reset (void);
extern void servers_wlan_cycle_power (void);
extern bool servers_are_enabled (void);
extern void servers_close_socket (int16_t *sd);
extern void servers_set_login (char *user, char *pass);

View File

@@ -27,6 +27,6 @@
#ifndef VERSION_H_
#define VERSION_H_
#define WIPY_SW_VERSION_NUMBER "1.1.1"
#define WIPY_SW_VERSION_NUMBER "1.2.0"
#endif /* VERSION_H_ */

View File

@@ -26,18 +26,29 @@ from collections import OrderedDict
micropy_port = os.getenv('MICROPY_PORT') or 'pyboard'
tags.add('port_' + micropy_port)
ports = OrderedDict((
("unix", "unix"),
("pyboard", "the pyboard"),
("wipy", "the WiPy"),
("esp8266", "esp8266"),
('unix', ('unix', 'unix')),
('pyboard', ('pyboard', 'the pyboard')),
('wipy', ('WiPy', 'the WiPy')),
('esp8266', ('ESP8266', 'the ESP8266')),
))
# The members of the html_context dict are available inside topindex.html
url_prefix = os.getenv('MICROPY_URL_PREFIX') or '/'
micropy_version = os.getenv('MICROPY_VERSION') or 'latest'
micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',')
url_pattern = '%s/en/%%s/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',)
html_context = {
'port':micropy_port,
'port_name':ports[micropy_port],
'all_ports':[(n, url_prefix + p) for p, n in ports.items()],
'port_short_name':ports[micropy_port][0],
'port_name':ports[micropy_port][1],
'port_version':micropy_version,
'all_ports':[
(port_name[0], url_pattern % (micropy_version, port_id))
for port_id, port_name in ports.items()
],
'all_versions':[
(ver, url_pattern % (ver, micropy_port))
for ver in micropy_all_versions
],
}
@@ -74,16 +85,16 @@ source_suffix = '.rst'
# General information about the project.
project = 'MicroPython'
copyright = '2014, Damien P. George'
copyright = '2014-2016, Damien P. George and contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.6'
version = '1.7'
# The full version, including alpha/beta/rc tags.
release = '1.6'
release = '1.7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@@ -306,5 +317,3 @@ exclude_patterns.extend([port + '*' for port in ports if port != micropy_port])
# Exclude pyb module if the port is the WiPy
if micropy_port == 'wipy':
exclude_patterns.append('library/pyb*')
else: # exclude machine
exclude_patterns.append('library/machine*')

254
docs/esp8266/quickref.rst Normal file
View File

@@ -0,0 +1,254 @@
.. _quickref:
Quick reference for the ESP8266
===============================
.. image:: https://learn.adafruit.com/system/assets/assets/000/028/689/medium640/adafruit_products_pinoutstop.jpg
:alt: Adafruit Feather HUZZAH board
:width: 640px
The Adafruit Feather HUZZAH board (image attribution: Adafruit).
General board control
---------------------
The MicroPython REPL is on UART0 (GPIO1=TX, GPIO3=RX) at baudrate 115200.
Tab-completion is useful to find out what methods an object has.
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
the REPL.
The ``machine`` module::
import machine
machine.freq() # get the current frequency of the CPU
machine.freq(160000000) # set the CPU frequency to 160 MHz
The ``esp`` module::
import esp
esp.osdebug(None) # turn off vendor O/S debugging messages
esp.osdebug(0) # redirect vendor O/S debugging messages to UART(0)
Networking
----------
The ``network`` module::
import network
wlan = network.WLAN(network.STA_IF) # create station interface
wlan.active(True) # activate the interface
wlan.scan() # scan for access points
wlan.isconnected() # check if the station is connected to an AP
wlan.connect('essid', 'password') # connect to an AP
wlan.mac() # get the interface's MAC adddress
wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses
ap = network.WLAN(network.AP_IF) # create access-point interface
ap.active(True) # activate the interface
ap.config(essid='ESP-AP') # set the ESSID of the access point
A useful function for connecting to your local WiFi network is::
def do_connect():
import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('connecting to network...')
wlan.connect('essid', 'password')
while not wlan.isconnected():
pass
print('network config:', wlan.ifconfig())
Once the network is established the ``socket`` module can be used
to create and use TCP/UDP sockets as usual.
Delay and timing
----------------
Use the ``time`` module::
import time
time.sleep(1) # sleep for 1 second
time.sleep_ms(500) # sleep for 500 milliseconds
time.sleep_us(10) # sleep for 10 microseconds
start = time.ticks_ms() # get millisecond counter
delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference
Timers
------
Virtual (RTOS-based) timers are supported. Use the ``machine.Timer`` class
with timer ID of -1::
from machine import Timer
tim = Timer(-1)
tim.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
The period is in milliseconds.
Pins and GPIO
-------------
Use the ``machine.Pin`` class::
from machine import Pin
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
p0.high() # set pin to high
p0.low() # set pin to low
p0.value(1) # set pin to high
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
print(p2.value()) # get value, 0 or 1
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
Available pins are: 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, which correspond
to the actual GPIO pin numbers of ESP8266 chip. Note that many end-user
boards use their own adhoc pin numbering (marked e.g. D0, D1, ...). As
MicroPython supports different boards and modules, physical pin numbering
was chosen as the lowest common denominator. For mapping between board
logical pins and physical chip pins, consult your board documentation.
Note that Pin(1) and Pin(3) are REPL UART TX and RX respectively.
Also note that Pin(16) is a special pin (used for wakeup from deepsleep
mode) and may be not available for use with higher-level classes like
``Neopixel``.
PWM (pulse width modulation)
----------------------------
PWM can be enabled on all pins except Pin(16). There is a single frequency
for all channels, with range between 1 and 1000 (measured in Hz). The duty
cycle is between 0 and 1023 inclusive.
Use the ``machine.PWM`` class::
from machine import Pin, PWM
pwm0 = PWM(Pin(0)) # create PWM object from a pin
pwm0.freq() # get current frequency
pwm0.freq(1000) # set frequency
pwm0.duty() # get current duty cycle
pwm0.duty(200) # set duty cycle
pwm0.deinit() # turn off PWM on the pin
pwm2 = PWM(Pin(2), freq=500, duty=512) # create and configure in one go
ADC (analog to digital conversion)
----------------------------------
ADC is available on a dedicated pin.
Note that input voltages on the ADC pin must be between 0v and 1.0v.
Use the ``machine.ADC`` class::
from machine import ADC
adc = ADC(0) # create ADC object on ADC pin
adc.read() # read value, 0-1024
SPI bus
-------
The SPI driver is implemented in software and works on all pins::
from machine import Pin, SPI
# construct an SPI bus on the given pins
# polarity is the idle state of SCK
# phase=0 means sample on the first edge of SCK, phase=1 means the second
spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
spi.init(baudrate=200000) # set the baudrate
spi.read(10) # read 10 bytes on MISO
spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI
buf = bytearray(50) # create a buffer
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI
spi.write(b'12345') # write 5 bytes on MOSI
buf = bytearray(4) # create a buffer
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
I2C bus
-------
The I2C driver is implemented in software and works on all pins::
from machine import Pin, I2C
# construct an I2C bus
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
i2c.readfrom(0x3a, 4) # read 4 bytes from slave device with address 0x3a
i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a
buf = bytearray(10) # create a buffer with 10 bytes
i2c.writeto(0x3a, buf) # write the given buffer to the slave
i2c.readfrom(0x3a, 4, stop=False) # don't send a stop bit after reading
i2c.writeto(0x3a, buf, stop=False) # don't send a stop bit after writing
OneWire driver
--------------
The OneWire driver is implemented in software and works on all pins::
from machine import Pin
import onewire
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
ow.scan() # return a list of devices on the bus
ow.reset() # reset the bus
ow.read_byte() # read a byte
ow.read_bytes(5) # read 5 bytes
ow.write_byte(0x12) # write a byte on the bus
ow.write_bytes('123') # write bytes on the bus
ow.select_rom(b'12345678') # select a specific device by its ROM code
There is a specific driver for DS18B20 devices::
import time
ds = onewire.DS18B20(ow)
roms = ds.scan()
ds.start_measure()
time.sleep_ms(750)
for rom in roms:
print(ds.get_temp(rom))
Be sure to put a 4.7k pull-up resistor on the data line.
NeoPixel driver
---------------
Use the ``neopixel`` module::
from machine import Pin
from neopixel import NeoPixel
pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
np[0] = (255, 255, 255) # set the first pixel to white
np.write() # write data to all pixels
r, g, b = np[0] # get first pixel colour
import neopixel
neopixel.demo(np) # run a demo
For low-level driving of a NeoPixel::
import esp
esp.neopixel_write(pin, grb_buf, is800khz)

View File

@@ -3,6 +3,7 @@ MicroPython documentation contents
.. toctree::
esp8266/quickref.rst
library/index.rst
reference/index.rst
license.rst

View File

@@ -3,6 +3,7 @@ MicroPython documentation and references
.. toctree::
esp8266/quickref.rst
library/index.rst
license.rst
esp8266_contents.rst

View File

@@ -10,46 +10,6 @@ The ``esp`` module contains specific functions related to the ESP8266 module.
Functions
---------
.. function:: mac([address])
Get or set the network interface's MAC address.
If the ``address`` parameter is provided, sets the address to its value. If
the function is called wihout parameters, returns the current address.
.. function:: getaddrinfo((hostname, port, lambda))
Initiate resolving of the given hostname.
When the hostname is resolved, the provided ``lambda`` callback will be
called with two arguments, first being the hostname being resolved,
second a tuple with information about that hostname.
.. function:: wifi_mode([mode])
Get or set the wireless network operating mode.
If the ``mode`` parameter is provided, sets the mode to its value. If
the function is called wihout parameters, returns the current mode.
The possible modes are defined as constants:
* ``STA_MODE`` -- station mode,
* ``AP_MODE`` -- software access point mode,
* ``STA_AP_MODE`` -- mixed station and software access point mode.
.. function:: phy_mode([mode])
Get or set the network interface mode.
If the ``mode`` parameter is provided, sets the mode to its value. If
the function is called wihout parameters, returns the current mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
.. function:: sleep_type([sleep_type])
Get or set the sleep type.
@@ -79,11 +39,3 @@ Functions
.. function:: flash_id()
Read the device ID of the flash memory.
Classes
-------
.. toctree::
:maxdepth: 1
esp.socket.rst

View File

@@ -55,6 +55,17 @@ For additional libraries, please download them from the `micropython-lib reposit
sys.rst
time.rst
.. only:: port_esp8266
.. toctree::
:maxdepth: 1
gc.rst
math.rst
struct.rst
sys.rst
time.rst
Python micro-libraries
----------------------
@@ -85,6 +96,19 @@ library.
usocket.rst
uzlib.rst
.. only:: port_esp8266
.. toctree::
:maxdepth: 1
ubinascii.rst
uctypes.rst
uhashlib.rst
uheapq.rst
ujson.rst
ure.rst
uzlib.rst
.. only:: port_pyboard
Libraries specific to the pyboard
@@ -134,6 +158,6 @@ library.
.. toctree::
:maxdepth: 2
pyb.rst
esp.rst
network.rst
esp.rst
machine.rst

View File

@@ -24,7 +24,7 @@ Usage Model:
print(pin.id())
pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN)
pin_int.irq(mode=Pin.IRQ_RISING, handler=pincb)
pin_int.irq(trigger=Pin.IRQ_RISING, handler=pincb)
# the callback can be triggered manually
pin_int.irq()()
# to disable the callback

View File

@@ -5,55 +5,49 @@ class Timer -- control internal timers
.. only:: port_wipy
.. note::
Contrary with the rest of the API, timer IDs start at 1, not a t zero. This is because
the ``Timer`` API is still provisional. A new MicroPython wide API will come soon.
Timers can be used for a great variety of tasks, calling a function periodically,
counting events, and generating a PWM signal are among the most common use cases.
Each timer consists of 2 16-bit channels and this channels can be tied together to
form 1 32-bit timer. The operating mode needs to be configured per timer, but then
Each timer consists of two 16-bit channels and this channels can be tied together to
form one 32-bit timer. The operating mode needs to be configured per timer, but then
the period (or the frequency) can be independently configured on each channel.
By using the callback method, the timer event can call a Python function.
Example usage to toggle an LED at a fixed frequency::
from machine import Timer
tim = Timer(4) # create a timer object using timer 4
from machine import Pin
led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED
tim = Timer(3) # create a timer object using timer 3
tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
tim_ch = tim.channel(Timer.A, freq=5) # configure channel A at a frequency of 5Hz
tim_ch.irq(handler=lambda t:led.toggle(), trigger=Timer.TIMEOUT) # toggle a LED on every cycle of the timer
Example using named function for the callback::
from machine import Timer
tim = Timer(1, mode=Timer.PERIODIC)
tim_a = tim.channel(Timer.A, freq=1000)
from machine import Pin
tim = Timer(1, mode=Timer.PERIODIC, width=32)
tim_a = tim.channel(Timer.A | Timer.B, freq=1) # 1 Hz frequency requires a 32 bit timer
led = Pin('GPIO2', mode=Pin.OUT)
led = Pin('GP16', mode=Pin.OUT) # enable GP16 as output to drive the LED
def tick(timer): # we will receive the timer object when being called
print(timer.time()) # show current timer's time value (is microseconds)
global led
led.toggle() # toggle the LED
tim_a.callback(handler=tick)
tim_a.irq(handler=tick, trigger=Timer.TIMEOUT) # create the interrupt
Further examples::
from machine import Timer
tim1 = Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
tim2 = Timer(1, mode=Timer.PWM) # initialize it in PWM mode
tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
tim_ch.time() # get the current time in usec (can also be set)
tim_ch.freq(20) # set the frequency (can also get)
tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
tim_ch.event_count() # get the number of captured events
tim_ch.event_time() # get the the time of the last captured event
tim_ch.period(2000000) # change the period to 2 seconds
tim1 = Timer(1, mode=Timer.ONE_SHOT) # initialize it in one shot mode
tim2 = Timer(2, mode=Timer.PWM) # initialize it in PWM mode
tim1_ch = tim1.channel(Timer.A, freq=10, polarity=Timer.POSITIVE) # start the event counter with a frequency of 10Hz and triggered by positive edges
tim2_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=5000) # start the PWM on channel B with a 50% duty cycle
tim2_ch.freq(20) # set the frequency (can also get)
tim2_ch.duty_cycle(3010) # set the duty cycle to 30.1% (can also get)
tim2_ch.duty_cycle(3020, Timer.NEGATIVE) # set the duty cycle to 30.2% and change the polarity to negative
tim2_ch.period(2000000) # change the period to 2 seconds
.. note::
@@ -69,9 +63,7 @@ Constructors
.. only:: port_wipy
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 4.
Construct a new timer object of the given id. ``id`` can take values from 0 to 3.
Methods
@@ -94,10 +86,9 @@ Methods
period of the channel expires.
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
frequency of the channel.
- ``Timer.EDGE_TIME`` - Meaure the time pin level changes.
- ``Timer.EDGE_COUNT`` - Count the number of pin level changes.
- ``Timer.PWM`` - Output a PWM signal on a pin.
- ``width`` must be either 16 or 32 (bits). For really low frequencies <= ~1Hz
- ``width`` must be either 16 or 32 (bits). For really low frequencies < 5Hz
(or large periods), 32-bit timers should be used. 32-bit mode is only available
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
@@ -112,7 +103,7 @@ Methods
If only a channel identifier passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Othwerwise, a TimerChannel object is initialized and returned.
The operating mode is is the one configured to the Timer object that was used to
@@ -130,12 +121,22 @@ Methods
Either ``freq`` or ``period`` must be given, never both.
- ``polarity`` this is applicable for:
- ``PWM``, defines the polarity of the duty cycle
- ``EDGE_TIME`` and ``EDGE_COUNT``, defines the polarity of the pin level change to detect.
To detect both rising and falling edges, make ``polarity=Timer.POSITIVE | Timer.NEGATIVE``.
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0-100)
- ``polarity`` this is applicable for ``PWM``, and defines the polarity of the duty cycle
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0.00-100.00). Since the WiPy
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
.. note::
When the channel is in PWM mode, the corresponding pin is assigned automatically, therefore
there's no need to assign the alternate function of the pin via the ``Pin`` class. The pins which
support PWM functionality are the following:
- ``GP24`` on Timer 0 channel A.
- ``GP25`` on Timer 1 channel A.
- ``GP9`` on Timer 2 channel B.
- ``GP10`` on Timer 3 channel A.
- ``GP11`` on Timer 3 channel B.
class TimerChannel --- setup a channel for a timer
==================================================
@@ -166,31 +167,49 @@ Methods
- ``priority`` level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- ``handler`` is an optional function to be called when the interrupt is triggered.
- ``trigger`` must be ``Timer.TIMEOUT`` when the operating mode is either ``Timer.PERIODIC`` or
``Timer.ONE_SHOT``. In the case that mode is ``Timer.PWM`` then trigger must be equal to
``Timer.MATCH``.
Returns a callback object.
.. only:: port_wipy
.. method:: timerchannel.freq([value])
Get or set the timer channel frequency (in Hz).
.. method:: timerchannel.period([value])
Get or set the timer channel period (in microseconds).
.. method:: timerchannel.time([value])
Get or set the timer channel current **time** value (in microseconds).
.. method:: timerchannel.event_count()
Get the number of edge events counted.
.. method:: timerchannel.event_time()
Get the time of ocurrance of the last event.
.. method:: timerchannel.duty_cycle([value])
Get or set the duty cycle of the PWM signal (in the range of 0-100).
Get or set the duty cycle of the PWM signal. It's a percentage (0.00-100.00). Since the WiPy
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
Constants
---------
.. data:: Timer.ONE_SHOT
.. data:: Timer.PERIODIC
.. data:: Timer.PWM
Selects the timer operating mode.
.. data:: Timer.A
.. data:: Timer.B
Selects the timer channel. Must be ORed (``Timer.A`` | ``Timer.B``) when
using a 32-bit timer.
.. data:: Timer.POSITIVE
.. data:: Timer.NEGATIVE
Timer channel polarity selection (only relevant in PWM mode).
.. data:: Timer.TIMEOUT
.. data:: Timer.MATCH
Timer channel IRQ triggers.

View File

@@ -11,7 +11,7 @@ Reset related functions
.. function:: reset()
Resets the WiPy in a manner similar to pushing the external RESET
Resets the device in a manner similar to pushing the external RESET
button.
.. function:: reset_cause()
@@ -87,7 +87,7 @@ Miscellaneous functions
.. function:: unique_id()
Returns a string of 6 bytes (48 bits), which is the unique ID of the MCU.
This also corresponds to the ``MAC address`` of the WiPy.
This also corresponds to the network ``MAC address``.
.. _machine_constants:

View File

@@ -30,27 +30,27 @@ For example::
.. only:: port_wipy
.. _network.server:
.. _network.Server:
class server
class Server
============
The server class controls the behaviour and the configuration of the FTP and telnet
The ``Server`` class controls the behaviour and the configuration of the FTP and telnet
services running on the WiPy. Any changes performed using this class' methods will
affect both.
Example::
import network
s = network.server()
s.deinit() # disable the server
server = network.Server()
server.deinit() # disable the server
# enable the server again with new settings
s.init(login=('user', 'password'), timeout=600)
server.init(login=('user', 'password'), timeout=600)
Constructors
------------
.. class:: network.server(id, ...)
.. class:: network.Server(id, ...)
Create a server instance, see ``init`` for parameters of initialization.
@@ -229,26 +229,52 @@ For example::
.. only:: port_esp8266
Functions
=========
.. function:: phy_mode([mode])
Get or set the PHY mode.
If the ``mode`` parameter is provided, sets the mode to its value. If
the function is called wihout parameters, returns the current mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
class WLAN
==========
This class provides a driver for WiFi network processor in the ESP8266. Example usage::
import network
# setup as a station
nic = network.WLAN()
# enable station interface and connect to WiFi access point
nic = network.WLAN(network.STA_IF)
nic.active(True)
nic.connect('your-ssid', 'your-password')
# now use socket as usual
# now use sockets as usual
Constructors
------------
.. class:: WLAN()
.. class:: WLAN(interface_id)
Create a WLAN driver object.
Create a WLAN network interface object. Supported interfaces are
``network.STA_IF`` (station aka client, connects to upstream WiFi access
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
connect). Availability of the methods below depends on interface type.
For example, only STA interface may ``connect()`` to an access point.
Methods
-------
.. method:: wlan.active([is_active])
Activate ("up") or deactivate ("down") network interface, if boolean
argument is passed. Otherwise, query current state if no argument is
provided. Most other methods require active interface.
.. method:: wlan.connect(ssid, password)
Connect to the specified wireless network, using the specified password.
@@ -257,16 +283,20 @@ For example::
Disconnect from the currently connected wireless network.
.. method:: wlan.scan(cb)
.. method:: wlan.mac([address])
Initiate scanning for the available wireless networks.
Get or set the network interface MAC address.
Scanning is only possible if the radio is in station or station+AP mode; if
called while in AP only mode, an OSError exception will be raised.
If the ``address`` parameter is provided, sets the address to its
value, which should be bytes object of length 6. If the function
is called wihout parameters, returns the current address.
Once the scanning is complete, the provided callback function ``cb`` will
be called once for each network found, and passed a tuple with information
about that network:
.. method:: wlan.scan()
Scan for the available wireless networks.
Scanning is only possible on STA interface. Returns list of tuples with
the information about WiFi access points:
(ssid, bssid, channel, RSSI, authmode, hidden)
@@ -283,7 +313,7 @@ For example::
* 0 -- visible
* 1 -- hidden
.. method:: status()
.. method:: wlan.status()
Return the current status of the wireless connection.

View File

@@ -4,12 +4,13 @@
.. module:: os
:synopsis: basic "operating system" services
The ``os`` module contains functions for filesystem access and ``urandom``.
The ``os`` module contains functions for filesystem access and ``urandom``
function.
Pyboard specifics
-----------------
Port specifics
--------------
The filesystem on the pyboard has ``/`` as the root directory and the
The filesystem has ``/`` as the root directory and the
available physical drives are accessible from here. They are currently:
``/flash`` -- the internal flash filesystem

View File

@@ -18,6 +18,7 @@ class ADC -- analog to digital conversion
val = adc.read_core_vbat() # read MCU VBAT
val = adc.read_core_vref() # read MCU VREF
Constructors
------------
@@ -77,6 +78,65 @@ Methods
The ADCAll Object
-----------------
Instantiating this changes all ADC pins to analog inputs. It is possible to read the
MCU temperature, VREF and VBAT without using ADCAll. The raw data can be accessed on
ADC channels 16, 17 and 18 respectively. However appropriate scaling will need to be applied.
.. only:: port_pyboard
Instantiating this changes all ADC pins to analog inputs. The raw MCU temperature,
VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively.
Appropriate scaling will need to be applied. The temperature sensor on the chip
has poor absolute accuracy and is suitable only for detecting temperature changes.
The ``ADCAll`` ``read_core_vbat()`` and ``read_core_vref()`` methods read
the backup battery voltage and the (1.21V nominal) reference voltage using the
3.3V supply as a reference. Assuming the ``ADCAll`` object has been Instantiated with
``adc = pyb.ADCAll(12)`` the 3.3V supply voltage may be calculated:
``v33 = 3.3 * 1.21 / adc.read_core_vref()``
If the 3.3V supply is correct the value of ``adc.read_core_vbat()`` will be
valid. If the supply voltage can drop below 3.3V, for example in in battery
powered systems with a discharging battery, the regulator will fail to preserve
the 3.3V supply resulting in an incorrect reading. To produce a value which will
remain valid under these circumstances use the following:
``vback = adc.read_core_vbat() * 1.21 / adc.read_core_vref()``
It is possible to access these values without incurring the side effects of ``ADCAll``::
def adcread(chan): # 16 temp 17 vbat 18 vref
assert chan >= 16 and chan <= 18, 'Invalid ADC channel'
start = pyb.millis()
timeout = 100
stm.mem32[stm.RCC + stm.RCC_APB2ENR] |= 0x100 # enable ADC1 clock.0x4100
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 # Turn on ADC
stm.mem32[stm.ADC1 + stm.ADC_CR1] = 0 # 12 bit
if chan == 17:
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x200000 # 15 cycles
stm.mem32[stm.ADC + 4] = 1 << 23
elif chan == 18:
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x1000000
stm.mem32[stm.ADC + 4] = 0xc00000
else:
stm.mem32[stm.ADC1 + stm.ADC_SMPR1] = 0x40000
stm.mem32[stm.ADC + 4] = 1 << 23
stm.mem32[stm.ADC1 + stm.ADC_SQR3] = chan
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 1 | (1 << 30) | (1 << 10) # start conversion
while not stm.mem32[stm.ADC1 + stm.ADC_SR] & 2: # wait for EOC
if pyb.elapsed_millis(start) > timeout:
raise OSError('ADC timout')
data = stm.mem32[stm.ADC1 + stm.ADC_DR] # clear down EOC
stm.mem32[stm.ADC1 + stm.ADC_CR2] = 0 # Turn off ADC
return data
def v33():
return 4096 * 1.21 / adcread(17)
def vbat():
return 1.21 * 2 * adcread(18) / adcread(17) # 2:1 divider on Vbat channel
def vref():
return 3.3 * adcread(17) / 4096
def temperature():
return 25 + 400 * (3.3 * adcread(16) / 4096 - 0.76)

View File

@@ -63,16 +63,24 @@ Constructors
.. class:: pyb.I2C(bus, ...)
Construct an I2C object on the given bus. ``bus`` can be 1 or 2.
With no additional parameters, the I2C object is created but not
Construct an I2C object on the given bus. ``bus`` can be 1 or 2, 'X' or
'Y'. With no additional parameters, the I2C object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the I2C busses are:
The physical pins of the I2C busses on Pyboards V1.0 and V1.1 are:
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
On the Pyboard Lite:
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
- ``I2C(3)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PA8, PB8)``
Calling the constructor with 'X' or 'Y' enables portability between Pyboard
types.
Methods
-------

View File

@@ -33,9 +33,9 @@ Constructors
.. class:: pyb.SPI(bus, ...)
Construct an SPI object on the given bus. ``bus`` can be 1 or 2.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
'X' or 'Y'. With no additional parameters, the SPI object is created but
not initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.

View File

@@ -103,7 +103,7 @@ Methods
.. method:: uart.any()
Return ``True`` if any characters waiting, else ``False``.
Returns the number of characters waiting (may be 0).
.. method:: uart.writechar(char)

View File

@@ -10,11 +10,25 @@ encodings of it in ASCII form (in both directions).
Functions
---------
.. function:: hexlify(data)
.. function:: hexlify(data, [sep])
Convert binary data to hexadecimal representation. Return bytes string.
.. admonition:: Difference to CPython
:class: attention
If additional argument, `sep` is supplied, it is used as a seperator
between hexadecimal values.
.. function:: unhexlify(data)
Convert hexadecimal data to binary representation. Return bytes string.
(i.e. inverse of hexlify)
.. function:: a2b_base64(data)
Convert Base64-encoded data to binary representation. Return bytes string.
.. function:: b2a_base64(data)
Encode binary data in Base64 format. Return string.

View File

@@ -6,7 +6,7 @@
This module implements "foreign data interface" for MicroPython. The idea
behind it is similar to CPython's ``ctypes`` modules, but actual API is
different, steamlined and optimized for small size.
different, streamlined and optimized for small size.
Defining structure layout
-------------------------

View File

@@ -64,8 +64,8 @@ This code uses a few new concepts:
Accepting arguments
-------------------
Inline assembler functions can accept up to 3 arguments. If they are
used, they must be named ``r0``, ``r1`` and ``r2`` to reflect the registers
Inline assembler functions can accept up to 4 arguments. If they are
used, they must be named ``r0``, ``r1``, ``r2`` and ``r3`` to reflect the registers
and the calling conventions.
Here is a function that adds its arguments::

View File

@@ -78,11 +78,23 @@ three arguments, which must (if used) be named ``r0``, ``r1`` and ``r2``. When
the code executes the registers will be initialised to those values.
The data types which can be passed in this way are integers and memory
addresses. With current firmware all possible 32 bit values may be passed.
Returned integers are restricted in that the top two bits must be identical,
limiting the range to -2**30 to 2**30 -1. The limitations on number of arguments
and return values can be overcome by means of the ``array`` module which enables
any number of values of any type to be accessed.
addresses. With current firmware all possible 32 bit values may be passed and
returned. If the return value may have the most significant bit set a Python
type hint should be employed to enable MicroPython to determine whether the
value should be interpreted as a signed or unsigned integer: types are
``int`` or ``uint``.
::
@micropython.asm_thumb
def uadd(r0, r1) -> uint:
add(r0, r0, r1)
``hex(uadd(0x40000000,0x40000000))`` will return 0x80000000, demonstrating the
passing and return of integers where bits 30 and 31 differ.
The limitations on the number of arguments and return values can be overcome by means
of the ``array`` module which enables any number of values of any type to be accessed.
Multiple arguments
~~~~~~~~~~~~~~~~~~

View File

@@ -14,6 +14,7 @@ MicroPython are described in the sections here.
repl.rst
isr_rules.rst
speed_python.rst
.. only:: port_pyboard

View File

@@ -0,0 +1,318 @@
Maximising Python Speed
=======================
This tutorial describes ways of improving the performance of MicroPython code.
Optimisations involving other languages are covered elsewhere, namely the use
of modules written in C and the MicroPython inline ARM Thumb-2 assembler.
The process of developing high performance code comprises the following stages
which should be performed in the order listed.
* Design for speed.
* Code and debug.
Optimisation steps:
* Identify the slowest section of code.
* Improve the efficiency of the Python code.
* Use the native code emitter.
* Use the viper code emitter.
Designing for speed
-------------------
Performance issues should be considered at the outset. This involves taking a view
on the sections of code which are most performance critical and devoting particular
attention to their design. The process of optimisation begins when the code has
been tested: if the design is correct at the outset optimisation will be
straightforward and may actually be unnecessary.
Algorithms
~~~~~~~~~~
The most important aspect of designing any routine for performance is ensuring that
the best algorithm is employed. This is a topic for textbooks rather than for a
MicroPython guide but spectacular performance gains can sometimes be achieved
by adopting algorithms known for their efficiency.
RAM Allocation
~~~~~~~~~~~~~~
To design efficient MicroPython code it is necessary to have an understanding of the
way the interpreter allocates RAM. When an object is created or grows in size
(for example where an item is appended to a list) the necessary RAM is allocated
from a block known as the heap. This takes a significant amount of time;
further it will on occasion trigger a process known as garbage collection which
can take several milliseconds.
Consequently the performance of a function or method can be improved if an object is created
once only and not permitted to grow in size. This implies that the object persists
for the duration of its use: typically it will be instantiated in a class constructor
and used in various methods.
This is covered in further detail :ref:`Controlling garbage collection <gc>` below.
Buffers
~~~~~~~
An example of the above is the common case where a buffer is required, such as one
used for communication with a device. A typical driver will create the buffer in the
constructor and use it in its I/O methods which will be called repeatedly.
The MicroPython libraries typically provide optional support for pre-allocated buffers.
For example the ``uart.readinto()`` method allows two options for its argument, an integer
or a buffer. If an integer is supplied it will read up to that number of bytes and
return the outcome: this implies that a buffer is created with a corresponding
memory allocation. Providing a pre-allocated buffer as the argument avoids this. See
the code fragment in :ref:`Caching object references <Caching>` below.
Floating Point
~~~~~~~~~~~~~~
For the most speed critical sections of code it is worth noting that performing
any kind of floating point operation involves heap allocation. Where possible use
integer operations and restrict the use of floating point to sections of the code
where performance is not paramount.
Arrays
~~~~~~
Consider the use of the various types of array classes as an alternative to lists.
The ``array`` module supports various element types with 8-bit elements supported
by Python's built in ``bytes`` and ``bytearray`` classes. These data structures all store
elements in contiguous memory locations. Once again to avoid memory allocation in critical
code these should be pre-allocated and passed as arguments or as bound objects.
When passing slices of objects such as ``bytearray`` instances, Python creates
a copy which involves allocation. This can be avoided using a ``memoryview``
object:
.. code:: python
ba = bytearray(100)
func(ba[3:10]) # a copy is passed
mv = memoryview(ba)
func(mv[3:10]) # a pointer to memory is passed
A ``memoryview`` can only be applied to objects supporting the buffer protocol - this
includes arrays but not lists.
Identifying the slowest section of code
---------------------------------------
This is a process known as profiling and is covered in textbooks and
(for standard Python) supported by various software tools. For the type of
smaller embedded application likely to be running on MicroPython platforms
the slowest function or method can usually be established by judicious use
of the timing ``ticks`` group of functions documented
`here <http://docs.micropython.org/en/latest/pyboard/library/time.html>`_.
Code execution time can be measured in ms, us, or CPU cycles.
The following enables any function or method to be timed by adding an
``@timed_function`` decorator:
.. code:: python
def timed_function(f, *args, **kwargs):
myname = str(f).split(' ')[1]
def new_func(*args, **kwargs):
t = time.ticks_us()
result = f(*args, **kwargs)
delta = time.ticks_diff(t, time.ticks_us())
print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000))
return result
return new_func
MicroPython code improvements
-----------------------------
The const() declaration
~~~~~~~~~~~~~~~~~~~~~~~
MicroPython provides a ``const()`` declaration. This works in a similar way
to ``#define`` in C in that when the code is compiled to bytecode the compiler
substitutes the numeric value for the identifier. This avoids a dictionary
lookup at runtime. The argument to ``const()`` may be anything which, at
compile time, evaluates to an integer e.g. ``0x100`` or ``1 << 8``.
.. _Caching:
Caching object references
~~~~~~~~~~~~~~~~~~~~~~~~~~
Where a function or method repeatedly accesses objects performance is improved
by caching the object in a local variable:
.. code:: python
class foo(object):
def __init__(self):
ba = bytearray(100)
def bar(self, obj_display):
ba_ref = self.ba
fb = obj_display.framebuffer
# iterative code using these two objects
This avoids the need repeatedly to look up ``self.ba`` and ``obj_display.framebuffer``
in the body of the method ``bar()``.
.. _gc:
Controlling garbage collection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When memory allocation is required, MicroPython attempts to locate an adequately
sized block on the heap. This may fail, usually because the heap is cluttered
with objects which are no longer referenced by code. If a failure occurs, the
process known as garbage collection reclaims the memory used by these redundant
objects and the allocation is then tried again - a process which can take several
milliseconds.
There are benefits in pre-empting this by periodically issuing ``gc.collect()``.
Firstly doing a collection before it is actually required is quicker - typically on the
order of 1ms if done frequently. Secondly you can determine the point in code
where this time is used rather than have a longer delay occur at random points,
possibly in a speed critical section. Finally performing collections regularly
can reduce fragmentation in the heap. Severe fragmentation can lead to
non-recoverable allocation failures.
Accessing hardware directly
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This comes into the category of more advanced programming and involves some knowledge
of the target MCU. Consider the example of toggling an output pin on the Pyboard. The
standard approach would be to write
.. code:: python
mypin.value(mypin.value() ^ 1) # mypin was instantiated as an output pin
This involves the overhead of two calls to the ``Pin`` instance's ``value()``
method. This overhead can be eliminated by performing a read/write to the relevant bit
of the chip's GPIO port output data register (odr). To facilitate this the ``stm``
module provides a set of constants providing the addresses of the relevant registers.
A fast toggle of pin ``P4`` (CPU pin ``A14``) - corresponding to the green LED -
can be performed as follows:
.. code:: python
BIT14 = const(1 << 14)
stm.mem16[stm.GPIOA + stm.GPIO_ODR] ^= BIT14
The Native code emitter
-----------------------
This causes the MicroPython compiler to emit ARM native opcodes rather than
bytecode. It covers the bulk of the Python language so most functions will require
no adaptation (but see below). It is invoked by means of a function decorator:
.. code:: python
@micropython.native
def foo(self, arg):
buf = self.linebuf # Cached object
# code
There are certain limitations in the current implementation of the native code emitter.
* Context managers are not supported (the ``with`` statement).
* Generators are not supported.
* If ``raise`` is used an argument must be supplied.
The trade-off for the improved performance (roughly twices as fast as bytecode) is an
increase in compiled code size.
The Viper code emitter
----------------------
The optimisations discussed above involve standards-compliant Python code. The
Viper code emitter is not fully compliant. It supports special Viper native data types
in pursuit of performance. Integer processing is non-compliant because it uses machine
words: arithmetic on 32 bit hardware is performed modulo 2**32.
Like the Native emitter Viper produces machine instructions but further optimisations
are performed, substantially increasing performance especially for integer arithmetic and
bit manipulations. It is invoked using a decorator:
.. code:: python
@micropython.viper
def foo(self, arg: int) -> int:
# code
As the above fragment illustrates it is beneficial to use Python type hints to assist the Viper optimiser.
Type hints provide information on the data types of arguments and of the return value; these
are a standard Python language feature formally defined here `PEP0484 <https://www.python.org/dev/peps/pep-0484/>`_.
Viper supports its own set of types namely ``int``, ``uint`` (unsigned integer), ``ptr``, ``ptr8``,
``ptr16`` and ``ptr32``. The ``ptrX`` types are discussed below. Currently the ``uint`` type serves
a single purpose: as a type hint for a function return value. If such a function returns ``0xffffffff``
Python will interpret the result as 2**32 -1 rather than as -1.
In addition to the restrictions imposed by the native emitter the following constraints apply:
* Functions may have up to four arguments.
* Default argument values are not permitted.
* Floating point may be used but is not optimised.
Viper provides pointer types to assist the optimiser. These comprise
* ``ptr`` Pointer to an object.
* ``ptr8`` Points to a byte.
* ``ptr16`` Points to a 16 bit half-word.
* ``ptr32`` Points to a 32 bit machine word.
The concept of a pointer may be unfamiliar to Python programmers. It has similarities
to a Python ``memoryview`` object in that it provides direct access to data stored in memory.
Items are accessed using subscript notation, but slices are not supported: a pointer can return
a single item only. Its purpose is to provide fast random access to data stored in contiguous
memory locations - such as data stored in objects which support the buffer protocol, and
memory-mapped peripheral registers in a microcontroller. It should be noted that programming
using pointers is hazardous: bounds checking is not performed and the compiler does nothing to
prevent buffer overrun errors.
Typical usage is to cache variables:
.. code:: python
@micropython.viper
def foo(self, arg: int) -> int:
buf = ptr8(self.linebuf) # self.linebuf is a bytearray or bytes object
for x in range(20, 30):
bar = buf[x] # Access a data item through the pointer
# code omitted
In this instance the compiler "knows" that ``buf`` is the address of an array of bytes;
it can emit code to rapidly compute the address of ``buf[x]`` at runtime. Where casts are
used to convert objects to Viper native types these should be performed at the start of
the function rather than in critical timing loops as the cast operation can take several
microseconds. The rules for casting are as follows:
* Casting operators are currently: ``int``, ``bool``, ``uint``, ``ptr``, ``ptr8``, ``ptr16`` and ``ptr32``.
* The result of a cast will be a native Viper variable.
* Arguments to a cast can be a Python object or a native Viper variable.
* If argument is a native Viper variable, then cast is a no-op (i.e. costs nothing at runtime)
that just changes the type (e.g. from ``uint`` to ``ptr8``) so that you can then store/load
using this pointer.
* If the argument is a Python object and the cast is ``int`` or ``uint``, then the Python object
must be of integral type and the value of that integral object is returned.
* The argument to a bool cast must be integral type (boolean or integer); when used as a return
type the viper function will return True or False objects.
* If the argument is a Python object and the cast is ``ptr``, ``ptr``, ``ptr16`` or ``ptr32``,
then the Python object must either have the buffer protocol with read-write capabilities
(in which case a pointer to the start of the buffer is returned) or it must be of integral
type (in which case the value of that integral object is returned).
The following example illustrates the use of a ``ptr16`` cast to toggle pin X1 ``n`` times:
.. code:: python
BIT0 = const(1)
@micropython.viper
def toggle_n(n: int):
odr = ptr16(stm.GPIOA + stm.GPIO_ODR)
for _ in range(n):
odr[0] ^= BIT0
A detailed technical description of the three code emitters may be found
on Kickstarter here `Note 1 <https://www.kickstarter.com/projects/214379695/micro-python-python-for-microcontrollers/posts/664832>`_
and here `Note 2 <https://www.kickstarter.com/projects/214379695/micro-python-python-for-microcontrollers/posts/665145>`_

39
docs/templates/versions.html vendored Normal file
View File

@@ -0,0 +1,39 @@
<div class="rst-versions" data-toggle="rst-versions" role="note" aria-label="versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span class="fa fa-book"> Ports and Versions</span>
{{ port_short_name }} ({{ port_version }})
<span class="fa fa-caret-down"></span>
</span>
<div class="rst-other-versions">
<dl>
<dt>Ports</dt>
{% for slug, url in all_ports %}
<dd><a href="{{ url }}">{{ slug }}</a></dd>
{% endfor %}
</dl>
<dl>
<dt>Versions</dt>
{% for slug, url in all_versions %}
<dd><a href="{{ url }}">{{ slug }}</a></dd>
{% endfor %}
</dl>
<!--
<dl>
<dt>Downloads</dt>
{% for type, url in downloads %}
<dd><a href="{{ url }}">{{ type }}</a></dd>
{% endfor %}
</dl>
-->
<hr/>
<dl>
<dt>External links</dt>
<dd>
<a href="http://www.micropython.org">micropython.org</a>
</dd>
<dd>
<a href="https://github.com/micropython/micropython">GitHub</a>
</dd>
</dl>
</div>
</div>

View File

@@ -41,10 +41,10 @@
{% endif %}
<p class="biglink">
<a class="biglink" href="{{ pathto("library/index") }}">Library Reference</a><br/>
{% if port == "wipy" %}
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/machine") }}">machine module</a></span>
{% else %}
{% if port == "pyboard" %}
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
{% else %}
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/machine") }}">machine module</a></span>
{% endif %}
</p>
</td>

View File

@@ -49,10 +49,10 @@ See :ref:`machine.Timer <machine.Timer>` and :ref:`machine.Pin <machine.Pin>`. :
from machine import Timer
from machine import Pin
tim = Timer(1, mode=Timer.PERIODIC)
tim = Timer(0, mode=Timer.PERIODIC)
tim_a = tim.channel(Timer.A, freq=1000)
tim_a.time() # get the value in microseconds
tim_a.freq(1) # 1 Hz
tim_a.freq(5) # 5 Hz
p_out = Pin('GP2', mode=Pin.OUT)
tim_a.irq(handler=lambda t: p_out.toggle())
@@ -63,16 +63,12 @@ PWM (pulse width modulation)
See :ref:`machine.Pin <machine.Pin>` and :ref:`machine.Timer <machine.Timer>`. ::
from machine import Timer
from machine import Pin
# assign GP25 to alternate function 9 (PWM)
p_out = Pin('GP25', mode=Pin.AF, alt=9)
# timer 2 in PWM mode and width must be 16 buts
tim = Timer(2, mode=Timer.PWM, width=16)
# timer 1 in PWM mode and width must be 16 buts
tim = Timer(1, mode=Timer.PWM, width=16)
# enable channel A @1KHz with a 50% duty cycle
tim_a = tim.channel(Timer.A, freq=1000, duty_cycle=50)
# enable channel A @1KHz with a 50.55% duty cycle
tim_a = tim.channel(Timer.A, freq=1000, duty_cycle=5055)
ADC (analog to digital conversion)
----------------------------------
@@ -201,12 +197,12 @@ See :ref:`network.WLAN <network.WLAN>` and :mod:`machine`. ::
Telnet and FTP server
---------------------
See :ref:`network.server <network.server>` ::
See :ref:`network.Server <network.Server>` ::
from network import server
from network import Server
# init with new user, password and seconds timeout
server = server.init(login=('user', 'password'), timeout=60)
server = Server(login=('user', 'password'), timeout=60)
server.timeout(300) # change the timeout
server.timeout() # get the timeout
server.isrunning() # check wether the server is running or not

View File

@@ -25,6 +25,9 @@ class SDCard:
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
#R1_ADDRESS_ERROR = const(1 << 5)
#R1_PARAMETER_ERROR = const(1 << 6)
TOKEN_CMD25 = const(0xfc)
TOKEN_STOP_TRAN = const(0xfd)
TOKEN_DATA = const(0xfe)
def __init__(self, spi, cs):
self.spi = spi
@@ -136,6 +139,18 @@ class SDCard:
self.spi.send(0xff)
return -1
def cmd_nodata(self, cmd):
self.spi.send(cmd)
self.spi.send_recv(0xff) # ignore stuff byte
for _ in range(CMD_TIMEOUT):
if self.spi.send_recv(0xff)[0] == 0xff:
self.cs.high()
self.spi.send(0xff)
return 0 # OK
self.cs.high()
self.spi.send(0xff)
return 1 # timeout
def readinto(self, buf):
self.cs.low()
@@ -154,11 +169,11 @@ class SDCard:
self.cs.high()
self.spi.send(0xff)
def write(self, buf):
def write(self, token, buf):
self.cs.low()
# send: start of block, data, checksum
self.spi.send(0xfe)
self.spi.send(token)
self.spi.send(buf)
self.spi.send(0xff)
self.spi.send(0xff)
@@ -176,29 +191,62 @@ class SDCard:
self.cs.high()
self.spi.send(0xff)
def write_token(self, token):
self.cs.low()
self.spi.send(token)
self.spi.send(0xff)
# wait for write to finish
while self.spi.send_recv(0xff)[0] == 0:
pass
self.cs.high()
self.spi.send(0xff)
def count(self):
return self.sectors
def readblocks(self, block_num, buf):
# TODO support multiple block reads
assert len(buf) == 512
# CMD17: set read address for single block
if self.cmd(17, block_num * self.cdv, 0) != 0:
return 1
# receive the data
self.readinto(buf)
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, 'Buffer length is invalid'
if nblocks == 1:
# CMD17: set read address for single block
if self.cmd(17, block_num * self.cdv, 0) != 0:
return 1
# receive the data
self.readinto(buf)
else:
# CMD18: set read address for multiple blocks
if self.cmd(18, block_num * self.cdv, 0) != 0:
return 1
offset = 0
mv = memoryview(buf)
while nblocks:
self.readinto(mv[offset : offset + 512])
offset += 512
nblocks -= 1
return self.cmd_nodata(12)
return 0
def writeblocks(self, block_num, buf):
# TODO support multiple block writes
assert len(buf) == 512
nblocks, err = divmod(len(buf), 512)
assert nblocks and not err, 'Buffer length is invalid'
if nblocks == 1:
# CMD24: set write address for single block
if self.cmd(24, block_num * self.cdv, 0) != 0:
return 1
# CMD24: set write address for single block
if self.cmd(24, block_num * self.cdv, 0) != 0:
return 1
# send the data
self.write(buf)
# send the data
self.write(TOKEN_DATA, buf)
else:
# CMD25: set write address for first block
if self.cmd(25, block_num * self.cdv, 0) != 0:
return 1
# send the data
offset = 0
mv = memoryview(buf)
while nblocks:
self.write(TOKEN_CMD25, mv[offset : offset + 512])
offset += 512
nblocks -= 1
self.write_token(TOKEN_STOP_TRAN)
return 0

57
drivers/sdcard/sdtest.py Normal file
View File

@@ -0,0 +1,57 @@
# Test for sdcard block protocol
# Peter hinch 30th Jan 2016
import os, sdcard, pyb
def sdtest():
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X21) # Compatible with PCB
pyb.mount(sd, '/fc')
print('Filesystem check')
print(os.listdir('/fc'))
line = 'abcdefghijklmnopqrstuvwxyz\n'
lines = line * 200 # 5400 chars
short = '1234567890\n'
fn = '/fc/rats.txt'
print()
print('Multiple block read/write')
with open(fn,'w') as f:
n = f.write(lines)
print(n, 'bytes written')
n = f.write(short)
print(n, 'bytes written')
n = f.write(lines)
print(n, 'bytes written')
with open(fn,'r') as f:
result1 = f.read()
print(len(result1), 'bytes read')
fn = '/fc/rats1.txt'
print()
print('Single block read/write')
with open(fn,'w') as f:
n = f.write(short) # one block
print(n, 'bytes written')
with open(fn,'r') as f:
result2 = f.read()
print(len(result2), 'bytes read')
pyb.mount(None, '/fc')
print()
print('Verifying data read back')
success = True
if result1 == ''.join((lines, short, lines)):
print('Large file Pass')
else:
print('Large file Fail')
success = False
if result2 == short:
print('Small file Pass')
else:
print('Small file Fail')
success = False
print()
print('Tests', 'passed' if success else 'failed')

View File

@@ -9,8 +9,8 @@ include ../py/py.mk
MAKE_FROZEN = ../tools/make-frozen.py
SCRIPTDIR = scripts
PORT = /dev/ttyACM0
BAUD = 115200
PORT ?= /dev/ttyACM0
BAUD ?= 115200
CROSS_COMPILE = xtensa-lx106-elf-
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
@@ -23,18 +23,21 @@ INC += -I../lib/timeutils
INC += -I$(BUILD)
INC += -I$(ESP_SDK)/include
UART_OS = 1
# UART for "os" messages. 0 is normal UART as used by MicroPython REPL,
# 1 is debug UART (tx only).
UART_OS = 0
CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \
-D__ets__ -DICACHE_FLASH \
-fno-inline-functions \
-Wl,-EL -mlongcalls -mtext-section-literals \
-DLWIP_OPEN_SRC
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \
$(CFLAGS_XTENSA) $(COPT) $(CFLAGS_EXTRA)
LDFLAGS = -nostdlib -T esp8266.ld -Map=$(@:.elf=.map) --cref
LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip -lpp -lnet80211 -lwpa -lphy -lnet80211
LIBS = -L$(ESP_SDK)/lib -lmain -ljson -lssl -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
@@ -45,7 +48,7 @@ CFLAGS += -g
COPT = -O0
else
CFLAGS += -fdata-sections -ffunction-sections
COPT += -Os -DNDEBUG
COPT += -Os -mforce-l32 -DNDEBUG
LDFLAGS += --gc-sections
endif
@@ -54,29 +57,64 @@ SRC_C = \
main.c \
esp_mphal.c \
gccollect.c \
lexerstr32.c \
uart.c \
esppwm.c \
espneopixel.c \
modpyb.c \
modpybpin.c \
modpybpwm.c \
modpybrtc.c \
modpybadc.c \
modpybuart.c \
modpybi2c.c \
modpybspi.c \
modesp.c \
modnetwork.c \
modutime.c \
moduos.c \
modmachine.c \
modonewire.c \
utils.c \
ets_alt_task.c \
$(BUILD)/frozen.c \
fatfs_port.o \
STM_SRC_C = $(addprefix stmhal/,\
pybstdio.c \
)
EXTMOD_SRC_C = $(addprefix extmod/,\
modlwip.o \
)
LIB_SRC_C = $(addprefix lib/,\
libc/string0.c \
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/printf.c \
fatfs/ff.c \
fatfs/option/ccsbcs.c \
)
SRC_S = \
@@ -87,6 +125,7 @@ OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
#OBJ += $(BUILD)/pins_$(BOARD).o
@@ -111,8 +150,8 @@ $(BUILD)/frozen.c: $(wildcard $(SCRIPTDIR)/*) $(CONFVARS_FILE)
deploy: $(BUILD)/firmware-combined.bin
$(ECHO) "Writing $< to the board"
#$(Q)esptool.py --port $(PORT) write_flash 0 $<
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash 0 $(BUILD)/firmware.elf-0x00000.bin 0x10000 $(BUILD)/firmware.elf-0x10000.bin
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $<
#$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $(BUILD)/firmware.elf-0x00000.bin 0x9000 $(BUILD)/firmware.elf-0x0[1-f]000.bin
reset:
echo -e "\r\nimport pyb; pyb.hard_reset()\r\n" >$(PORT)
@@ -120,7 +159,7 @@ reset:
$(BUILD)/firmware-combined.bin: $(BUILD)/firmware.elf
$(ECHO) "Create $@"
$(Q)esptool.py elf2image $^
$(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x10000.bin $@
$(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x0[1-f]000.bin $@
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"

View File

@@ -8,49 +8,81 @@ WARNING: The port is highly experimental and any APIs are subject to change.
Currently implemented features include:
- REPL (Python prompt) over UART0.
- 24k heap RAM available for Python code.
- Garbage collector, exceptions.
- Unicode support.
- Builtin modules: gc, array, collections, io, struct, sys, esp, network.
- C long-long type used as bignum implementation (gives 64 bit signed ints).
- Rudimentary WiFi support in station mode.
- Sockets with callbacks.
- Basic GPIO support.
Note that floating-point numbers are not supported.
- Builtin modules: gc, array, collections, io, struct, sys, esp, network,
many more.
- Arbitrary-precision long integers and 30-bit precision floats.
- Basic WiFi support.
- Sockets using modlwip.
- GPIO and bit-banging I2C, SPI support.
- 1-Wire and WS2812 (aka Neopixel) protocols support.
On the TODO list:
- Full wifi support.
- Internal filesystem using the flash.
- ...
Work-in-progress documentation is available at
http://docs.micropython.org/en/latest/esp8266/ .
Build instructions
------------------
The tool chain required for the build is the OpenSource ESP SDK, which can be
found at <https://github.com/pfalcon/esp-open-sdk>. Clone this repository and
run `make` in its directory to build and install the SDK locally.
run `make` in its directory to build and install the SDK locally. Make sure
to add toolchain bin directory to your PATH. Read esp-open-sdk's README for
additional important information on toolchain setup.
Add the external dependencies to the MicroPython repository checkout:
```bash
$ git submodule update --init
```
See the README in the repository root for more information about external
dependencies.
Then, to build MicroPython for the ESP8266, just run:
```bash
$ cd esp8266
$ make
```
This should produce binary images in the `build/` subdirectory. To flash them
to your ESP8266, use:
This will produce binary images in the `build/` subdirectory. If you install
MicroPython to your module for the first time, or after installing any other
firmware, you should erase flash completely:
```
esptool.py --port /dev//ttyXXX erase_flash
```
Erase flash also as a troubleshooting measure, if a module doesn't behave as
expected.
To flash MicroPython image to your ESP8266, use:
```bash
$ make deploy
```
This will use the `esptool.py` script to download the images. You must have
your ESP module in the bootloader, and connected to a serial port on your PC.
your ESP module in the bootloader mode, and connected to a serial port on your PC.
The default serial port is `/dev/ttyACM0`. To specify another, use, eg:
```bash
$ make PORT=/dev/ttyUSB0 deploy
```
The images that are built are:
- `firmware.elf-0x00000.bin`: to be flashed at 0x00000
- `firmware.elf-0x10000.bin`: to be flashed at 0x10000
The image produced is `firmware-combined.bin`, to be flashed at 0x00000.
There is also a combined image, made up of the above 2 binary files with the
appropriate padding:
- `firmware-combined.bin`: to be flashed at 0x00000
Troubleshooting
---------------
While the port is still in alpha, it's known to be generally stable. If you
experience strange bootloops, crashes, lockups, here's a list to check against:
- You didn't erase flash before programming MicroPython firmware.
- Firmware can be occasionally flashed incorrectly. Just retry. Recent
esptool.py versions have --verify option.
- Power supply you use doesn't provide enough power for ESP8266 or isn't
stable enough.
- A module/flash may be defective (not unheard of for cheap modules).
Please consult dedicated ESP8266 forums/resources for hardware-related
problems.

View File

@@ -132,12 +132,12 @@ PROVIDE ( ets_memcmp = 0x400018d4 );
PROVIDE ( ets_memcpy = 0x400018b4 );
PROVIDE ( ets_memmove = 0x400018c4 );
PROVIDE ( ets_memset = 0x400018a4 );
PROVIDE ( ets_post = 0x40000e24 );
PROVIDE ( _ets_post = 0x40000e24 );
PROVIDE ( ets_printf = 0x400024cc );
PROVIDE ( ets_putc = 0x40002be8 );
PROVIDE ( ets_rtc_int_register = 0x40002a40 );
PROVIDE ( ets_run = 0x40000e04 );
PROVIDE ( ets_set_idle_cb = 0x40000dc0 );
PROVIDE ( _ets_run = 0x40000e04 );
PROVIDE ( _ets_set_idle_cb = 0x40000dc0 );
PROVIDE ( ets_set_user_start = 0x40000fbc );
PROVIDE ( ets_str2macaddr = 0x40002af8 );
PROVIDE ( ets_strcmp = 0x40002aa8 );
@@ -146,12 +146,12 @@ PROVIDE ( ets_strlen = 0x40002ac8 );
PROVIDE ( ets_strncmp = 0x40002ab8 );
PROVIDE ( ets_strncpy = 0x40002a98 );
PROVIDE ( ets_strstr = 0x40002ad8 );
PROVIDE ( ets_task = 0x40000dd0 );
PROVIDE ( _ets_task = 0x40000dd0 );
PROVIDE ( ets_timer_arm = 0x40002cc4 );
PROVIDE ( ets_timer_disarm = 0x40002d40 );
PROVIDE ( ets_timer_done = 0x40002d80 );
PROVIDE ( ets_timer_handler_isr = 0x40002da8 );
PROVIDE ( ets_timer_init = 0x40002e68 );
PROVIDE ( _ets_timer_init = 0x40002e68 );
PROVIDE ( ets_timer_setfn = 0x40002c48 );
PROVIDE ( ets_uart_printf = 0x40002544 );
PROVIDE ( ets_update_cpu_frequency = 0x40002f04 );
@@ -343,5 +343,8 @@ PROVIDE ( xthal_window_spill = 0x4000e324 );
PROVIDE ( xthal_window_spill_nw = 0x4000e320 );
PROVIDE ( Te0 = 0x3fffccf0 );
PROVIDE ( Td0 = 0x3fffd100 );
PROVIDE ( Td4s = 0x3fffd500);
PROVIDE ( rcons = 0x3fffd0f0);
PROVIDE ( UartDev = 0x3fffde10 );
PROVIDE ( flashchip = 0x3fffc714);

View File

@@ -5,7 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3ff00000, len = 0x10
dram0_0_seg : org = 0x3ffe8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40210000, len = 0x5A000
irom0_0_seg : org = 0x40209000, len = 0x80000
}
/* define the top of RAM */
@@ -80,26 +80,84 @@ SECTIONS
*(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
/* we put some specific text in this section */
*py/*.o*(.literal* .text*)
*pyexec.o(.literal*, .text*)
*readline.o(.literal*, .text*)
*pybstdio.o(.literal*, .text*)
*py/argcheck.o*(.literal* .text*)
*py/asm*.o*(.literal* .text*)
*py/bc.o*(.literal* .text*)
*py/binary.o*(.literal* .text*)
*py/builtin*.o*(.literal* .text*)
*py/compile.o*(.literal* .text*)
*py/emit*.o*(.literal* .text*)
*py/formatfloat.o*(.literal* .text*)
*py/frozenmod.o*(.literal* .text*)
*py/gc.o*(.literal* .text*)
*py/lexer*.o*(.literal* .text*)
*py/malloc*.o*(.literal* .text*)
*py/map*.o*(.literal* .text*)
*py/mod*.o*(.literal* .text*)
*py/mpprint.o*(.literal* .text*)
*py/mpstate.o*(.literal* .text*)
*py/mpz.o*(.literal* .text*)
*py/native*.o*(.literal* .text*)
*py/nlr*.o*(.literal* .text*)
*py/obj*.o*(.literal* .text*)
*py/opmethods.o*(.literal* .text*)
*py/parse*.o*(.literal* .text*)
*py/qstr.o*(.literal* .text*)
*py/repl.o*(.literal* .text*)
*py/runtime.o*(.literal* .text*)
*py/scope.o*(.literal* .text*)
*py/sequence.o*(.literal* .text*)
*py/showbc.o*(.literal* .text*)
*py/smallint.o*(.literal* .text*)
*py/stackctrl.o*(.literal* .text*)
*py/stream.o*(.literal* .text*)
*py/unicode.o*(.literal* .text*)
*py/vm.o*(.literal* .text*)
*py/vstr.o*(.literal* .text*)
*py/warning.o*(.literal* .text*)
*extmod/*.o*(.literal* .text*)
*lib/fatfs/*.o*(.literal*, .text*)
*lib/libm/*.o*(.literal*, .text*)
*lib/mp-readline/*.o(.literal*, .text*)
*lib/netutils/*.o*(.literal*, .text*)
*lib/timeutils/*.o*(.literal*, .text*)
*lib/utils/*.o*(.literal*, .text*)
*stmhal/pybstdio.o(.literal*, .text*)
*gccollect.o(.literal* .text*)
*gchelper.o(.literal* .text*)
*lexerstr32.o(.literal* .text*)
*utils.o(.literal* .text*)
*modpyb.o(.literal*, .text*)
*modpybpin.o(.literal*, .text*)
*modpybpwm.o(.literal*, .text*)
*modpybrtc.o(.literal*, .text*)
*modpybadc.o(.literal*, .text*)
*modpybuart.o(.literal*, .text*)
*modpybi2c.o(.literal*, .text*)
*modpybspi.o(.literal*, .text*)
*modesp.o(.literal* .text*)
*modnetwork.o(.literal* .text*)
*moduos.o(.literal* .text*)
*modutime.o(.literal* .text*)
*modlwip.o(.literal* .text*)
*modsocket.o(.literal* .text*)
/* we put as much rodata as possible in this section */
/* note that only rodata accessed as a machine word is allowed here */
*py/qstr.o(.rodata.const_pool)
*py/*.o(.rodata.mp_type_*) /* catches type: mp_obj_type_t */
*py/*.o(.rodata.*_locals_dict*) /* catches types: mp_obj_dict_t, mp_map_elem_t */
*py/*.o(.rodata.mp_module_*) /* catches types: mp_obj_module_t, mp_obj_dict_t, mp_map_elem_t */
*.o(.rodata.mp_type_*) /* catches type: mp_obj_type_t */
*.o(.rodata.*_locals_dict*) /* catches types: mp_obj_dict_t, mp_map_elem_t */
*.o(.rodata.mp_module_*) /* catches types: mp_obj_module_t, mp_obj_dict_t, mp_map_elem_t */
*/frozen.o(.rodata.mp_frozen_sizes) /* frozen modules */
*/frozen.o(.rodata.mp_frozen_content) /* frozen modules */
/* for -mforce-l32 */
build/*.o(.rodata*)
_irom0_text_end = ABSOLUTE(.);
} >irom0_0_seg :irom0_0_phdr
@@ -172,6 +230,7 @@ SECTIONS
.rodata : ALIGN(4)
{
_rodata_start = ABSOLUTE(.);
*(.sdk.version)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)

View File

@@ -30,13 +30,24 @@
#include "uart.h"
#include "esp_mphal.h"
#include "user_interface.h"
#include "ets_alt_task.h"
#include "py/obj.h"
#include "py/mpstate.h"
#include "extmod/misc.h"
#include "lib/utils/pyexec.h"
extern void ets_wdt_disable(void);
extern void wdt_feed(void);
extern void ets_delay_us();
STATIC byte input_buf_array[256];
ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
void mp_hal_init(void) {
ets_wdt_disable(); // it's a pain while developing
mp_hal_rtc_init();
uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200);
}
@@ -47,12 +58,15 @@ void mp_hal_feed_watchdog(void) {
}
void mp_hal_delay_us(uint32_t us) {
ets_delay_us(us);
uint32_t start = system_get_time();
while (system_get_time() - start < us) {
ets_event_poll();
}
}
int mp_hal_stdin_rx_chr(void) {
for (;;) {
int c = uart0_rx();
int c = ringbuf_get(&input_buf);
if (c != -1) {
return c;
}
@@ -61,19 +75,43 @@ int mp_hal_stdin_rx_chr(void) {
}
}
void mp_hal_stdout_tx_str(const char *str) {
void mp_hal_stdout_tx_char(char c) {
uart_tx_one_char(UART0, c);
mp_uos_dupterm_tx_strn(&c, 1);
}
#if 0
void mp_hal_debug_str(const char *str) {
while (*str) {
uart_tx_one_char(UART0, *str++);
}
uart_flush(UART0);
}
#endif
void mp_hal_stdout_tx_str(const char *str) {
while (*str) {
mp_hal_stdout_tx_char(*str++);
}
}
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
while (len--) {
uart_tx_one_char(UART0, *str++);
mp_hal_stdout_tx_char(*str++);
}
}
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
while (len--) {
if (*str == '\n') {
mp_hal_stdout_tx_char('\r');
}
mp_hal_stdout_tx_char(*str++);
}
}
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
(void)env;
while (len--) {
if (*str == '\n') {
uart_tx_one_char(UART0, '\r');
@@ -86,10 +124,95 @@ uint32_t mp_hal_ticks_ms(void) {
return system_get_time() / 1000;
}
uint32_t mp_hal_ticks_us(void) {
return system_get_time();
}
void mp_hal_delay_ms(uint32_t delay) {
mp_hal_delay_us(delay * 1000);
}
void mp_hal_set_interrupt_char(int c) {
// TODO
if (c != -1) {
mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_kbd_exception));
}
extern int interrupt_char;
interrupt_char = c;
}
void ets_event_poll(void) {
ets_loop_iter();
if (MP_STATE_VM(mp_pending_exception) != NULL) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
}
}
void __assert_func(const char *file, int line, const char *func, const char *expr) {
printf("assert:%s:%d:%s: %s\n", file, line, func, expr);
nlr_raise(mp_obj_new_exception_msg(&mp_type_AssertionError,
"C-level assert"));
}
void mp_hal_signal_input(void) {
#if MICROPY_REPL_EVENT_DRIVEN
system_os_post(UART_TASK_ID, 0, 0);
#endif
}
static int call_dupterm_read(void) {
if (MP_STATE_PORT(term_obj) == NULL) {
return -1;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t read_m[3];
mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_read, read_m);
read_m[2] = MP_OBJ_NEW_SMALL_INT(1);
mp_obj_t res = mp_call_method_n_kw(1, 0, read_m);
if (res == mp_const_none) {
return -2;
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len == 0) {
mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n");
MP_STATE_PORT(term_obj) = NULL;
return -1;
}
nlr_pop();
return *(byte*)bufinfo.buf;
} else {
// Temporarily disable dupterm to avoid infinite recursion
mp_obj_t save_term = MP_STATE_PORT(term_obj);
MP_STATE_PORT(term_obj) = NULL;
mp_printf(&mp_plat_print, "dupterm: ");
mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
MP_STATE_PORT(term_obj) = save_term;
}
return -1;
}
STATIC void dupterm_task_handler(os_event_t *evt) {
while (1) {
int c = call_dupterm_read();
if (c < 0) {
break;
}
ringbuf_put(&input_buf, c);
}
mp_hal_signal_input();
}
STATIC os_event_t dupterm_evt_queue[4];
void dupterm_task_init() {
system_os_task(dupterm_task_handler, DUPTERM_TASK_ID, dupterm_evt_queue, MP_ARRAY_SIZE(dupterm_evt_queue));
}
void mp_hal_signal_dupterm_input(void) {
system_os_post(DUPTERM_TASK_ID, 0, 0);
}

View File

@@ -27,18 +27,33 @@
#ifndef _INCLUDED_MPHAL_H_
#define _INCLUDED_MPHAL_H_
// SDK functions not declared in SDK itself
void ets_isr_mask(unsigned);
#include "py/ringbuf.h"
struct _mp_print_t;
// Structure for UART-only output via mp_printf()
extern const struct _mp_print_t mp_debug_print;
extern ringbuf_t input_buf;
// Call this after putting data to input_buf
void mp_hal_signal_input(void);
// Call this when data is available in dupterm object
void mp_hal_signal_dupterm_input(void);
void mp_hal_init(void);
void mp_hal_rtc_init(void);
void mp_hal_feed_watchdog(void);
uint32_t mp_hal_ticks_us(void);
void mp_hal_delay_us(uint32_t);
void mp_hal_set_interrupt_char(int c);
uint32_t mp_hal_get_cpu_freq(void);
#define UART_TASK_ID 0
#define DUPTERM_TASK_ID 1
void uart_task_init();
void dupterm_task_init();
void ets_event_poll(void);
#define ETS_POLL_WHILE(cond) { while (cond) ets_event_poll(); }
#endif // _INCLUDED_MPHAL_H_

64
esp8266/espneopixel.c Normal file
View File

@@ -0,0 +1,64 @@
// 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 "c_types.h"
#include "eagle_soc.h"
#include "user_interface.h"
#include "espneopixel.h"
#define NEO_KHZ400 (1)
static uint32_t _getCycleCount(void) __attribute__((always_inline));
static inline uint32_t _getCycleCount(void) {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}
void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
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 = system_get_cpu_freq() * 1000000;
#ifdef NEO_KHZ400
if(is800KHz) {
#endif
time0 = fcpu / 2500000; // 0.4us
time1 = fcpu / 1250000; // 0.8us
period = fcpu / 800000; // 1.25us per bit
#ifdef NEO_KHZ400
} else { // 400 KHz bitstream
time0 = fcpu / 2000000; // 0.5uS
time1 = fcpu / 833333; // 1.2us
period = fcpu / 400000; // 2.5us per bit
}
#endif
for(t = time0;; t = time0) {
if(pix & mask) t = time1; // Bit high duration
while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
startTime = c; // Save start time
while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if(!(mask >>= 1)) { // Next bit/byte
if(p >= end) break;
pix = *p++;
mask = 0x80;
}
}
while((_getCycleCount() - startTime) < period); // Wait for last bit
}

1
esp8266/espneopixel.h Normal file
View File

@@ -0,0 +1 @@
void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);

428
esp8266/esppwm.c Normal file
View File

@@ -0,0 +1,428 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: pwm.c
*
* Description: pwm driver
*
* Modification history:
* 2014/5/1, v1.0 create this file.
* 2016/3/2: Modifications by dpgeorge to suit MicroPython
*******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "etshal.h"
#include "os_type.h"
#include "gpio.h"
#include "esppwm.h"
#include "py/mpprint.h"
#define PWM_DBG(...)
//#define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__)
#define ICACHE_RAM_ATTR // __attribute__((section(".text")))
#define PWM_CHANNEL 8
#define PWM_DEPTH 1023
#define PWM_FREQ_MAX 1000
#define PWM_1S 1000000
struct pwm_single_param {
uint16_t gpio_set;
uint16_t gpio_clear;
uint32_t h_time;
};
struct pwm_param {
uint32_t period;
uint16_t freq;
uint16_t duty[PWM_CHANNEL];
};
STATIC const uint8_t pin_num[PWM_CHANNEL] = {0, 2, 4, 5, 12, 13, 14, 15};
STATIC struct pwm_single_param pwm_single_toggle[2][PWM_CHANNEL + 1];
STATIC struct pwm_single_param *pwm_single;
STATIC struct pwm_param pwm;
STATIC int8_t pwm_out_io_num[PWM_CHANNEL] = {-1, -1, -1, -1, -1, -1, -1, -1};
STATIC uint8_t pwm_channel_toggle[2];
STATIC uint8_t *pwm_channel;
STATIC uint8_t pwm_toggle = 1;
STATIC uint8_t pwm_timer_down = 1;
STATIC uint8_t pwm_current_channel = 0;
STATIC uint16_t pwm_gpio = 0;
STATIC uint8_t pwm_channel_num = 0;
//XXX: 0xffffffff/(80000000/16)=35A
#define US_TO_RTC_TIMER_TICKS(t) \
((t) ? \
(((t) > 0x35A) ? \
(((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000)) : \
(((t) *(APB_CLK_FREQ>>4)) / 1000000)) : \
0)
//FRC1
#define FRC1_ENABLE_TIMER BIT7
typedef enum {
DIVDED_BY_1 = 0,
DIVDED_BY_16 = 4,
DIVDED_BY_256 = 8,
} TIMER_PREDIVED_MODE;
typedef enum {
TM_LEVEL_INT = 1,
TM_EDGE_INT = 0,
} TIMER_INT_MODE;
STATIC void ICACHE_FLASH_ATTR
pwm_insert_sort(struct pwm_single_param pwm[], uint8 n)
{
uint8 i;
for (i = 1; i < n; i++) {
if (pwm[i].h_time < pwm[i - 1].h_time) {
int8 j = i - 1;
struct pwm_single_param tmp;
memcpy(&tmp, &pwm[i], sizeof(struct pwm_single_param));
memcpy(&pwm[i], &pwm[i - 1], sizeof(struct pwm_single_param));
while (tmp.h_time < pwm[j].h_time) {
memcpy(&pwm[j + 1], &pwm[j], sizeof(struct pwm_single_param));
j--;
if (j < 0) {
break;
}
}
memcpy(&pwm[j + 1], &tmp, sizeof(struct pwm_single_param));
}
}
}
STATIC volatile uint8 critical = 0;
#define LOCK_PWM(c) do { \
while( (c)==1 ); \
(c) = 1; \
} while (0)
#define UNLOCK_PWM(c) do { \
(c) = 0; \
} while (0)
void ICACHE_FLASH_ATTR
pwm_start(void)
{
uint8 i, j;
PWM_DBG("--Function pwm_start() is called\n");
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.period:%d,pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.period,pwm.duty[0],pwm.duty[1],pwm.duty[2]);
LOCK_PWM(critical); // enter critical
struct pwm_single_param *local_single = pwm_single_toggle[pwm_toggle ^ 0x01];
uint8 *local_channel = &pwm_channel_toggle[pwm_toggle ^ 0x01];
// step 1: init PWM_CHANNEL+1 channels param
for (i = 0; i < pwm_channel_num; i++) {
uint32 us = pwm.period * pwm.duty[i] / PWM_DEPTH;
local_single[i].h_time = US_TO_RTC_TIMER_TICKS(us);
PWM_DBG("i:%d us:%d ht:%d\n",i,us,local_single[i].h_time);
local_single[i].gpio_set = 0;
local_single[i].gpio_clear = 1 << pin_num[pwm_out_io_num[i]];
}
local_single[pwm_channel_num].h_time = US_TO_RTC_TIMER_TICKS(pwm.period);
local_single[pwm_channel_num].gpio_set = pwm_gpio;
local_single[pwm_channel_num].gpio_clear = 0;
PWM_DBG("i:%d period:%d ht:%d\n",pwm_channel_num,pwm.period,local_single[pwm_channel_num].h_time);
// step 2: sort, small to big
pwm_insert_sort(local_single, pwm_channel_num + 1);
*local_channel = pwm_channel_num + 1;
PWM_DBG("1channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
// step 3: combine same duty channels
for (i = pwm_channel_num; i > 0; i--) {
if (local_single[i].h_time == local_single[i - 1].h_time) {
local_single[i - 1].gpio_set |= local_single[i].gpio_set;
local_single[i - 1].gpio_clear |= local_single[i].gpio_clear;
for (j = i + 1; j < *local_channel; j++) {
memcpy(&local_single[j - 1], &local_single[j], sizeof(struct pwm_single_param));
}
(*local_channel)--;
}
}
PWM_DBG("2channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
// step 4: cacl delt time
for (i = *local_channel - 1; i > 0; i--) {
local_single[i].h_time -= local_single[i - 1].h_time;
}
// step 5: last channel needs to clean
local_single[*local_channel-1].gpio_clear = 0;
// step 6: if first channel duty is 0, remove it
if (local_single[0].h_time == 0) {
local_single[*local_channel - 1].gpio_set &= ~local_single[0].gpio_clear;
local_single[*local_channel - 1].gpio_clear |= local_single[0].gpio_clear;
for (i = 1; i < *local_channel; i++) {
memcpy(&local_single[i - 1], &local_single[i], sizeof(struct pwm_single_param));
}
(*local_channel)--;
}
// if timer is down, need to set gpio and start timer
if (pwm_timer_down == 1) {
pwm_channel = local_channel;
pwm_single = local_single;
// start
gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0);
// yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start...
if (*local_channel != 1) {
pwm_timer_down = 0;
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);
}
}
if (pwm_toggle == 1) {
pwm_toggle = 0;
} else {
pwm_toggle = 1;
}
UNLOCK_PWM(critical); // leave critical
PWM_DBG("3channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);
}
/******************************************************************************
* FunctionName : pwm_set_duty
* Description : set each channel's duty params
* Parameters : uint8 duty : 0 ~ PWM_DEPTH
* uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_set_duty(uint16 duty, uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i] == channel){
channel = i;
break;
}
}
if(i==pwm_channel_num) // non found
return;
LOCK_PWM(critical); // enter critical
if (duty < 1) {
pwm.duty[channel] = 0;
} else if (duty >= PWM_DEPTH) {
pwm.duty[channel] = PWM_DEPTH;
} else {
pwm.duty[channel] = duty;
}
UNLOCK_PWM(critical); // leave critical
}
/******************************************************************************
* FunctionName : pwm_set_freq
* Description : set pwm frequency
* Parameters : uint16 freq : 100hz typically
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_set_freq(uint16 freq, uint8 channel)
{
LOCK_PWM(critical); // enter critical
if (freq > PWM_FREQ_MAX) {
pwm.freq = PWM_FREQ_MAX;
} else if (freq < 1) {
pwm.freq = 1;
} else {
pwm.freq = freq;
}
pwm.period = PWM_1S / pwm.freq;
UNLOCK_PWM(critical); // leave critical
}
/******************************************************************************
* FunctionName : pwm_get_duty
* Description : get duty of each channel
* Parameters : uint8 channel : channel index
* Returns : NONE
*******************************************************************************/
uint16 ICACHE_FLASH_ATTR
pwm_get_duty(uint8 channel)
{
uint8 i;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i] == channel){
channel = i;
break;
}
}
if(i==pwm_channel_num) // non found
return 0;
return pwm.duty[channel];
}
/******************************************************************************
* FunctionName : pwm_get_freq
* Description : get pwm frequency
* Parameters : NONE
* Returns : uint16 : pwm frequency
*******************************************************************************/
uint16 ICACHE_FLASH_ATTR
pwm_get_freq(uint8 channel)
{
return pwm.freq;
}
/******************************************************************************
* FunctionName : pwm_period_timer
* Description : pwm period timer function, output high level,
* start each channel's high level timer
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
STATIC void ICACHE_RAM_ATTR
pwm_tim1_intr_handler(void *dummy)
{
(void)dummy;
uint8 local_toggle = pwm_toggle; // pwm_toggle may change outside
RTC_CLR_REG_MASK(FRC1_INT_ADDRESS, FRC1_INT_CLR_MASK);
if (pwm_current_channel >= (*pwm_channel - 1)) { // *pwm_channel may change outside
pwm_single = pwm_single_toggle[local_toggle];
pwm_channel = &pwm_channel_toggle[local_toggle];
gpio_output_set(pwm_single[*pwm_channel - 1].gpio_set,
pwm_single[*pwm_channel - 1].gpio_clear,
pwm_gpio,
0);
pwm_current_channel = 0;
if (*pwm_channel != 1) {
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
} else {
pwm_timer_down = 1;
}
} else {
gpio_output_set(pwm_single[pwm_current_channel].gpio_set,
pwm_single[pwm_current_channel].gpio_clear,
pwm_gpio, 0);
pwm_current_channel++;
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);
}
}
/******************************************************************************
* FunctionName : pwm_init
* Description : pwm gpio, params and timer initialization
* Parameters : uint16 freq : pwm freq param
* uint16 *duty : each channel's duty
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
pwm_init(void)
{
uint8 i;
RTC_REG_WRITE(FRC1_CTRL_ADDRESS, //FRC2_AUTO_RELOAD|
DIVDED_BY_16
| FRC1_ENABLE_TIMER
| TM_EDGE_INT);
RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);
for (i = 0; i < PWM_CHANNEL; i++) {
pwm_gpio = 0;
pwm.duty[i] = 0;
}
pwm_set_freq(500, 0);
pwm_start();
ETS_FRC_TIMER1_INTR_ATTACH(pwm_tim1_intr_handler, NULL);
TM1_EDGE_INT_ENABLE();
ETS_FRC1_INTR_ENABLE();
}
int ICACHE_FLASH_ATTR
pwm_add(uint8_t pin_id, uint32_t pin_mux, uint32_t pin_func){
PWM_DBG("--Function pwm_add() is called. channel:%d\n", channel);
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]);
int channel = -1;
for (int i = 0; i < PWM_CHANNEL; ++i) {
if (pin_num[i] == pin_id) {
channel = i;
break;
}
}
if (channel == -1) {
return -1;
}
uint8 i;
for(i=0;i<PWM_CHANNEL;i++){
if(pwm_out_io_num[i]==channel) // already exist
return channel;
if(pwm_out_io_num[i] == -1){ // empty exist
LOCK_PWM(critical); // enter critical
pwm_out_io_num[i] = channel;
pwm.duty[i] = 0;
pwm_gpio |= (1 << pin_num[channel]);
PIN_FUNC_SELECT(pin_mux, pin_func);
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;
pwm_channel_num++;
UNLOCK_PWM(critical); // leave critical
return channel;
}
}
return -1;
}
bool ICACHE_FLASH_ATTR
pwm_delete(uint8 channel){
PWM_DBG("--Function pwm_delete() is called. channel:%d\n", channel);
PWM_DBG("pwm_gpio:%x,pwm_channel_num:%d\n",pwm_gpio,pwm_channel_num);
PWM_DBG("pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\n",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);
PWM_DBG("pwm.duty[0]:%d,[1]:%d,[2]:%d\n",pwm.duty[0],pwm.duty[1],pwm.duty[2]);
uint8 i,j;
for(i=0;i<pwm_channel_num;i++){
if(pwm_out_io_num[i]==channel){ // exist
LOCK_PWM(critical); // enter critical
pwm_out_io_num[i] = -1;
pwm_gpio &= ~(1 << pin_num[channel]); //clear the bit
for(j=i;j<pwm_channel_num-1;j++){
pwm_out_io_num[j] = pwm_out_io_num[j+1];
pwm.duty[j] = pwm.duty[j+1];
}
pwm_out_io_num[pwm_channel_num-1] = -1;
pwm.duty[pwm_channel_num-1] = 0;
pwm_channel_num--;
UNLOCK_PWM(critical); // leave critical
return true;
}
}
// non found
return true;
}

17
esp8266/esppwm.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef __ESPPWM_H__
#define __ESPPWM_H__
#include <stdbool.h>
#include <stdint.h>
void pwm_init(void);
void pwm_start(void);
void pwm_set_duty(uint16_t duty, uint8_t channel);
uint16_t pwm_get_duty(uint8_t channel);
void pwm_set_freq(uint16_t freq, uint8_t channel);
uint16_t pwm_get_freq(uint8_t channel);
int pwm_add(uint8_t pin_id, uint32_t pin_mux, uint32_t pin_func);
bool pwm_delete(uint8_t channel);
#endif

194
esp8266/ets_alt_task.c Normal file
View File

@@ -0,0 +1,194 @@
#include <stdio.h>
#include "osapi.h"
#include "os_type.h"
#include "ets_sys.h"
#include <esp_sdk_ver.h>
#include "etshal.h"
#include "user_interface.h"
// Use standard ets_task or alternative impl
#define USE_ETS_TASK 0
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
struct task_entry {
os_event_t *queue;
os_task_t task;
uint8_t qlen;
uint8_t prio;
int8_t i_get;
int8_t i_put;
};
static void (*idle_cb)(void *);
static void *idle_arg;
#if ESP_SDK_VERSION >= 010500
# define FIRST_PRIO 0
#else
# define FIRST_PRIO 0x14
#endif
#define LAST_PRIO 0x20
#define PRIO2ID(prio) ((prio) - FIRST_PRIO)
volatile struct task_entry emu_tasks[PRIO2ID(LAST_PRIO) + 1];
static inline int prio2id(uint8_t prio) {
int id = PRIO2ID(prio);
if (id < 0 || id >= MP_ARRAY_SIZE(emu_tasks)) {
printf("task prio out of range: %d\n", prio);
while (1);
}
return id;
}
#if DEBUG
void dump_task(int prio, volatile struct task_entry *t) {
printf("q for task %d: queue: %p, get ptr: %d, put ptr: %d, qlen: %d\n",
prio, t->queue, t->i_get, t->i_put, t->qlen);
}
void dump_tasks(void) {
for (int i = 0; i < MP_ARRAY_SIZE(emu_tasks); i++) {
if (emu_tasks[i].qlen) {
dump_task(i + FIRST_PRIO, &emu_tasks[i]);
}
}
printf("====\n");
}
#endif
bool ets_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen) {
static unsigned cnt;
printf("#%d ets_task(%p, %d, %p, %d)\n", cnt++, task, prio, queue, qlen);
#if USE_ETS_TASK
return _ets_task(task, prio, queue, qlen);
#else
int id = prio2id(prio);
emu_tasks[id].task = task;
emu_tasks[id].queue = queue;
emu_tasks[id].qlen = qlen;
emu_tasks[id].i_get = 0;
emu_tasks[id].i_put = 0;
return true;
#endif
}
bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
// static unsigned cnt; printf("#%d ets_post(%d, %x, %x)\n", cnt++, prio, sig, param);
#if USE_ETS_TASK
return _ets_post(prio, sig, param);
#else
ets_intr_lock();
const int id = prio2id(prio);
os_event_t *q = emu_tasks[id].queue;
if (emu_tasks[id].i_put == -1) {
// queue is full
printf("ets_post: task %d queue full\n", prio);
return false;
}
q = &q[emu_tasks[id].i_put++];
q->sig = sig;
q->par = param;
if (emu_tasks[id].i_put == emu_tasks[id].qlen) {
emu_tasks[id].i_put = 0;
}
if (emu_tasks[id].i_put == emu_tasks[id].i_get) {
// queue got full
emu_tasks[id].i_put = -1;
}
//printf("after ets_post: "); dump_task(prio, &emu_tasks[id]);
//dump_tasks();
ets_intr_unlock();
return true;
#endif
}
bool ets_loop_iter(void) {
//static unsigned cnt;
bool progress = false;
for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
system_soft_wdt_feed();
ets_intr_lock();
//printf("etc_loop_iter: "); dump_task(t - emu_tasks + FIRST_PRIO, t);
if (t->i_get != t->i_put) {
progress = true;
//printf("#%d Calling task %d(%p) (%x, %x)\n", cnt++,
// t - emu_tasks + FIRST_PRIO, t->task, t->queue[t->i_get].sig, t->queue[t->i_get].par);
int idx = t->i_get;
if (t->i_put == -1) {
t->i_put = t->i_get;
}
if (++t->i_get == t->qlen) {
t->i_get = 0;
}
//ets_intr_unlock();
t->task(&t->queue[idx]);
//ets_intr_lock();
//printf("Done calling task %d\n", t - emu_tasks + FIRST_PRIO);
}
ets_intr_unlock();
}
return progress;
}
#if SDK_BELOW_1_1_1
void my_timer_isr(void *arg) {
// uart0_write_char('+');
ets_post(0x1f, 0, 0);
}
// Timer init func is in ROM, and calls ets_task by relative addr directly in ROM
// so, we have to re-init task using our handler
void ets_timer_init() {
printf("ets_timer_init\n");
// _ets_timer_init();
ets_isr_attach(10, my_timer_isr, NULL);
SET_PERI_REG_MASK(0x3FF00004, 4);
ETS_INTR_ENABLE(10);
ets_task((os_task_t)0x40002E3C, 0x1f, (os_event_t*)0x3FFFDDC0, 4);
WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0);
WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x28, 0x88);
WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + 0x30, 0);
printf("Installed timer ISR\n");
}
#endif
bool ets_run(void) {
#if USE_ETS_TASK
#if SDK_BELOW_1_1_1
ets_isr_attach(10, my_timer_isr, NULL);
#endif
_ets_run();
#else
// ets_timer_init();
*(char*)0x3FFFC6FC = 0;
ets_intr_lock();
printf("ets_alt_task: ets_run\n");
#if DEBUG
dump_tasks();
#endif
ets_intr_unlock();
while (1) {
if (!ets_loop_iter()) {
//printf("idle\n");
ets_intr_lock();
if (idle_cb) {
idle_cb(idle_arg);
}
asm("waiti 0");
ets_intr_unlock();
}
}
#endif
}
void ets_set_idle_cb(void (*handler)(void *), void *arg) {
//printf("ets_set_idle_cb(%p, %p)\n", handler, arg);
idle_cb = handler;
idle_arg = arg;
}

1
esp8266/ets_alt_task.h Normal file
View File

@@ -0,0 +1 @@
bool ets_loop_iter(void);

View File

@@ -1,9 +1,23 @@
#ifndef _INCLUDED_ETSHAL_H_
#define _INCLUDED_ETSHAL_H_
void ets_isr_unmask();
#include <os_type.h>
// see http://esp8266-re.foogod.com/wiki/Random_Number_Generator
#define WDEV_HWRNG ((volatile uint32_t*)0x3ff20e44)
void ets_delay_us();
void ets_intr_lock(void);
void ets_intr_unlock(void);
void ets_isr_mask(uint32_t mask);
void ets_isr_unmask(uint32_t mask);
void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg);
void ets_install_putc1();
void ets_isr_attach();
void uart_div_modify();
void ets_set_idle_cb(void (*handler)(void *), void *arg);
void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer);
void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data);
void ets_timer_disarm(os_timer_t *tim);
#endif // _INCLUDED_ETSHAL_H_

6
esp8266/fatfs_port.c Normal file
View File

@@ -0,0 +1,6 @@
#include "lib/fatfs/ff.h"
#include "lib/fatfs/diskio.h"
DWORD get_fattime(void) {
return 0;
}

View File

@@ -39,10 +39,6 @@ void gc_collect(void) {
// start the GC
gc_collect_start();
// We need to scan everything in RAM that can hold a pointer.
// The data segment is used, but should not contain pointers, so we just scan the bss.
gc_collect_root((void**)&_bss_start, ((uint32_t)&_bss_end - (uint32_t)&_bss_start) / sizeof(uint32_t));
// get the registers and the sp
mp_uint_t regs[8];
mp_uint_t sp = gc_helper_get_regs_and_sp(regs);

69
esp8266/lexerstr32.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2016 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 "py/lexer.h"
#if MICROPY_ENABLE_COMPILER
typedef struct _mp_lexer_str32_buf_t {
const uint32_t *src_cur;
uint32_t val;
uint8_t byte_off;
} mp_lexer_str32_buf_t;
STATIC mp_uint_t str32_buf_next_byte(mp_lexer_str32_buf_t *sb) {
byte c = sb->val & 0xff;
if (c == 0) {
return MP_LEXER_EOF;
}
if (++sb->byte_off > 3) {
sb->byte_off = 0;
sb->val = *sb->src_cur++;
} else {
sb->val >>= 8;
}
return c;
}
STATIC void str32_buf_free(mp_lexer_str32_buf_t *sb) {
m_del_obj(mp_lexer_str32_buf_t, sb);
}
mp_lexer_t *mp_lexer_new_from_str32(qstr src_name, const char *str, mp_uint_t len, mp_uint_t free_len) {
mp_lexer_str32_buf_t *sb = m_new_obj_maybe(mp_lexer_str32_buf_t);
if (sb == NULL) {
return NULL;
}
sb->byte_off = (uint32_t)str & 3;
sb->src_cur = (uint32_t*)(str - sb->byte_off);
sb->val = *sb->src_cur++ >> sb->byte_off * 8;
return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str32_buf_next_byte, (mp_lexer_stream_close_t)str32_buf_free);
}
#endif // MICROPY_ENABLE_COMPILER

View File

@@ -38,51 +38,106 @@
#include "gccollect.h"
#include "user_interface.h"
STATIC char heap[16384];
STATIC char heap[24 * 1024];
STATIC void mp_reset(void) {
mp_stack_set_limit(10240);
mp_stack_set_top((void*)0x40000000);
mp_stack_set_limit(8192);
mp_hal_init();
gc_init(heap, heap + sizeof(heap));
mp_init();
mp_obj_list_init(mp_sys_path, 0);
mp_obj_list_init(mp_sys_argv, 0);
#if MICROPY_VFS_FAT
memset(MP_STATE_PORT(fs_user_mount), 0, sizeof(MP_STATE_PORT(fs_user_mount)));
#endif
MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
#if MICROPY_MODULE_FROZEN
pyexec_frozen_module("main");
pyexec_frozen_module("_boot");
pyexec_file("boot.py");
pyexec_file("main.py");
#endif
}
void soft_reset(void) {
mp_hal_stdout_tx_str("PYB: soft reset\r\n");
mp_hal_stdout_tx_str("PYB: soft reboot\r\n");
mp_hal_delay_us(10000); // allow UART to flush output
mp_reset();
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_event_repl_init();
#endif
}
void init_done(void) {
#if MICROPY_REPL_EVENT_DRIVEN
uart_task_init();
#endif
mp_reset();
mp_hal_stdout_tx_str("\r\n");
#if MICROPY_REPL_EVENT_DRIVEN
pyexec_event_repl_init();
uart_task_init();
#endif
dupterm_task_init();
#if !MICROPY_REPL_EVENT_DRIVEN
soft_reset:
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
if (pyexec_raw_repl() != 0) {
break;
}
} else {
if (pyexec_friendly_repl() != 0) {
break;
}
}
}
soft_reset();
goto soft_reset;
#endif
}
void user_init(void) {
system_init_done_cb(init_done);
}
mp_lexer_t *fat_vfs_lexer_new_from_file(const char *filename);
mp_import_stat_t fat_vfs_import_stat(const char *path);
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
#if MICROPY_VFS_FAT
return fat_vfs_lexer_new_from_file(filename);
#else
(void)filename;
return NULL;
#endif
}
mp_import_stat_t mp_import_stat(const char *path) {
#if MICROPY_VFS_FAT
return fat_vfs_import_stat(path);
#else
(void)path;
return MP_IMPORT_STAT_NO_EXIST;
#endif
}
mp_obj_t vfs_proxy_call(qstr method_name, mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
#if MICROPY_VFS_FAT
// TODO: Handle kwargs!
return vfs_proxy_call(MP_QSTR_open, n_args, args);
#else
return mp_const_none;
#endif
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
void mp_keyboard_interrupt(void) {
MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
}
void nlr_jump_fail(void *val) {
printf("NLR jump failed\n");
for (;;) {

View File

@@ -1,5 +1,7 @@
import sys
SEGS_MAX_SIZE = 0x9000
assert len(sys.argv) == 4
with open(sys.argv[3], 'wb') as fout:
@@ -9,7 +11,7 @@ with open(sys.argv[3], 'wb') as fout:
fout.write(data_flash)
print('flash ', len(data_flash))
pad = b'\xff' * (0x10000 - len(data_flash))
pad = b'\xff' * (SEGS_MAX_SIZE - len(data_flash))
fout.write(pad)
print('padding ', len(pad))
@@ -18,4 +20,4 @@ with open(sys.argv[3], 'wb') as fout:
fout.write(data_rom)
print('irom0text', len(data_rom))
print('total ', 0x10000 + len(data_rom))
print('total ', SEGS_MAX_SIZE + len(data_rom))

View File

@@ -35,12 +35,16 @@
#include "py/runtime.h"
#include "netutils.h"
#include "queue.h"
#include "ets_sys.h"
#include "uart.h"
#include "user_interface.h"
#include "espconn.h"
#include "spi_flash.h"
#include "utils.h"
#include "espneopixel.h"
#include "modpyb.h"
#define MODESP_ESPCONN (1)
#define MODESP_ESPCONN (0)
#if MODESP_ESPCONN
STATIC const mp_obj_type_t esp_socket_type;
@@ -512,25 +516,15 @@ void error_check(bool status, const char *msg) {
}
}
STATIC mp_obj_t esp_wifi_mode(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return mp_obj_new_int(wifi_get_opmode());
STATIC mp_obj_t esp_osdebug(mp_obj_t val) {
if (val == mp_const_none) {
uart_os_config(-1);
} else {
wifi_set_opmode(mp_obj_get_int(args[0]));
return mp_const_none;
uart_os_config(mp_obj_get_int(val));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_wifi_mode_obj, 0, 1, esp_wifi_mode);
STATIC mp_obj_t esp_phy_mode(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return mp_obj_new_int(wifi_get_phy_mode());
} else {
wifi_set_phy_mode(mp_obj_get_int(args[0]));
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_osdebug_obj, esp_osdebug);
STATIC mp_obj_t esp_sleep_type(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
@@ -553,42 +547,106 @@ STATIC mp_obj_t esp_flash_id() {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_id_obj, esp_flash_id);
STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_in) {
STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) {
mp_int_t offset = mp_obj_get_int(offset_in);
mp_int_t len = mp_obj_get_int(len_in);
byte *buf = m_new(byte, len);
mp_int_t len;
byte *buf;
bool alloc_buf = MP_OBJ_IS_INT(len_or_buf_in);
if (alloc_buf) {
len = mp_obj_get_int(len_or_buf_in);
buf = m_new(byte, len);
} else {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(len_or_buf_in, &bufinfo, MP_BUFFER_WRITE);
len = bufinfo.len;
buf = bufinfo.buf;
}
// We know that allocation will be 4-byte aligned for sure
SpiFlashOpResult res = spi_flash_read(offset, (uint32_t*)buf, len);
if (res == SPI_FLASH_RESULT_OK) {
return mp_obj_new_bytes(buf, len);
if (alloc_buf) {
return mp_obj_new_bytes(buf, len);
}
return mp_const_none;
}
if (alloc_buf) {
m_del(byte, buf, len);
}
m_del(byte, buf, len);
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) {
mp_int_t offset = mp_obj_get_int(offset_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len & 0x3) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "len must be multiple of 4"));
}
SpiFlashOpResult res = spi_flash_write(offset, bufinfo.buf, bufinfo.len);
if (res == SPI_FLASH_RESULT_OK) {
return mp_const_none;
}
nlr_raise(mp_obj_new_exception_arg1(
&mp_type_OSError,
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
mp_int_t sector = mp_obj_get_int(sector_in);
SpiFlashOpResult res = spi_flash_erase_sector(sector);
if (res == SPI_FLASH_RESULT_OK) {
return mp_const_none;
}
nlr_raise(mp_obj_new_exception_arg1(
&mp_type_OSError,
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
esp_neopixel_write(mp_obj_get_pin_obj(pin)->phys_port,
(uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_is_true(is800k));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
STATIC mp_obj_t esp_freemem() {
return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_freemem_obj, esp_freemem);
STATIC mp_obj_t esp_meminfo() {
system_print_meminfo();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_meminfo_obj, esp_meminfo);
STATIC const mp_map_elem_t esp_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_esp) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wifi_mode), (mp_obj_t)&esp_wifi_mode_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_osdebug), (mp_obj_t)&esp_osdebug_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_type), (mp_obj_t)&esp_sleep_type_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_deepsleep), (mp_obj_t)&esp_deepsleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flash_id), (mp_obj_t)&esp_flash_id_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flash_read), (mp_obj_t)&esp_flash_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flash_write), (mp_obj_t)&esp_flash_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flash_erase), (mp_obj_t)&esp_flash_erase_obj },
#if MODESP_ESPCONN
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&esp_neopixel_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_freemem), (mp_obj_t)&esp_freemem_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_meminfo), (mp_obj_t)&esp_meminfo_obj },
#if MODESP_INCLUDE_CONSTANTS
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11B),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11B) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11G),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11G) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11N),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11N) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP_NONE),
MP_OBJ_NEW_SMALL_INT(NONE_SLEEP_T) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP_LIGHT),

174
esp8266/modmachine.c Normal file
View File

@@ -0,0 +1,174 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* 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 "py/obj.h"
#include "py/runtime.h"
#include "extmod/machine_mem.h"
#include "utils.h"
#include "modpyb.h"
#include "os_type.h"
#include "osapi.h"
#include "etshal.h"
#include "user_interface.h"
#if MICROPY_PY_MACHINE
STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
return mp_obj_new_int(system_get_cpu_freq() * 1000000);
} else {
// set
mp_int_t freq = mp_obj_get_int(args[0]) / 1000000;
if (freq != 80 && freq != 160) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"frequency can only be either 80Mhz or 160MHz"));
}
system_update_cpu_freq(freq);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 1, machine_freq);
STATIC mp_obj_t machine_reset(void) {
system_restart();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
STATIC mp_obj_t machine_unique_id(void) {
uint32_t id = system_get_chip_id();
return mp_obj_new_bytes((byte*)&id, sizeof(id));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
typedef struct _esp_timer_obj_t {
mp_obj_base_t base;
os_timer_t timer;
mp_obj_t callback;
} esp_timer_obj_t;
const mp_obj_type_t esp_timer_type;
STATIC void esp_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
esp_timer_obj_t *self = self_in;
mp_printf(print, "Timer(%p)", &self->timer);
}
STATIC mp_obj_t esp_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
esp_timer_obj_t *tim = m_new_obj(esp_timer_obj_t);
tim->base.type = &esp_timer_type;
return tim;
}
STATIC void esp_timer_cb(void *arg) {
esp_timer_obj_t *self = arg;
call_function_1_protected(self->callback, self);
}
STATIC mp_obj_t esp_timer_init_helper(esp_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_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ 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} },
};
// 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);
self->callback = args[2].u_obj;
// Be sure to disarm timer before making any changes
os_timer_disarm(&self->timer);
os_timer_setfn(&self->timer, esp_timer_cb, self);
os_timer_arm(&self->timer, args[0].u_int, args[1].u_int);
return mp_const_none;
}
STATIC mp_obj_t esp_timer_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return esp_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_timer_init_obj, 1, esp_timer_init);
STATIC mp_obj_t esp_timer_deinit(mp_obj_t self_in) {
esp_timer_obj_t *self = self_in;
os_timer_disarm(&self->timer);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_timer_deinit_obj, esp_timer_deinit);
STATIC const mp_map_elem_t esp_timer_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&esp_timer_deinit_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&esp_timer_init_obj },
// { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&esp_timer_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ONE_SHOT), MP_OBJ_NEW_SMALL_INT(false) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PERIODIC), MP_OBJ_NEW_SMALL_INT(true) },
};
STATIC MP_DEFINE_CONST_DICT(esp_timer_locals_dict, esp_timer_locals_dict_table);
const mp_obj_type_t esp_timer_type = {
{ &mp_type_type },
.name = MP_QSTR_Timer,
.print = esp_timer_print,
.make_new = esp_timer_make_new,
.locals_dict = (mp_obj_t)&esp_timer_locals_dict,
};
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&pyb_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
const mp_obj_module_t mp_module_machine = {
.base = { &mp_type_module },
.name = MP_QSTR_umachine,
.globals = (mp_obj_dict_t*)&machine_module_globals,
};
#endif // MICROPY_PY_MACHINE

View File

@@ -32,29 +32,77 @@
#include "py/nlr.h"
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "netutils.h"
#include "queue.h"
#include "user_interface.h"
#include "espconn.h"
#include "spi_flash.h"
#include "utils.h"
#include "ets_alt_task.h"
#define MODNETWORK_INCLUDE_CONSTANTS (1)
typedef struct _wlan_if_obj_t {
mp_obj_base_t base;
int if_id;
} wlan_if_obj_t;
void error_check(bool status, const char *msg);
extern const mp_obj_module_t network_module;
const mp_obj_type_t wlan_if_type;
STATIC mp_obj_t get_module() {
return (mp_obj_t)&network_module;
STATIC const wlan_if_obj_t wlan_objs[] = {
{{&wlan_if_type}, STATION_IF},
{{&wlan_if_type}, SOFTAP_IF},
};
STATIC void require_if(mp_obj_t wlan_if, int if_no) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
if (self->if_id != if_no) {
error_check(false, if_no == STATION_IF ? "STA required" : "AP required");
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(get_module_obj, get_module);
STATIC mp_obj_t get_wlan(mp_uint_t n_args, const mp_obj_t *args) {
int idx = 0;
if (n_args > 0) {
idx = mp_obj_get_int(args[0]);
}
return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
STATIC mp_obj_t esp_active(mp_uint_t n_args, const mp_obj_t *args) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
uint32_t mode = wifi_get_opmode();
if (n_args > 1) {
int mask = self->if_id == STATION_IF ? STATION_MODE : SOFTAP_MODE;
if (mp_obj_get_int(args[1]) != 0) {
mode |= mask;
} else {
mode &= ~mask;
}
error_check(wifi_set_opmode(mode), "Cannot update i/f status");
return mp_const_none;
}
// Get active status
if (self->if_id == STATION_IF) {
return mp_obj_new_bool(mode & STATION_MODE);
} else {
return mp_obj_new_bool(mode & SOFTAP_MODE);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
STATIC mp_obj_t esp_connect(mp_uint_t n_args, const mp_obj_t *args) {
require_if(args[0], STATION_IF);
struct station_config config = {{0}};
mp_uint_t len;
const char *p;
p = mp_obj_str_get_data(args[0], &len);
memcpy(config.ssid, p, len);
p = mp_obj_str_get_data(args[1], &len);
memcpy(config.ssid, p, len);
p = mp_obj_str_get_data(args[2], &len);
memcpy(config.password, p, len);
error_check(wifi_station_set_config(&config), "Cannot set STA config");
@@ -62,24 +110,33 @@ STATIC mp_obj_t esp_connect(mp_uint_t n_args, const mp_obj_t *args) {
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 2, 6, esp_connect);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 3, 7, esp_connect);
STATIC mp_obj_t esp_disconnect() {
STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
require_if(self_in, STATION_IF);
error_check(wifi_station_disconnect(), "Cannot disconnect from AP");
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_disconnect_obj, esp_disconnect);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
#define MODNETWORK_INCLUDE_CONSTANTS (1)
STATIC mp_obj_t esp_status() {
return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
STATIC mp_obj_t esp_status(mp_obj_t self_in) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->if_id == STATION_IF) {
return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
}
return MP_OBJ_NEW_SMALL_INT(-1);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_status_obj, esp_status);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status);
STATIC mp_obj_t *esp_scan_list = NULL;
STATIC void esp_scan_cb(scaninfo *si, STATUS status) {
struct bss_info *bs;
if (si->pbss) {
if (esp_scan_list == NULL) {
// called unexpectedly
return;
}
if (si->pbss && status == 0) {
struct bss_info *bs;
STAILQ_FOREACH(bs, si->pbss, next) {
mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid));
@@ -88,69 +145,205 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) {
t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi);
t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode);
t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden);
call_function_1_protected(MP_STATE_PORT(scan_cb_obj), t);
mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
}
} else {
// indicate error
*esp_scan_list = MP_OBJ_NULL;
}
esp_scan_list = NULL;
}
STATIC mp_obj_t esp_scan(mp_obj_t cb_in) {
MP_STATE_PORT(scan_cb_obj) = cb_in;
STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
if (wifi_get_opmode() == SOFTAP_MODE) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"Scan not supported in AP mode"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
"scan unsupported in AP mode"));
}
mp_obj_t list = mp_obj_new_list(0, NULL);
esp_scan_list = &list;
wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb);
return mp_const_none;
ETS_POLL_WHILE(esp_scan_list != NULL);
if (list == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed"));
}
return list;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
/// \method isconnected()
/// Return True if connected to an AP and an IP address has been assigned,
/// false otherwise.
STATIC mp_obj_t esp_isconnected() {
if (wifi_station_get_connect_status() == STATION_GOT_IP) {
return mp_const_true;
STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->if_id == STATION_IF) {
if (wifi_station_get_connect_status() == STATION_GOT_IP) {
return mp_const_true;
}
} else {
if (wifi_softap_get_station_num() > 0) {
return mp_const_true;
}
}
return mp_const_false;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_isconnected_obj, esp_isconnected);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
STATIC mp_obj_t esp_mac(mp_uint_t n_args, const mp_obj_t *args) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
uint8_t mac[6];
if (n_args == 0) {
wifi_get_macaddr(STATION_IF, mac);
if (n_args == 1) {
wifi_get_macaddr(self->if_id, mac);
return mp_obj_new_bytes(mac, sizeof(mac));
} else {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
if (bufinfo.len != 6) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"invalid buffer length"));
}
wifi_set_macaddr(STATION_IF, bufinfo.buf);
wifi_set_macaddr(self->if_id, bufinfo.buf);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_mac_obj, 0, 1, esp_mac);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_mac_obj, 1, 2, esp_mac);
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) },
// MicroPython "network" module interface requires it to contains classes
// to instantiate. But as we have just a static network interace,
// use module as a "class", and just make all methods module-global
// functions.
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_module_obj },
STATIC mp_obj_t esp_ifconfig(mp_obj_t self_in) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
struct ip_info info;
wifi_get_ip_info(self->if_id, &info);
mp_obj_t ifconfig[4] = {
netutils_format_ipv4_addr((uint8_t*)&info.ip, NETUTILS_BIG),
netutils_format_ipv4_addr((uint8_t*)&info.netmask, NETUTILS_BIG),
netutils_format_ipv4_addr((uint8_t*)&info.gw, NETUTILS_BIG),
MP_OBJ_NEW_QSTR(MP_QSTR_), // no DNS server
};
return mp_obj_new_tuple(4, ifconfig);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_ifconfig_obj, esp_ifconfig);
STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
if (n_args != 1 && kwargs->used != 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"either pos or kw args are allowed"));
}
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
union {
struct station_config sta;
struct softap_config ap;
} cfg;
if (self->if_id == STATION_IF) {
error_check(wifi_station_get_config(&cfg.sta), "can't get STA config");
} else {
error_check(wifi_softap_get_config(&cfg.ap), "can't get AP config");
}
if (kwargs->used != 0) {
for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
switch ((uintptr_t)kwargs->table[i].key) {
case QS(MP_QSTR_essid): {
mp_uint_t len;
const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
len = MIN(len, sizeof(cfg.ap.ssid));
memcpy(cfg.ap.ssid, s, len);
cfg.ap.ssid_len = len;
break;
}
default:
goto unknown;
}
#undef QS
}
}
if (self->if_id == STATION_IF) {
error_check(wifi_station_set_config(&cfg.sta), "can't set STA config");
} else {
error_check(wifi_softap_set_config(&cfg.ap), "can't set AP config");
}
return mp_const_none;
}
// Get config
if (n_args != 2) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"can query only one param"));
}
#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
switch ((uintptr_t)args[1]) {
case QS(MP_QSTR_essid):
return mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false);
}
#undef QS
unknown:
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"unknown config param"));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
STATIC const mp_map_elem_t wlan_if_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_active), (mp_obj_t)&esp_active_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&esp_connect_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&esp_disconnect_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&esp_status_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&esp_scan_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&esp_isconnected_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mac), (mp_obj_t)&esp_mac_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_config), (mp_obj_t)&esp_config_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&esp_ifconfig_obj },
};
STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
const mp_obj_type_t wlan_if_type = {
{ &mp_type_type },
.name = MP_QSTR_WLAN,
.locals_dict = (mp_obj_t)&wlan_if_locals_dict,
};
STATIC mp_obj_t esp_wifi_mode(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return mp_obj_new_int(wifi_get_opmode());
} else {
wifi_set_opmode(mp_obj_get_int(args[0]));
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_wifi_mode_obj, 0, 1, esp_wifi_mode);
STATIC mp_obj_t esp_phy_mode(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return mp_obj_new_int(wifi_get_phy_mode());
} else {
wifi_set_phy_mode(mp_obj_get_int(args[0]));
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&get_wlan_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_wifi_mode), (mp_obj_t)&esp_wifi_mode_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_phy_mode), (mp_obj_t)&esp_phy_mode_obj },
#if MODNETWORK_INCLUDE_CONSTANTS
{ MP_OBJ_NEW_QSTR(MP_QSTR_STA_IF),
MP_OBJ_NEW_SMALL_INT(STATION_IF)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_AP_IF),
MP_OBJ_NEW_SMALL_INT(SOFTAP_IF)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_STAT_IDLE),
MP_OBJ_NEW_SMALL_INT(STATION_IDLE)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_STAT_CONNECTING),
@@ -163,6 +356,13 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
MP_OBJ_NEW_SMALL_INT(STATION_CONNECT_FAIL)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_STAT_GOT_IP),
MP_OBJ_NEW_SMALL_INT(STATION_GOT_IP)},
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11B),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11B) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11G),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11G) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11N),
MP_OBJ_NEW_SMALL_INT(PHY_MODE_11N) },
#endif
};

185
esp8266/modonewire.c Normal file
View File

@@ -0,0 +1,185 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 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 "etshal.h"
#include "user_interface.h"
#include "py/obj.h"
#include "py/mphal.h"
#include "modpyb.h"
STATIC uint32_t disable_irq(void) {
ets_intr_lock();
return 0;
}
STATIC void enable_irq(uint32_t i) {
ets_intr_unlock();
}
STATIC void mp_hal_delay_us_no_irq(uint32_t us) {
uint32_t start = system_get_time();
while (system_get_time() - start < us) {
}
}
#define DELAY_US mp_hal_delay_us_no_irq
#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)
static int timings[] = {480, 40, 420, 5, 5, 40, 10, 50, 10};
STATIC mp_obj_t onewire_timings(mp_obj_t timings_in) {
mp_obj_t *items;
mp_obj_get_array_fixed_n(timings_in, 9, &items);
for (int i = 0; i < 9; ++i) {
timings[i] = mp_obj_get_int(items[i]);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_timings_obj, onewire_timings);
STATIC mp_obj_t onewire_reset(mp_obj_t pin_in) {
uint pin = mp_obj_get_pin(pin_in);
pin_set(pin, 0);
DELAY_US(timings[TIMING_RESET1]);
uint32_t i = disable_irq();
pin_set(pin, 1);
DELAY_US(timings[TIMING_RESET2]);
int status = !pin_get(pin);
enable_irq(i);
DELAY_US(timings[TIMING_RESET3]);
return mp_obj_new_bool(status);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_reset_obj, onewire_reset);
STATIC int _onewire_readbit(uint pin) {
pin_set(pin, 1);
uint32_t i = disable_irq();
pin_set(pin, 0);
DELAY_US(timings[TIMING_READ1]);
pin_set(pin, 1);
DELAY_US(timings[TIMING_READ2]);
int value = pin_get(pin);
enable_irq(i);
DELAY_US(timings[TIMING_READ3]);
return value;
}
STATIC mp_obj_t onewire_readbit(mp_obj_t pin_in) {
return MP_OBJ_NEW_SMALL_INT(_onewire_readbit(mp_obj_get_pin(pin_in)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbit_obj, onewire_readbit);
STATIC mp_obj_t onewire_readbyte(mp_obj_t pin_in) {
uint pin = mp_obj_get_pin(pin_in);
uint8_t value = 0;
for (int i = 0; i < 8; ++i) {
value |= _onewire_readbit(pin) << i;
}
return MP_OBJ_NEW_SMALL_INT(value);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_readbyte_obj, onewire_readbyte);
STATIC void _onewire_writebit(uint pin, int value) {
uint32_t i = disable_irq();
pin_set(pin, 0);
DELAY_US(timings[TIMING_WRITE1]);
pin_set(pin, value);
DELAY_US(timings[TIMING_WRITE2]);
pin_set(pin, 1);
DELAY_US(timings[TIMING_WRITE3]);
enable_irq(i);
}
STATIC mp_obj_t onewire_writebit(mp_obj_t pin_in, mp_obj_t value_in) {
_onewire_writebit(mp_obj_get_pin(pin_in), mp_obj_get_int(value_in));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebit_obj, onewire_writebit);
STATIC mp_obj_t onewire_writebyte(mp_obj_t pin_in, mp_obj_t value_in) {
uint pin = mp_obj_get_pin(pin_in);
int value = mp_obj_get_int(value_in);
for (int i = 0; i < 8; ++i) {
_onewire_writebit(pin, value & 1);
value >>= 1;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(onewire_writebyte_obj, onewire_writebyte);
STATIC mp_obj_t onewire_crc8(mp_obj_t data) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
uint8_t crc = 0;
for (size_t i = 0; i < bufinfo.len; ++i) {
uint8_t byte = ((uint8_t*)bufinfo.buf)[i];
for (int b = 0; b < 8; ++b) {
uint8_t fb_bit = (crc ^ byte) & 0x01;
if (fb_bit == 0x01) {
crc = crc ^ 0x18;
}
crc = (crc >> 1) & 0x7f;
if (fb_bit == 0x01) {
crc = crc | 0x80;
}
byte = byte >> 1;
}
}
return MP_OBJ_NEW_SMALL_INT(crc);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(onewire_crc8_obj, onewire_crc8);
STATIC const mp_map_elem_t onewire_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_onewire) },
{ MP_ROM_QSTR(MP_QSTR_timings), MP_ROM_PTR((mp_obj_t)&onewire_timings_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR((mp_obj_t)&onewire_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_readbit), MP_ROM_PTR((mp_obj_t)&onewire_readbit_obj) },
{ MP_ROM_QSTR(MP_QSTR_readbyte), MP_ROM_PTR((mp_obj_t)&onewire_readbyte_obj) },
{ MP_ROM_QSTR(MP_QSTR_writebit), MP_ROM_PTR((mp_obj_t)&onewire_writebit_obj) },
{ MP_ROM_QSTR(MP_QSTR_writebyte), MP_ROM_PTR((mp_obj_t)&onewire_writebyte_obj) },
{ MP_ROM_QSTR(MP_QSTR_crc8), MP_ROM_PTR((mp_obj_t)&onewire_crc8_obj) },
};
STATIC MP_DEFINE_CONST_DICT(onewire_module_globals, onewire_module_globals_table);
const mp_obj_module_t onewire_module = {
.base = { &mp_type_module },
.name = MP_QSTR_onewire,
.globals = (mp_obj_dict_t*)&onewire_module_globals,
};

View File

@@ -77,23 +77,6 @@ STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
STATIC mp_obj_t pyb_freq(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
return mp_obj_new_int(system_get_cpu_freq() * 1000000);
} else {
// set
mp_int_t freq = mp_obj_get_int(args[0]) / 1000000;
if (freq != 80 && freq != 160) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"frequency can only be either 80Mhz or 160MHz"));
}
system_update_cpu_freq(freq);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_freq_obj, 0, 1, pyb_freq);
STATIC mp_obj_t pyb_sync(void) {
//storage_flush();
return mp_const_none;
@@ -142,23 +125,10 @@ STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
STATIC mp_obj_t pyb_hard_reset(void) {
system_restart();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_hard_reset_obj, pyb_hard_reset);
STATIC mp_obj_t pyb_unique_id(void) {
uint32_t id = system_get_chip_id();
return mp_obj_new_bytes((byte *)&id, sizeof(id));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_millis), (mp_obj_t)&pyb_elapsed_millis_obj },
@@ -167,7 +137,6 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pyb_pin_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },

View File

@@ -1,3 +1,20 @@
extern const mp_obj_type_t pyb_pin_type;
extern const mp_obj_type_t pyb_pwm_type;
extern const mp_obj_type_t pyb_adc_type;
extern const mp_obj_type_t pyb_rtc_type;
extern const mp_obj_type_t pyb_uart_type;
extern const mp_obj_type_t pyb_i2c_type;
extern const mp_obj_type_t pyb_spi_type;
typedef struct _pyb_pin_obj_t {
mp_obj_base_t base;
uint16_t pin_id;
uint16_t phys_port;
uint32_t periph;
uint16_t func;
} pyb_pin_obj_t;
uint mp_obj_get_pin(mp_obj_t pin_in);
pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in);
int pin_get(uint pin);
void pin_set(uint pin, int value);

323
esp8266/modpybi2c.c Normal file
View File

@@ -0,0 +1,323 @@
/*
* 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 "ets_sys.h"
#include "etshal.h"
#include "osapi.h"
#include "gpio.h"
#include "py/runtime.h"
#include "modpyb.h"
typedef struct _pyb_i2c_obj_t {
mp_obj_base_t base;
pyb_pin_obj_t *scl;
pyb_pin_obj_t *sda;
} pyb_i2c_obj_t;
// these set the frequency of SCL
#define mphal_i2c_wait_a() os_delay_us(2)
#define mphal_i2c_wait_b() os_delay_us(1)
STATIC void mphal_i2c_set_sda(pyb_i2c_obj_t *self, uint8_t sda) {
uint32_t port = self->sda->phys_port;
sda &= 0x01;
gpio_output_set(sda << port, (1 - sda) << port, 1 << port, 0);
}
STATIC void mphal_i2c_set_scl(pyb_i2c_obj_t *self, uint8_t scl) {
uint32_t port = self->scl->phys_port;
scl &= 0x01;
gpio_output_set(scl << port, (1 - scl) << port, 1 << port, 0);
}
STATIC int mphal_i2c_get_sda(pyb_i2c_obj_t *self) {
return GPIO_INPUT_GET(GPIO_ID_PIN(self->sda->phys_port));
}
STATIC void mphal_i2c_start(pyb_i2c_obj_t *self) {
mphal_i2c_set_sda(self, 1);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
mphal_i2c_set_sda(self, 0);
mphal_i2c_wait_a();
}
STATIC void mphal_i2c_stop(pyb_i2c_obj_t *self) {
mphal_i2c_wait_a();
mphal_i2c_set_sda(self, 0);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
mphal_i2c_set_sda(self, 1);
mphal_i2c_wait_a();
}
STATIC void mphal_i2c_init(pyb_i2c_obj_t *self, uint32_t freq) {
pyb_pin_obj_t *scl = self->scl;
pyb_pin_obj_t *sda = self->sda;
ETS_GPIO_INTR_DISABLE();
//ETS_INTR_LOCK();
PIN_FUNC_SELECT(sda->periph, sda->func);
PIN_FUNC_SELECT(scl->periph, scl->func);
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(sda->phys_port)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(sda->phys_port)))
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,
GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << sda->phys_port));
GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(scl->phys_port)),
GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(scl->phys_port)))
| GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,
GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << scl->phys_port));
mphal_i2c_set_scl(self, 1);
mphal_i2c_set_sda(self, 1);
ETS_GPIO_INTR_ENABLE();
//ETS_INTR_UNLOCK();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
// when SCL = 0, toggle SDA to clear up
mphal_i2c_set_sda(self, 0);
mphal_i2c_wait_a();
mphal_i2c_set_sda(self, 1);
mphal_i2c_wait_a();
// set data_cnt to max value
for (uint8_t i = 0; i < 28; i++) {
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
}
// reset all
mphal_i2c_stop(self);
}
STATIC int mphal_i2c_write_byte(pyb_i2c_obj_t *self, uint8_t val) {
uint8_t dat;
sint8 i;
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
for (i = 7; i >= 0; i--) {
dat = val >> i;
mphal_i2c_set_sda(self, dat);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
if (i == 0) {
mphal_i2c_wait_b();
}
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
}
mphal_i2c_set_sda(self, 1);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
int ret = mphal_i2c_get_sda(self);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
return !ret;
}
STATIC void mphal_i2c_write(pyb_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len, bool stop) {
mphal_i2c_start(self);
if (!mphal_i2c_write_byte(self, addr << 1)) {
goto er;
}
while (len--) {
if (!mphal_i2c_write_byte(self, *data++)) {
goto er;
}
}
if (stop) {
mphal_i2c_stop(self);
}
return;
er:
mphal_i2c_stop(self);
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
STATIC int mphal_i2c_read_byte(pyb_i2c_obj_t *self, uint8_t *val) {
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
uint8_t dat = 0;
for (int i = 7; i >= 0; i--) {
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
dat = (dat << 1) | mphal_i2c_get_sda(self);
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
}
*val = dat;
mphal_i2c_wait_a();
mphal_i2c_set_scl(self, 1);
mphal_i2c_wait_a();
mphal_i2c_wait_b();
mphal_i2c_set_scl(self, 0);
mphal_i2c_wait_a();
return 1; // success
}
STATIC void mphal_i2c_read(pyb_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len, bool stop) {
mphal_i2c_start(self);
if (!mphal_i2c_write_byte(self, (addr << 1) | 1)) {
goto er;
}
while (len--) {
if (!mphal_i2c_read_byte(self, data++)) {
goto er;
}
}
if (stop) {
mphal_i2c_stop(self);
}
return;
er:
mphal_i2c_stop(self);
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
/******************************************************************************/
// MicroPython bindings for I2C
STATIC void pyb_i2c_obj_init_helper(pyb_i2c_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_scl, ARG_sda, ARG_freq };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
};
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);
self->scl = mp_obj_get_pin_obj(args[ARG_scl].u_obj);
self->sda = mp_obj_get_pin_obj(args[ARG_sda].u_obj);
mphal_i2c_init(self, args[ARG_freq].u_int);
}
STATIC mp_obj_t pyb_i2c_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, MP_OBJ_FUN_ARGS_MAX, true);
pyb_i2c_obj_t *self = m_new_obj(pyb_i2c_obj_t);
self->base.type = &pyb_i2c_type;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
pyb_i2c_obj_init_helper(self, n_args, args, &kw_args);
return (mp_obj_t)self;
}
STATIC mp_obj_t pyb_i2c_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_i2c_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_obj_init);
STATIC mp_obj_t pyb_i2c_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_n, ARG_stop };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
pyb_i2c_obj_t *self = 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);
// do the I2C transfer
vstr_t vstr;
vstr_init_len(&vstr, args[ARG_n].u_int);
mphal_i2c_read(self, args[ARG_addr].u_int, (uint8_t*)vstr.buf, vstr.len, args[ARG_stop].u_bool);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_obj, 1, pyb_i2c_readfrom);
STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_buf, ARG_stop };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
pyb_i2c_obj_t *self = 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);
// get the buffer to write from
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
// do the I2C transfer
mphal_i2c_write(self, args[ARG_addr].u_int, bufinfo.buf, bufinfo.len, args[ARG_stop].u_bool);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto);
STATIC const mp_rom_map_elem_t pyb_i2c_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_i2c_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&pyb_i2c_readfrom_obj) },
{ MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&pyb_i2c_writeto_obj) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table);
const mp_obj_type_t pyb_i2c_type = {
{ &mp_type_type },
.name = MP_QSTR_I2C,
.make_new = pyb_i2c_make_new,
.locals_dict = (mp_obj_dict_t*)&pyb_i2c_locals_dict,
};

View File

@@ -38,19 +38,12 @@
#define GPIO_MODE_INPUT (0)
#define GPIO_MODE_OUTPUT (1)
#define GPIO_MODE_OPEN_DRAIN (2) // synthesised
#define GPIO_PULL_NONE (0)
#define GPIO_PULL_UP (1)
// Removed in SDK 1.1.0
//#define GPIO_PULL_DOWN (2)
typedef struct _pyb_pin_obj_t {
mp_obj_base_t base;
uint16_t pin_id;
uint16_t phys_port;
uint32_t periph;
uint16_t func;
} pyb_pin_obj_t;
STATIC const pyb_pin_obj_t pyb_pin_obj[] = {
{{&pyb_pin_type}, 0, 0, PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0},
{{&pyb_pin_type}, 1, 1, PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1},
@@ -64,8 +57,75 @@ STATIC const pyb_pin_obj_t pyb_pin_obj[] = {
{{&pyb_pin_type}, 13, 13, PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13},
{{&pyb_pin_type}, 14, 14, PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14},
{{&pyb_pin_type}, 15, 15, PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15},
// GPIO16 is special, belongs to different register set, and
// otherwise handled specially.
{{&pyb_pin_type}, 16, 16, -1, -1},
};
STATIC uint8_t pin_mode[16 + 1];
pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) {
if (mp_obj_get_type(pin_in) != &pyb_pin_type) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting a pin"));
}
pyb_pin_obj_t *self = pin_in;
return self;
}
uint mp_obj_get_pin(mp_obj_t pin_in) {
return mp_obj_get_pin_obj(pin_in)->phys_port;
}
int pin_get(uint pin) {
if (pin == 16) {
return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1;
}
return GPIO_INPUT_GET(pin);
}
void pin_set(uint pin, int value) {
if (pin == 16) {
int out_en = (pin_mode[pin] == GPIO_MODE_OUTPUT);
WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | 1);
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | out_en);
WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1) | value);
return;
}
uint32_t enable = 0;
uint32_t disable = 0;
switch (pin_mode[pin]) {
case GPIO_MODE_INPUT:
value = -1;
disable = 1;
break;
case GPIO_MODE_OUTPUT:
enable = 1;
break;
case GPIO_MODE_OPEN_DRAIN:
if (value == -1) {
return;
} else if (value == 0) {
enable = 1;
} else {
value = -1;
disable = 1;
}
break;
}
enable <<= pin;
disable <<= pin;
if (value == -1) {
gpio_output_set(0, 0, enable, disable);
} else {
gpio_output_set(value << pin, (1 - value) << pin, enable, disable);
}
}
STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_pin_obj_t *self = self_in;
@@ -77,43 +137,59 @@ STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_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_mode, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_pull, MP_ARG_INT, {.u_int = GPIO_PULL_NONE}},
{ MP_QSTR_pull, MP_ARG_INT, {.u_int = GPIO_PULL_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);
struct {
mp_arg_val_t mode, pull, value;
} args;
mp_arg_parse_all(n_args, pos_args, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
// get io mode
uint mode = args[0].u_int;
uint mode = args.mode.u_int;
// get pull mode
uint pull = args[1].u_int;
uint pull = args.pull.u_int;
// get initial value
int value;
if (args.value.u_obj == MP_OBJ_NULL) {
value = -1;
} else {
value = mp_obj_is_true(args.value.u_obj);
}
// save the mode
pin_mode[self->phys_port] = mode;
// configure the GPIO as requested
PIN_FUNC_SELECT(self->periph, self->func);
#if 0
// Removed in SDK 1.1.0
if ((pull & GPIO_PULL_DOWN) == 0) {
PIN_PULLDWN_DIS(self->periph);
}
#endif
if ((pull & GPIO_PULL_UP) == 0) {
PIN_PULLUP_DIS(self->periph);
}
#if 0
if ((pull & GPIO_PULL_DOWN) != 0) {
PIN_PULLDWN_EN(self->periph);
}
#endif
if ((pull & GPIO_PULL_UP) != 0) {
PIN_PULLUP_EN(self->periph);
if (self->phys_port == 16) {
// TODO: Set pull up/pull down
} else {
PIN_FUNC_SELECT(self->periph, self->func);
#if 0
// Removed in SDK 1.1.0
if ((pull & GPIO_PULL_DOWN) == 0) {
PIN_PULLDWN_DIS(self->periph);
}
#endif
if ((pull & GPIO_PULL_UP) == 0) {
PIN_PULLUP_DIS(self->periph);
}
#if 0
if ((pull & GPIO_PULL_DOWN) != 0) {
PIN_PULLDWN_EN(self->periph);
}
#endif
if ((pull & GPIO_PULL_UP) != 0) {
PIN_PULLUP_EN(self->periph);
}
}
// TODO input mode is not working...
if ((mode & GPIO_MODE_OUTPUT) == 0) {
GPIO_DIS_OUTPUT(self->phys_port);
}
pin_set(self->phys_port, value);
return mp_const_none;
}
@@ -145,6 +221,20 @@ STATIC mp_obj_t pyb_pin_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp
return (mp_obj_t)pin;
}
// fast method for getting/setting pin value
STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
pyb_pin_obj_t *self = self_in;
if (n_args == 0) {
// get pin
return MP_OBJ_NEW_SMALL_INT(GPIO_INPUT_GET(self->phys_port));
} else {
// set pin
pin_set(self->phys_port, mp_obj_is_true(args[0]));
return mp_const_none;
}
}
// pin.init(mode, pull)
STATIC mp_obj_t pyb_pin_obj_init(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
return pyb_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args);
@@ -153,26 +243,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_init_obj, 1, pyb_pin_obj_init);
// pin.value([value])
STATIC mp_obj_t pyb_pin_value(mp_uint_t n_args, const mp_obj_t *args) {
pyb_pin_obj_t *self = args[0];
if (n_args == 1) {
// get pin
return MP_OBJ_NEW_SMALL_INT(GPIO_INPUT_GET(self->phys_port));
} else {
// set pin
if (mp_obj_is_true(args[1])) {
GPIO_OUTPUT_SET(self->phys_port, 1);
} else {
GPIO_OUTPUT_SET(self->phys_port, 0);
}
return mp_const_none;
}
return pyb_pin_call(args[0], n_args - 1, 0, args + 1);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pin_value_obj, 1, 2, pyb_pin_value);
// pin.low()
STATIC mp_obj_t pyb_pin_low(mp_obj_t self_in) {
pyb_pin_obj_t *self = self_in;
GPIO_OUTPUT_SET(self->phys_port, 0);
pin_set(self->phys_port, 0);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_low_obj, pyb_pin_low);
@@ -180,7 +258,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_low_obj, pyb_pin_low);
// pin.high()
STATIC mp_obj_t pyb_pin_high(mp_obj_t self_in) {
pyb_pin_obj_t *self = self_in;
GPIO_OUTPUT_SET(self->phys_port, 1);
pin_set(self->phys_port, 1);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_high_obj, pyb_pin_high);
@@ -194,7 +272,8 @@ STATIC const mp_map_elem_t pyb_pin_locals_dict_table[] = {
// class constants
{ MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_INPUT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OUT_PP), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OUT), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OPEN_DRAIN) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_NONE), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_NONE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_UP) },
//{ MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULL_DOWN) },
@@ -207,5 +286,6 @@ const mp_obj_type_t pyb_pin_type = {
.name = MP_QSTR_Pin,
.print = pyb_pin_print,
.make_new = pyb_pin_make_new,
.call = pyb_pin_call,
.locals_dict = (mp_obj_t)&pyb_pin_locals_dict,
};

172
esp8266/modpybpwm.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* 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 <stdint.h>
#include "esppwm.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "modpyb.h"
typedef struct _pyb_pwm_obj_t {
mp_obj_base_t base;
pyb_pin_obj_t *pin;
uint8_t active;
uint8_t channel;
} pyb_pwm_obj_t;
STATIC bool pwm_inited = false;
/******************************************************************************/
// MicroPython bindings for PWM
STATIC void pyb_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "PWM(%u", self->pin->pin_id);
if (self->active) {
mp_printf(print, ", freq=%u, duty=%u",
pwm_get_freq(self->channel), pwm_get_duty(self->channel));
}
mp_printf(print, ")");
}
STATIC void pyb_pwm_init_helper(pyb_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 = pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
if (channel == -1) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
"PWM not supported on pin %d", self->pin->phys_port));
}
self->channel = channel;
self->active = 1;
if (args[ARG_freq].u_int != -1) {
pwm_set_freq(args[ARG_freq].u_int, self->channel);
}
if (args[ARG_duty].u_int != -1) {
pwm_set_duty(args[ARG_duty].u_int, self->channel);
}
pwm_start();
}
STATIC mp_obj_t pyb_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);
pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]);
// create PWM object from the given pin
pyb_pwm_obj_t *self = m_new_obj(pyb_pwm_obj_t);
self->base.type = &pyb_pwm_type;
self->pin = pin;
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);
pyb_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t pyb_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pwm_init_obj, 1, pyb_pwm_init);
STATIC mp_obj_t pyb_pwm_deinit(mp_obj_t self_in) {
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
pwm_delete(self->channel);
self->active = 0;
pwm_start();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pwm_deinit_obj, pyb_pwm_deinit);
STATIC mp_obj_t pyb_pwm_freq(size_t n_args, const mp_obj_t *args) {
//pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args == 1) {
// get
return MP_OBJ_NEW_SMALL_INT(pwm_get_freq(0));
} else {
// set
pwm_set_freq(mp_obj_get_int(args[1]), 0);
pwm_start();
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_freq_obj, 1, 2, pyb_pwm_freq);
STATIC mp_obj_t pyb_pwm_duty(size_t n_args, const mp_obj_t *args) {
pyb_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (!self->active) {
pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
self->active = 1;
}
if (n_args == 1) {
// get
return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel));
} else {
// set
pwm_set_duty(mp_obj_get_int(args[1]), self->channel);
pwm_start();
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_pwm_duty_obj, 1, 2, pyb_pwm_duty);
STATIC const mp_rom_map_elem_t pyb_pwm_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pwm_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_pwm_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&pyb_pwm_freq_obj) },
{ MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&pyb_pwm_duty_obj) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_pwm_locals_dict, pyb_pwm_locals_dict_table);
const mp_obj_type_t pyb_pwm_type = {
{ &mp_type_type },
.name = MP_QSTR_PWM,
.print = pyb_pwm_print,
.make_new = pyb_pwm_make_new,
.locals_dict = (mp_obj_dict_t*)&pyb_pwm_locals_dict,
};

View File

@@ -49,6 +49,20 @@ typedef struct _pyb_rtc_obj_t {
// singleton RTC object
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
void mp_hal_rtc_init(void) {
uint32_t magic;
system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
if (magic != MEM_MAGIC) {
magic = MEM_MAGIC;
system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
uint32_t cal = system_rtc_clock_cali_proc();
int64_t delta = 0;
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
}
}
STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
@@ -58,7 +72,7 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp
}
STATIC uint64_t pyb_rtc_raw_us(uint64_t cal) {
return system_get_rtc_time() * ((cal >> 12) * 1000 + (cal & 0xfff) / 4) / 1000;
return (system_get_rtc_time() * cal) >> 12;
};
void pyb_rtc_set_us_since_2000(uint64_t nowus) {
@@ -146,7 +160,7 @@ STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
}
magic = MEM_MAGIC;
system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(len));
system_rtc_mem_write(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
len = bufinfo.len;
system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));

217
esp8266/modpybspi.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* 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 <errno.h>
#include "ets_sys.h"
#include "etshal.h"
#include "ets_alt_task.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "modpyb.h"
typedef struct _pyb_spi_obj_t {
mp_obj_base_t base;
uint32_t baudrate;
uint8_t polarity;
uint8_t phase;
pyb_pin_obj_t *sck;
pyb_pin_obj_t *mosi;
pyb_pin_obj_t *miso;
} pyb_spi_obj_t;
STATIC void mp_hal_spi_transfer(pyb_spi_obj_t *self, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) {
// only MSB transfer is implemented
uint32_t delay_half = 500000 / self->baudrate + 1;
for (size_t i = 0; i < src_len || i < dest_len; ++i) {
uint8_t data_out;
if (src_len == 1) {
data_out = src_buf[0];
} else {
data_out = src_buf[i];
}
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
pin_set(self->mosi->phys_port, (data_out >> 7) & 1);
if (self->phase == 0) {
ets_delay_us(delay_half);
pin_set(self->sck->phys_port, 1 - self->polarity);
} else {
pin_set(self->sck->phys_port, 1 - self->polarity);
ets_delay_us(delay_half);
}
data_in = (data_in << 1) | pin_get(self->miso->phys_port);
if (self->phase == 0) {
ets_delay_us(delay_half);
pin_set(self->sck->phys_port, self->polarity);
} else {
pin_set(self->sck->phys_port, self->polarity);
ets_delay_us(delay_half);
}
}
if (dest_len != 0) {
dest_buf[i] = data_in;
}
// make sure pending tasks have a chance to run
ets_loop_iter();
}
}
/******************************************************************************/
// MicroPython bindings for SPI
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SPI(baudrate=%u, polarity=%u, phase=%u, sck=%u, mosi=%u, miso=%u)",
self->baudrate, self->polarity, self->phase, self->sck->phys_port, self->mosi->phys_port, self->miso->phys_port);
}
STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_phase, 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);
if (args[ARG_baudrate].u_int != -1) {
self->baudrate = args[ARG_baudrate].u_int;
}
if (args[ARG_polarity].u_int != -1) {
self->polarity = args[ARG_polarity].u_int;
}
if (args[ARG_phase].u_int != -1) {
self->phase = args[ARG_phase].u_int;
}
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
self->sck = mp_obj_get_pin_obj(args[ARG_sck].u_obj);
}
if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
self->mosi = mp_obj_get_pin_obj(args[ARG_mosi].u_obj);
}
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
self->miso = mp_obj_get_pin_obj(args[ARG_miso].u_obj);
}
}
STATIC mp_obj_t pyb_spi_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, MP_OBJ_FUN_ARGS_MAX, true);
pyb_spi_obj_t *self = m_new_obj(pyb_spi_obj_t);
self->base.type = &pyb_spi_type;
// set defaults
self->baudrate = 500000;
self->polarity = 0;
self->phase = 0;
self->sck = NULL;
self->mosi = NULL;
self->miso = NULL;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
pyb_spi_init_helper(self, n_args, args, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_spi_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *args) {
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
uint8_t write_byte = 0;
if (n_args == 3) {
write_byte = mp_obj_get_int(args[2]);
}
vstr_t vstr;
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
mp_hal_spi_transfer(self, 1, &write_byte, vstr.len, (uint8_t*)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_read_obj, 2, 3, pyb_spi_read);
STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *args) {
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
uint8_t write_byte = 0;
if (n_args == 3) {
write_byte = mp_obj_get_int(args[2]);
}
mp_hal_spi_transfer(self, 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_readinto_obj, 2, 3, pyb_spi_readinto);
STATIC mp_obj_t pyb_spi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) {
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t src_buf;
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, 0, NULL);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write);
STATIC mp_obj_t pyb_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) {
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t src_buf;
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
mp_buffer_info_t dest_buf;
mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE);
if (src_buf.len != dest_buf.len) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length"));
}
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, dest_buf.len, (uint8_t*)dest_buf.buf);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto);
STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) },
};
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
const mp_obj_type_t pyb_spi_type = {
{ &mp_type_type },
.name = MP_QSTR_SPI,
.print = pyb_spi_print,
.make_new = pyb_spi_make_new,
.locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict,
};

157
esp8266/modpybuart.c Normal file
View File

@@ -0,0 +1,157 @@
/*
* 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 <errno.h>
#include "ets_sys.h"
#include "uart.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "modpyb.h"
typedef struct _pyb_uart_obj_t {
mp_obj_base_t base;
uint8_t uart_id;
} pyb_uart_obj_t;
/******************************************************************************/
// MicroPython bindings for UART
STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "UART(%u)", self->uart_id);
}
STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
/*
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_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);
*/
// not implemented
}
STATIC mp_obj_t pyb_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_id = mp_obj_get_int(args[0]);
if (uart_id != 0 && uart_id != 1) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "UART(%d) does not exist", uart_id));
}
// create instance
pyb_uart_obj_t *self = m_new_obj(pyb_uart_obj_t);
self->base.type = &pyb_uart_type;
self->uart_id = uart_id;
if (n_args > 1 || n_kw > 0) {
// init the peripheral
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);
}
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t pyb_uart_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
pyb_uart_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_init_obj, 1, pyb_uart_init);
STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_uart_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_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(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
mp_not_implemented("reading from UART");
}
STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
const byte *buf = buf_in;
/* TODO implement non-blocking
// wait to be able to write the first character
if (!uart_tx_wait(self, timeout)) {
*errcode = EAGAIN;
return MP_STREAM_ERROR;
}
*/
// write the data
for (size_t i = 0; i < size; ++i) {
uart_tx_one_char(self->uart_id, *buf++);
}
// return number of bytes written
return size;
}
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
*errcode = EINVAL;
return MP_STREAM_ERROR;
}
STATIC const mp_stream_p_t uart_stream_p = {
.read = pyb_uart_read,
.write = pyb_uart_write,
.ioctl = pyb_uart_ioctl,
.is_text = false,
};
const mp_obj_type_t pyb_uart_type = {
{ &mp_type_type },
.name = MP_QSTR_UART,
.print = pyb_uart_print,
.make_new = pyb_uart_make_new,
.getiter = mp_identity,
.iternext = mp_stream_unbuffered_iter,
.stream_p = &uart_stream_p,
.locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict,
};

View File

@@ -25,15 +25,21 @@
*/
#include <string.h>
#include <errno.h>
#include "py/mpconfig.h"
#include "py/nlr.h"
#include "py/obj.h"
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/runtime.h"
#include "extmod/misc.h"
#include "genhdr/mpversion.h"
#include "etshal.h"
#include "user_interface.h"
extern const mp_obj_type_t mp_fat_vfs_type;
STATIC const qstr os_uname_info_fields[] = {
MP_QSTR_sysname, MP_QSTR_nodename,
MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
@@ -65,9 +71,52 @@ STATIC mp_obj_t os_uname(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
STATIC const mp_map_elem_t os_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_uname), (mp_obj_t)&os_uname_obj },
#if MICROPY_VFS_FAT
mp_obj_t vfs_proxy_call(qstr method_name, mp_uint_t n_args, const mp_obj_t *args) {
if (MP_STATE_PORT(fs_user_mount)[0] == NULL) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENODEV)));
}
mp_obj_t meth[n_args + 2];
mp_load_method(MP_STATE_PORT(fs_user_mount)[0], method_name, meth);
memcpy(meth + 2, args, n_args * sizeof(*args));
return mp_call_method_n_kw(n_args, 0, meth);
}
STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) {
return vfs_proxy_call(MP_QSTR_listdir, n_args, args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);
STATIC mp_obj_t os_remove(mp_obj_t path_in) {
return vfs_proxy_call(MP_QSTR_remove, 1, &path_in);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);
#endif
STATIC mp_obj_t os_urandom(mp_obj_t num) {
mp_int_t n = mp_obj_get_int(num);
vstr_t vstr;
vstr_init_len(&vstr, n);
for (int i = 0; i < n; i++) {
vstr.buf[i] = *WDEV_HWRNG;
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
{ MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
{ MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
#if MICROPY_PY_OS_DUPTERM
{ MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
#endif
#if MICROPY_VFS_FAT
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
{ MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&os_listdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) },
#endif
};
STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);

View File

@@ -33,6 +33,7 @@
#include "py/gc.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/smallint.h"
#include "modpyb.h"
#include "modpybrtc.h"
#include "timeutils.h"
@@ -101,11 +102,51 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
/// \function sleep(seconds)
/// Sleep for the given number of seconds.
STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
#if MICROPY_PY_BUILTINS_FLOAT
mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o));
#else
mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));
#endif
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
mp_hal_delay_ms(mp_obj_get_int(arg));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms);
STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
mp_hal_delay_us(mp_obj_get_int(arg));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
STATIC mp_obj_t time_ticks_ms(void) {
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
STATIC mp_obj_t time_ticks_us(void) {
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
STATIC mp_obj_t time_ticks_cpu(void) {
// TODO
return MP_OBJ_NEW_SMALL_INT(0 & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) {
// we assume that the arguments come from ticks_xx so are small ints
uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff);
/// \function time()
/// Returns the number of seconds, as an integer, since 1/1/2000.
STATIC mp_obj_t time_time(void) {
@@ -120,6 +161,12 @@ STATIC const mp_map_elem_t time_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
};

View File

@@ -2,19 +2,23 @@
// options to control how Micro Python is built
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
#define MICROPY_ALLOC_PATH_MAX (128)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
#define MICROPY_MEM_STATS (0)
#define MICROPY_DEBUG_PRINTERS (0)
#define MICROPY_DEBUG_PRINTERS (1)
#define MICROPY_ENABLE_GC (1)
#define MICROPY_STACK_CHECK (0)
#define MICROPY_REPL_EVENT_DRIVEN (1)
#define MICROPY_STACK_CHECK (1)
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_HELPER_REPL (1)
#define MICROPY_HELPER_LEXER_UNIX (0)
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
@@ -25,19 +29,55 @@
#define MICROPY_PY___FILE__ (0)
#define MICROPY_PY_GC (1)
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_COLLECTIONS (1)
#define MICROPY_PY_MATH (0)
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (1)
#define MICROPY_PY_STRUCT (1)
#define MICROPY_PY_SYS (1)
#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_EXIT (1)
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_CPYTHON_COMPAT (0)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
#define MICROPY_PY_UBINASCII (1)
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_UHASHLIB (1)
#define MICROPY_PY_UHASHLIB_SHA1 (1)
#define MICROPY_PY_UHEAPQ (1)
#define MICROPY_PY_UJSON (1)
#define MICROPY_PY_URANDOM (1)
#define MICROPY_PY_URE (1)
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_LWIP (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_OS_DUPTERM (1)
#define MICROPY_CPYTHON_COMPAT (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
#define MICROPY_STREAMS_NON_BLOCK (1)
#define MICROPY_MODULE_FROZEN (1)
#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32
#define MICROPY_FATFS_ENABLE_LFN (1)
#define MICROPY_FATFS_RPATH (2)
#define MICROPY_FATFS_VOLUMES (2)
#define MICROPY_FATFS_MAX_SS (4096)
#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
#define MICROPY_FSUSERMOUNT (1)
#define MICROPY_VFS_FAT (1)
#define MICROPY_EVENT_POLL_HOOK {ets_event_poll();}
#define MICROPY_VM_HOOK_COUNT (10)
#define MICROPY_VM_HOOK_INIT static uint vm_hook_divisor = MICROPY_VM_HOOK_COUNT;
#define MICROPY_VM_HOOK_POLL if (--vm_hook_divisor == 0) { \
vm_hook_divisor = MICROPY_VM_HOOK_COUNT; \
extern void ets_loop_iter(void); \
ets_loop_iter(); \
}
#define MICROPY_VM_HOOK_LOOP MICROPY_VM_HOOK_POLL
#define MICROPY_VM_HOOK_RETURN MICROPY_VM_HOOK_POLL
// type definitions for the specific machine
@@ -45,6 +85,8 @@
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p)))
#define MP_SSIZE_MAX (0x7fffffff)
#define UINT_FMT "%u"
#define INT_FMT "%d"
@@ -53,6 +95,7 @@ typedef uint32_t mp_uint_t; // must be pointer size
typedef void *machine_ptr_t; // must be of pointer size
typedef const void *machine_const_ptr_t; // must be of pointer size
typedef long mp_off_t;
typedef uint32_t sys_prot_t; // for modlwip
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
@@ -67,26 +110,33 @@ extern const struct _mp_obj_module_t esp_module;
extern const struct _mp_obj_module_t network_module;
extern const struct _mp_obj_module_t utime_module;
extern const struct _mp_obj_module_t uos_module;
extern const struct _mp_obj_module_t mp_module_lwip;
extern const struct _mp_obj_module_t mp_module_machine;
extern const struct _mp_obj_module_t onewire_module;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_lwip), (mp_obj_t)&mp_module_lwip }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_lwip }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_lwip }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&network_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&utime_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&onewire_module }, \
#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&utime_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
#define MP_STATE_PORT MP_STATE_VM
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8]; \
\
/* Singleton instance of scan callback, meaning that there can
be only one concurrent AP scan. */ \
mp_obj_t scan_cb_obj; \
vstr_t *repl_line; \
mp_obj_t mp_kbd_exception; \
// We need to provide a declaration/definition of alloca()
#include <alloca.h>
@@ -97,3 +147,5 @@ extern const struct _mp_obj_module_t uos_module;
#define MICROPY_HW_BOARD_NAME "ESP module"
#define MICROPY_HW_MCU_NAME "ESP8266"
#define MICROPY_PY_SYS_PLATFORM "ESP8266"
#define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr))

View File

@@ -39,7 +39,6 @@ Q(elapsed_micros)
Q(delay)
Q(udelay)
Q(sync)
Q(hard_reset)
Q(unique_id)
// uos module
@@ -54,10 +53,12 @@ Q(machine)
Q(esp)
Q(socket)
Q(usocket)
Q(connect)
Q(disconnect)
Q(wifi_mode)
Q(phy_mode)
Q(osdebug)
Q(sleep_type)
Q(deepsleep)
Q(adc)
@@ -65,7 +66,11 @@ Q(vdd33)
Q(chip_id)
Q(flash_id)
Q(flash_read)
Q(flash_write)
Q(flash_erase)
Q(sdk_version)
Q(freemem)
Q(meminfo)
Q(getaddrinfo)
Q(send)
Q(sendto)
@@ -84,6 +89,7 @@ Q(onconnect)
Q(onrecv)
Q(onsent)
Q(ondisconnect)
Q(neopixel_write)
Q(MODE_11B)
Q(MODE_11G)
Q(MODE_11N)
@@ -97,16 +103,23 @@ Q(STA_AP_MODE)
// network module
Q(network)
Q(WLAN)
Q(active)
Q(scan)
Q(status)
Q(isconnected)
Q(mac)
Q(config)
Q(ifconfig)
Q(STA_IF)
Q(AP_IF)
Q(STAT_IDLE)
Q(STAT_CONNECTING)
Q(STAT_WRONG_PASSWORD)
Q(STAT_NO_AP_FOUND)
Q(STAT_CONNECT_FAIL)
Q(STAT_GOT_IP)
// config keys
Q(essid)
// Pin class
Q(Pin)
@@ -117,12 +130,19 @@ Q(value)
Q(low)
Q(high)
Q(IN)
Q(OUT_PP)
Q(OUT_OD)
Q(OUT)
Q(OPEN_DRAIN)
Q(PULL_NONE)
Q(PULL_UP)
Q(PULL_DOWN)
// PWM class
Q(PWM)
Q(init)
Q(deinit)
Q(freq)
Q(duty)
// RTC
Q(RTC)
Q(datetime)
@@ -132,9 +152,70 @@ Q(memory)
Q(ADC)
Q(read)
// UART
Q(UART)
Q(init)
// I2C
Q(I2C)
Q(init)
Q(scl)
Q(sda)
Q(freq)
Q(readfrom)
Q(writeto)
Q(stop)
Q(buf)
Q(addr)
Q(n)
// SPI
Q(SPI)
Q(init)
Q(baudrate)
Q(phase)
Q(polarity)
Q(sck)
Q(mosi)
Q(miso)
Q(read)
Q(readinto)
Q(write)
Q(write_readinto)
// utime
Q(utime)
Q(localtime)
Q(mktime)
Q(sleep)
Q(sleep_ms)
Q(sleep_us)
Q(ticks_ms)
Q(ticks_us)
Q(ticks_cpu)
Q(ticks_diff)
Q(time)
// machine
Q(reset)
Q(Timer)
Q(callback)
Q(deinit)
Q(init)
Q(mode)
Q(period)
Q(ONE_SHOT)
Q(PERIODIC)
// onewire
Q(_onewire)
Q(onewire)
Q(timings)
Q(reset)
Q(readbit)
Q(readbyte)
Q(writebit)
Q(writebyte)
Q(crc8)
Q(json)

64
esp8266/tests/neopixel.py Normal file
View File

@@ -0,0 +1,64 @@
import time
import machine
from esp import neopixel_write
class NeoPixel:
def __init__(self, pin, n):
self.pin = pin
self.n = n
self.buf = bytearray(n * 3)
def __setitem__(self, index, val):
r, g, b = val
self.buf[index * 3] = g
self.buf[index * 3 + 1] = r
self.buf[index * 3 + 2] = b
def __getitem__(self, index):
i = index * 3
return self.buf[i], self.buf[i + 1], self.buf[i + 2]
def write(self):
neopixel_write(self.pin, self.buf, True)
def test():
# put a neopixel strip on GPIO4
p = machine.Pin(4, machine.Pin.OUT)
np = NeoPixel(p, 8)
n = np.n
# cycle
for i in range(4 * n):
for j in range(n):
np[j] = (0, 0, 0)
np[i % n] = (255, 255, 255)
np.write()
time.sleep_ms(25)
# bounce
for i in range(4 * n):
for j in range(n):
np[j] = (0, 0, 128)
if (i // n) % 2 == 0:
np[i % n] = (0, 0, 0)
else:
np[n - 1 - (i % n)] = (0, 0, 0)
np.write()
time.sleep_ms(60)
# fade in/out
for i in range(0, 4 * 256, 8):
for j in range(n):
if (i // 256) % 2 == 0:
val = i & 0xff
else:
val = 255 - (i & 0xff)
np[j] = (val, 0, 0)
np.write()
# clear
for i in range(n):
np[i] = (0, 0, 0)
np.write()
test()

147
esp8266/tests/onewire.py Normal file
View File

@@ -0,0 +1,147 @@
import time
import pyb
import _onewire as _ow
class OneWire:
CMD_SEARCHROM = const(0xf0)
CMD_READROM = const(0x33)
CMD_MATCHROM = const(0x55)
CMD_SKIPROM = const(0xcc)
def __init__(self, pin):
self.pin = pin
self.pin.init(pin.OPEN_DRAIN, pin.PULL_NONE)
def reset(self):
return _ow.reset(self.pin)
def read_bit(self):
return _ow.readbit(self.pin)
def read_byte(self):
return _ow.readbyte(self.pin)
def read_bytes(self, count):
buf = bytearray(count)
for i in range(count):
buf[i] = _ow.readbyte(self.pin)
return buf
def write_bit(self, value):
return _ow.writebit(self.pin, value)
def write_byte(self, value):
return _ow.writebyte(self.pin, value)
def write_bytes(self, buf):
for b in buf:
_ow.writebyte(self.pin, b)
def select_rom(self, rom):
self.reset()
self.write_byte(CMD_MATCHROM)
self.write_bytes(rom)
def scan(self):
devices = []
diff = 65
rom = False
for i in range(0xff):
rom, diff = self._search_rom(rom, diff)
if rom:
devices += [rom]
if diff == 0:
break
return devices
def _search_rom(self, l_rom, diff):
if not self.reset():
return None, 0
self.write_byte(CMD_SEARCHROM)
if not l_rom:
l_rom = bytearray(8)
rom = bytearray(8)
next_diff = 0
i = 64
for byte in range(8):
r_b = 0
for bit in range(8):
b = self.read_bit()
if self.read_bit():
if b: # there are no devices or there is an error on the bus
return None, 0
else:
if not b: # collision, two devices with different bit meaning
if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i):
b = 1
next_diff = i
self.write_bit(b)
if b:
r_b |= 1 << bit
i -= 1
rom[byte] = r_b
return rom, next_diff
def crc8(self, data):
return _ow.crc8(data)
class DS18B20:
THERM_CMD_CONVERTTEMP = const(0x44)
THERM_CMD_RSCRATCHPAD = const(0xbe)
def __init__(self, onewire):
self.ow = onewire
self.roms = []
def scan(self):
self.roms = []
for rom in self.ow.scan():
if rom[0] == 0x28:
self.roms += [rom]
return self.roms
def start_measure(self):
if not self.ow.reset():
return False
self.ow.write_byte(CMD_SKIPROM)
self.ow.write_byte(THERM_CMD_CONVERTTEMP)
return True
def get_temp(self, rom):
if not self.ow.reset():
return None
self.ow.select_rom(rom)
self.ow.write_byte(THERM_CMD_RSCRATCHPAD)
buf = self.ow.read_bytes(9)
if self.ow.crc8(buf):
return None
return self._convert_temp(buf)
def _convert_temp(self, data):
temp_lsb = data[0]
temp_msb = data[1]
return (temp_msb << 8 | temp_lsb) / 16
# connect 1-wire temp sensors to GPIO12 for this test
def test():
dat = pyb.Pin(12)
ow = OneWire(dat)
ds = DS18B20(ow)
roms = ow.scan()
print('found devices:', roms)
for i in range(4):
print('temperatures:', end=' ')
ds.start_measure()
time.sleep_ms(750)
for rom in roms:
print(ds.get_temp(rom), end=' ')
print()
#pyb.freq(80000000)
#pyb.freq(160000000)
test()

View File

@@ -19,21 +19,33 @@
#include "user_interface.h"
#include "esp_mphal.h"
#define RX_BUF_SIZE (256)
#define UART_REPL UART0
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
// the uart to which OS messages go; -1 to disable
static int uart_os = UART_OS;
/* unused
// circular buffer for RX buffering
#define RX_BUF_SIZE (256)
static uint16_t rx_buf_in;
static uint16_t rx_buf_out;
static uint8_t rx_buf[RX_BUF_SIZE];
*/
#if MICROPY_REPL_EVENT_DRIVEN
static os_event_t uart_evt_queue[16];
#endif
static void uart0_rx_intr_handler(void *para);
void soft_reset(void);
void mp_keyboard_interrupt(void);
int interrupt_char;
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
@@ -83,9 +95,11 @@ static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
// enable rx_interrupt
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
/* unused
// init RX buffer
rx_buf_in = 0;
rx_buf_out = 0;
*/
}
/******************************************************************************
@@ -105,6 +119,15 @@ void uart_tx_one_char(uint8 uart, uint8 TxChar) {
WRITE_PERI_REG(UART_FIFO(uart), TxChar);
}
void uart_flush(uint8 uart) {
while (true) {
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) {
break;
}
}
}
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
@@ -114,15 +137,23 @@ void uart_tx_one_char(uint8 uart, uint8 TxChar) {
*******************************************************************************/
static void ICACHE_FLASH_ATTR
uart_os_write_char(char c) {
if (uart_os == -1) {
return;
}
if (c == '\n') {
uart_tx_one_char(UART_OS, '\r');
uart_tx_one_char(UART_OS, '\n');
uart_tx_one_char(uart_os, '\r');
uart_tx_one_char(uart_os, '\n');
} else if (c == '\r') {
} else {
uart_tx_one_char(UART_OS, c);
uart_tx_one_char(uart_os, c);
}
}
void ICACHE_FLASH_ATTR
uart_os_config(int uart) {
uart_os = uart;
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
@@ -150,7 +181,22 @@ static void uart0_rx_intr_handler(void *para) {
read_chars:
#if 1 //MICROPY_REPL_EVENT_DRIVEN is not available here
ETS_UART_INTR_DISABLE();
system_os_post(UART_TASK_ID, 0, 0);
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
if (RcvChar == interrupt_char) {
mp_keyboard_interrupt();
} else {
ringbuf_put(&input_buf, RcvChar);
}
}
mp_hal_signal_input();
// Clear pending FIFO interrupts
WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
ETS_UART_INTR_ENABLE();
#else
while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
@@ -164,6 +210,7 @@ static void uart0_rx_intr_handler(void *para) {
}
}
/* unused
int uart0_rx(void) {
if (rx_buf_out != rx_buf_in) {
int chr = rx_buf[rx_buf_out];
@@ -173,6 +220,7 @@ int uart0_rx(void) {
return -1;
}
}
*/
int uart_rx_one_char(uint8 uart_no) {
if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
@@ -196,7 +244,7 @@ void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
uart_config(UART1);
ETS_UART_INTR_ENABLE();
// install uart1 putc callback
// install handler for "os" messages
os_install_putc1((void *)uart_os_write_char);
}
@@ -209,22 +257,30 @@ void ICACHE_FLASH_ATTR uart_reattach() {
#include "py/obj.h"
#include "lib/utils/pyexec.h"
void soft_reset(void);
#if MICROPY_REPL_EVENT_DRIVEN
void uart_task_handler(os_event_t *evt) {
if (pyexec_repl_active) {
// TODO: Just returning here isn't exactly right.
// What really should be done is something like
// enquing delayed event to itself, for another
// chance to feed data to REPL. Otherwise, there
// can be situation when buffer has bunch of data,
// and sits unprocessed, because we consumed all
// processing signals like this.
return;
}
int c, ret = 0;
while ((c = uart_rx_one_char(UART_REPL)) >= 0) {
while ((c = ringbuf_get(&input_buf)) >= 0) {
if (c == interrupt_char) {
mp_keyboard_interrupt();
}
ret = pyexec_event_repl_process_char(c);
if (ret & PYEXEC_FORCED_EXIT) {
break;
}
}
// Clear pending FIFO interrupts
WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
// Enable UART interrupts, so our task will receive events again from IRQ handler
ETS_UART_INTR_ENABLE();
if (ret & PYEXEC_FORCED_EXIT) {
soft_reset();
}
@@ -233,3 +289,4 @@ void uart_task_handler(os_event_t *evt) {
void uart_task_init() {
system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue));
}
#endif

View File

@@ -92,5 +92,7 @@ typedef struct {
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
int uart0_rx(void);
void uart_tx_one_char(uint8 uart, uint8 TxChar);
void uart_flush(uint8 uart);
void uart_os_config(int uart);
#endif // _INCLUDED_UART_H_

View File

@@ -0,0 +1,28 @@
try:
import usocket as socket
except:
import socket
def main(use_stream=False):
s = socket.socket()
ai = socket.getaddrinfo("google.com", 80)
print("Address infos:", ai)
addr = ai[0][4]
print("Connect address:", addr)
s.connect(addr)
if use_stream:
# MicroPython socket objects support stream (aka file) interface
# directly, but the line below is needed for CPython.
s = s.makefile("rwb", 0)
s.write(b"GET / HTTP/1.0\n\n")
print(s.readall())
else:
s.send(b"GET / HTTP/1.0\n\n")
print(s.recv(4096))
main()

View File

@@ -0,0 +1,36 @@
try:
import usocket as _socket
except:
import _socket
try:
import ussl as ssl
except:
import ssl
def main(use_stream=True):
s = _socket.socket()
ai = _socket.getaddrinfo("google.com", 443)
print("Address infos:", ai)
addr = ai[0][4]
print("Connect address:", addr)
s.connect(addr)
s = ssl.wrap_socket(s)
print(s)
if use_stream:
# Both CPython and MicroPython SSLSocket objects support read() and
# write() methods.
s.write(b"GET / HTTP/1.0\n\n")
print(s.read(4096))
else:
# MicroPython SSLSocket objects implement only stream interface, not
# socket interface
s.send(b"GET / HTTP/1.0\n\n")
print(s.recv(4096))
main()

View File

@@ -0,0 +1,47 @@
try:
import usocket as socket
except:
import socket
CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d from MicroPython!
"""
def main(use_stream=False):
s = socket.socket()
# Binding to all interfaces - server will be accessible to other hosts!
ai = socket.getaddrinfo("0.0.0.0", 8080)
print("Bind address info:", ai)
addr = ai[0][4]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://<this_host>:8080/")
counter = 0
while True:
res = s.accept()
client_s = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_s)
print("Request:")
if use_stream:
# MicroPython socket objects support stream (aka file) interface
# directly.
print(client_s.read(4096))
client_s.write(CONTENT % counter)
else:
print(client_s.recv(4096))
client_s.send(CONTENT % counter)
client_s.close()
counter += 1
print()
main()

View File

@@ -1,32 +0,0 @@
try:
import usocket as _socket
except:
import _socket
s = _socket.socket()
if 1:
ai = _socket.getaddrinfo("google.com", 80)
print("Address infos:", ai)
addr = ai[0][4]
else:
# Deprecated ways to construct connection address
addr = _socket.sockaddr_in()
addr.sin_family = 2
#addr.sin_addr = (0x0100 << 16) + 0x007f
#addr.sin_addr = (0x7f00 << 16) + 0x0001
#addr.sin_addr = _socket.inet_aton("127.0.0.1")
addr.sin_addr = _socket.gethostbyname("google.com")
addr.sin_port = _socket.htons(80)
print("Connect address:", addr)
s.connect(addr)
if 0:
# MicroPython rawsocket module supports file interface directly
s.write("GET / HTTP/1.0\n\n")
print(s.readall())
else:
s.send(b"GET / HTTP/1.0\n\n")
print(s.recv(4096))

View File

@@ -1,41 +0,0 @@
try:
import usocket as socket
except:
import socket
CONTENT = """\
HTTP/1.0 200 OK
Hello #{} from MicroPython!
"""
s = socket.socket()
ai = socket.getaddrinfo("127.0.0.1", 8080)
print("Bind address info:", ai)
addr = ai[0][4]
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(5)
print("Listening, connect your browser to http://127.0.0.1:8080/")
counter = 0
while True:
res = s.accept()
client_s = res[0]
client_addr = res[1]
print("Client address:", client_addr)
print("Client socket:", client_s)
print("Request:")
if 0:
# MicroPython rawsocket module supports file interface directly
print(client_s.read(4096))
#print(client_s.readall())
client_s.write(CONTENT.format(counter))
else:
print(client_s.recv(4096))
client_s.send(bytes(CONTENT.format(counter), "ascii"))
client_s.close()
counter += 1

View File

@@ -26,13 +26,15 @@
#include "py/mpconfig.h"
#if MICROPY_FSUSERMOUNT
#include <string.h>
#include <errno.h>
#include "py/nlr.h"
#include "py/runtime.h"
#include "lib/fatfs/ff.h"
#include "fsusermount.h"
STATIC mp_obj_t pyb_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
@@ -51,67 +53,150 @@ STATIC mp_obj_t pyb_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *
if (device == mp_const_none) {
// umount
FRESULT res = FR_NO_FILESYSTEM;
if (MP_STATE_PORT(fs_user_mount) != NULL) {
res = f_mount(NULL, MP_STATE_PORT(fs_user_mount)->str, 0);
m_del_obj(fs_user_mount_t, MP_STATE_PORT(fs_user_mount));
MP_STATE_PORT(fs_user_mount) = NULL;
for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
if (vfs != NULL && !memcmp(mnt_str, vfs->str, mnt_len + 1)) {
res = f_mount(NULL, vfs->str, 0);
if (vfs->flags & FSUSER_FREE_OBJ) {
m_del_obj(fs_user_mount_t, vfs);
}
MP_STATE_PORT(fs_user_mount)[i] = NULL;
break;
}
}
if (res != FR_OK) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't umount"));
}
return NULL;
} else {
// mount
if (MP_STATE_PORT(fs_user_mount) != NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "device already mounted"));
size_t i = 0;
for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
if (MP_STATE_PORT(fs_user_mount)[i] == NULL) {
break;
}
}
if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "too many devices mounted"));
}
// create new object
MP_STATE_PORT(fs_user_mount) = m_new_obj(fs_user_mount_t);
MP_STATE_PORT(fs_user_mount)->str = mnt_str;
MP_STATE_PORT(fs_user_mount)->len = mnt_len;
fs_user_mount_t *vfs;
MP_STATE_PORT(fs_user_mount)[i] = vfs = m_new_obj(fs_user_mount_t);
vfs->str = mnt_str;
vfs->len = mnt_len;
vfs->flags = FSUSER_FREE_OBJ;
// load block protocol methods
mp_load_method(device, MP_QSTR_readblocks, MP_STATE_PORT(fs_user_mount)->readblocks);
mp_load_method_maybe(device, MP_QSTR_writeblocks, MP_STATE_PORT(fs_user_mount)->writeblocks);
mp_load_method_maybe(device, MP_QSTR_sync, MP_STATE_PORT(fs_user_mount)->sync);
mp_load_method(device, MP_QSTR_count, MP_STATE_PORT(fs_user_mount)->count);
mp_load_method(device, MP_QSTR_readblocks, vfs->readblocks);
mp_load_method_maybe(device, MP_QSTR_writeblocks, vfs->writeblocks);
mp_load_method_maybe(device, MP_QSTR_ioctl, vfs->u.ioctl);
if (vfs->u.ioctl[0] != MP_OBJ_NULL) {
// device supports new block protocol, so indicate it
vfs->flags |= FSUSER_HAVE_IOCTL;
} else {
// no ioctl method, so assume the device uses the old block protocol
mp_load_method_maybe(device, MP_QSTR_sync, vfs->u.old.sync);
mp_load_method(device, MP_QSTR_count, vfs->u.old.count);
}
// Read-only device indicated by writeblocks[0] == MP_OBJ_NULL.
// User can specify read-only device by:
// 1. readonly=True keyword argument
// 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)
if (args[0].u_bool) {
MP_STATE_PORT(fs_user_mount)->writeblocks[0] = MP_OBJ_NULL;
vfs->writeblocks[0] = MP_OBJ_NULL;
}
// mount the block device
FRESULT res = f_mount(&MP_STATE_PORT(fs_user_mount)->fatfs, MP_STATE_PORT(fs_user_mount)->str, 1);
// mount the block device (if mkfs, only pre-mount)
FRESULT res = f_mount(&vfs->fatfs, vfs->str, !mkfs);
// check the result
if (res == FR_OK) {
if (mkfs) {
goto mkfs;
}
} else if (res == FR_NO_FILESYSTEM && args[1].u_bool) {
res = f_mkfs(MP_STATE_PORT(fs_user_mount)->str, 1, 0);
mkfs:
res = f_mkfs(vfs->str, 1, 0);
if (res != FR_OK) {
mkfs_error:
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't mkfs"));
}
if (mkfs) {
// If requested to only mkfs, unmount pre-mounted device
res = f_mount(NULL, vfs->str, 0);
if (res != FR_OK) {
goto mkfs_error;
}
MP_STATE_PORT(fs_user_mount)[i] = NULL;
return NULL;
}
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't mount"));
}
/*
if (MP_STATE_PORT(fs_user_mount)->writeblocks[0] == MP_OBJ_NULL) {
if (vfs->writeblocks[0] == MP_OBJ_NULL) {
printf("mounted read-only");
} else {
printf("mounted read-write");
}
DWORD nclst;
FATFS *fatfs;
f_getfree(MP_STATE_PORT(fs_user_mount)->str, &nclst, &fatfs);
printf(" on %s with %u bytes free\n", MP_STATE_PORT(fs_user_mount)->str, (uint)(nclst * fatfs->csize * 512));
f_getfree(vfs->str, &nclst, &fatfs);
printf(" on %s with %u bytes free\n", vfs->str, (uint)(nclst * fatfs->csize * 512));
*/
return vfs;
}
}
STATIC mp_obj_t fatfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
fatfs_mount_mkfs(n_args, pos_args, kw_args, false);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount);
STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) {
size_t i = 0;
if (MP_OBJ_IS_STR(bdev_or_path_in)) {
mp_uint_t mnt_len;
const char *mnt_str = mp_obj_str_get_data(bdev_or_path_in, &mnt_len);
for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
if (vfs != NULL && !memcmp(mnt_str, vfs->str, mnt_len + 1)) {
break;
}
}
} else {
for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) {
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
if (vfs != NULL && bdev_or_path_in == vfs->readblocks[1]) {
break;
}
}
}
if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL)));
}
fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i];
FRESULT res = f_mount(NULL, vfs->str, 0);
if (vfs->flags & FSUSER_FREE_OBJ) {
m_del_obj(fs_user_mount_t, vfs);
}
MP_STATE_PORT(fs_user_mount)[i] = NULL;
if (res != FR_OK) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't umount"));
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_mount_obj, 2, pyb_mount);
MP_DEFINE_CONST_FUN_OBJ_1(fsuser_umount_obj, fatfs_umount);
STATIC mp_obj_t fatfs_mkfs(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
fatfs_mount_mkfs(n_args, pos_args, kw_args, true);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mkfs_obj, 2, fatfs_mkfs);
#endif // MICROPY_FSUSERMOUNT

View File

@@ -24,14 +24,38 @@
* THE SOFTWARE.
*/
// these are the values for fs_user_mount_t.flags
#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
// constants for block protocol ioctl
#define BP_IOCTL_INIT (1)
#define BP_IOCTL_DEINIT (2)
#define BP_IOCTL_SYNC (3)
#define BP_IOCTL_SEC_COUNT (4)
#define BP_IOCTL_SEC_SIZE (5)
typedef struct _fs_user_mount_t {
mp_obj_base_t base;
const char *str;
mp_uint_t len;
uint16_t len; // length of str
uint16_t flags;
mp_obj_t readblocks[4];
mp_obj_t writeblocks[4];
mp_obj_t sync[2];
mp_obj_t count[2];
// new protocol uses just ioctl, old uses sync (optional) and count
union {
mp_obj_t ioctl[4];
struct {
mp_obj_t sync[2];
mp_obj_t count[2];
} old;
} u;
FATFS fatfs;
} fs_user_mount_t;
MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj);
fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs);
MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj);
MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj);
MP_DECLARE_CONST_FUN_OBJ(fsuser_mkfs_obj);

View File

@@ -79,7 +79,7 @@ STATIC mp_obj_t machine_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t va
} else {
// store
uintptr_t addr = MICROPY_MACHINE_MEM_GET_WRITE_ADDR(index, self->elem_size);
uint32_t val = mp_obj_get_int(value);
uint32_t val = mp_obj_get_int_truncated(value);
switch (self->elem_size) {
case 1: (*(uint8_t*)addr) = val; break;
case 2: (*(uint16_t*)addr) = val; break;

View File

@@ -27,6 +27,7 @@
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "py/nlr.h"
#include "py/objlist.h"
@@ -43,6 +44,14 @@
//#include "lwip/raw.h"
#include "lwip/dns.h"
// For compatibilily with older lwIP versions.
#ifndef ip_set_option
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
#endif
#ifndef ip_reset_option
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#endif
#ifdef MICROPY_PY_LWIP_SLIP
#include "netif/slipif.h"
#include "lwip/sio.h"
@@ -152,6 +161,9 @@ STATIC const mp_obj_type_t lwip_slip_type = {
// 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
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
@@ -161,6 +173,28 @@ static const int error_lookup_table[] = {
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */
ECONNRESET, /* ERR_RST -9 Connection reset. */
ENOTCONN, /* ERR_CLSD -10 Connection closed. */
ENOTCONN, /* ERR_CONN -11 Not connected. */
EIO, /* ERR_ARG -12 Illegal argument. */
EADDRINUSE, /* ERR_USE -13 Address in use. */
-1, /* ERR_IF -14 Low-level netif error */
EALREADY, /* ERR_ISCONN -15 Already connected. */
EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
#else
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
ENOMEM, /* ERR_MEM -1 Out of memory error. */
ENOBUFS, /* ERR_BUF -2 Buffer error. */
EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
EINVAL, /* ERR_VAL -6 Illegal value. */
EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
EADDRINUSE, /* ERR_USE -8 Address in use. */
EALREADY, /* ERR_ISCONN -9 Already connected. */
ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
@@ -171,6 +205,7 @@ static const int error_lookup_table[] = {
-1, /* ERR_IF -15 Low-level netif error */
EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
#endif
/*******************************************************************************/
// The socket object provided by lwip.socket.
@@ -210,8 +245,11 @@ typedef struct _lwip_socket_obj_t {
} lwip_socket_obj_t;
static inline void poll_sockets(void) {
// TODO: Allow to override by ports
#ifdef MICROPY_EVENT_POLL_HOOK
MICROPY_EVENT_POLL_HOOK;
#else
mp_hal_delay_ms(1);
#endif
}
/*******************************************************************************/
@@ -250,9 +288,19 @@ STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
return ERR_OK;
}
// By default, a child socket of listen socket is created with recv
// handler which discards incoming pbuf's. We don't want to do that,
// so set this handler which requests lwIP to keep pbuf's and deliver
// them later. We cannot cache pbufs in child socket on Python side,
// until it is created in accept().
STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
return ERR_BUF;
}
// Callback for incoming tcp connections.
STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
tcp_recv(newpcb, _lwip_tcp_recv_unaccepted);
if (socket->incoming.connection != NULL) {
// We need to handle this better. This single-level structure makes the
@@ -280,19 +328,6 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
return ERR_OK;
}
STATIC uint8_t lwip_dns_returned;
STATIC uint8_t lwip_dns_result[4];
// Callback for incoming DNS requests. Just set our results.
STATIC void _lwip_dns_incoming(const char *name, ip_addr_t *addr, void *callback_arg) {
if (addr != NULL) {
lwip_dns_returned = 1;
memcpy(lwip_dns_result, addr, sizeof(lwip_dns_result));
} else {
lwip_dns_returned = 2;
}
}
/*******************************************************************************/
// Functions for socket send/recieve operations. Socket send/recv and friends call
// these to do the work.
@@ -347,7 +382,7 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
} else {
while (socket->incoming.pbuf == NULL) {
mp_hal_delay_ms(100);
poll_sockets();
}
}
}
@@ -369,6 +404,35 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
// Helper function for send/sendto to handle TCP packets
STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
u16_t available = tcp_sndbuf(socket->pcb.tcp);
if (available == 0) {
// Non-blocking socket
if (socket->timeout == 0) {
*_errno = EAGAIN;
return -1;
}
mp_uint_t start = mp_hal_ticks_ms();
// Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it
// sending direction, but not receiving. Consequently, check for both STATE_CONNECTED
// and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent.
// If peer fully closed socket, we would have socket->state set to ERR_RST (connection
// reset) by error callback.
// Avoid sending too small packets, so wait until at least 16 bytes available
while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = ETIMEDOUT;
return -1;
}
poll_sockets();
}
if (socket->state < 0) {
*_errno = error_lookup_table[-socket->state];
return -1;
}
}
u16_t write_len = MIN(available, len);
err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
@@ -383,20 +447,32 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
// Helper function for recv/recvfrom to handle TCP packets
STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
if (socket->state == STATE_PEER_CLOSED) {
return 0;
}
if (socket->incoming.pbuf == NULL) {
// Non-blocking socket
if (socket->timeout == 0) {
*_errno = EAGAIN;
return -1;
}
mp_uint_t start = mp_hal_ticks_ms();
while (socket->incoming.pbuf == NULL) {
while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) {
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = ETIMEDOUT;
return -1;
}
poll_sockets();
}
if (socket->state == STATE_PEER_CLOSED) {
if (socket->incoming.pbuf == NULL) {
// socket closed and no data left in buffer
return 0;
}
} else if (socket->state != STATE_CONNECTED) {
assert(socket->state < 0);
*_errno = error_lookup_table[-socket->state];
return -1;
}
}
struct pbuf *p = socket->incoming.pbuf;
@@ -424,8 +500,14 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
STATIC const mp_obj_type_t lwip_socket_type;
STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
lwip_socket_obj_t *self = self_in;
mp_printf(print, "<socket state=%d timeout=%d incoming=%p remaining=%d>", self->state, self->timeout,
self->incoming.pbuf, self->leftover_count);
}
// FIXME: Only supports two arguments at present
STATIC mp_obj_t lwip_socket_make_new(mp_obj_t type_in, mp_uint_t n_args,
STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args,
mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 4, false);
@@ -587,7 +669,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
}
} else {
while (socket->incoming.connection == NULL) {
mp_hal_delay_ms(100);
poll_sockets();
}
}
}
@@ -670,7 +752,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
}
} else {
while (socket->state == STATE_CONNECTING) {
mp_hal_delay_ms(100);
poll_sockets();
}
}
if (socket->state == STATE_CONNECTED) {
@@ -694,16 +776,20 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_connect_obj, lwip_socket_connect);
STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) {
if (socket->pcb.tcp == NULL) {
// not connected
int _errno = error_lookup_table[-socket->state];
socket->state = _ERR_BADF;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
}
}
STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->state)];
socket->state = _ERR_BADF;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
}
lwip_socket_check_connected(socket);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
@@ -731,12 +817,7 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->state)];
socket->state = _ERR_BADF;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
}
lwip_socket_check_connected(socket);
mp_int_t len = mp_obj_get_int(len_in);
vstr_t vstr;
@@ -769,12 +850,7 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->state)];
socket->state = _ERR_BADF;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
}
lwip_socket_check_connected(socket);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
@@ -805,12 +881,7 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->state)];
socket->state = _ERR_BADF;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
}
lwip_socket_check_connected(socket);
mp_int_t len = mp_obj_get_int(len_in);
vstr_t vstr;
@@ -864,6 +935,70 @@ STATIC mp_obj_t lwip_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_settimeout_obj, lwip_socket_settimeout);
STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
lwip_socket_obj_t *socket = self_in;
bool val = mp_obj_is_true(flag_in);
if (val) {
socket->timeout = -1;
} else {
socket->timeout = 0;
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking);
STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; // always 4
lwip_socket_obj_t *socket = args[0];
mp_int_t val = mp_obj_get_int(args[3]);
switch (mp_obj_get_int(args[2])) {
case SOF_REUSEADDR:
// Options are common for UDP and TCP pcb's.
if (val) {
ip_set_option(socket->pcb.tcp, SOF_REUSEADDR);
} else {
ip_reset_option(socket->pcb.tcp, SOF_REUSEADDR);
}
break;
default:
printf("Warning: lwip.setsockopt() not implemented\n");
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt);
STATIC mp_obj_t lwip_socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args;
return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_makefile_obj, 1, 3, lwip_socket_makefile);
STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
lwip_socket_obj_t *socket = self_in;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
return lwip_tcp_receive(socket, buf, size, errcode);
case MOD_NETWORK_SOCK_DGRAM:
return lwip_udp_receive(socket, buf, size, NULL, NULL, errcode);
}
// Unreachable
return MP_STREAM_ERROR;
}
STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
lwip_socket_obj_t *socket = self_in;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
return lwip_tcp_send(socket, buf, size, errcode);
case MOD_NETWORK_SOCK_DGRAM:
return lwip_udp_send(socket, buf, size, NULL, 0, errcode);
}
// Unreachable
return MP_STREAM_ERROR;
}
STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&lwip_socket_close_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&lwip_socket_close_obj },
@@ -876,13 +1011,27 @@ STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&lwip_socket_sendto_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&lwip_socket_recvfrom_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&lwip_socket_settimeout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&lwip_socket_setblocking_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&lwip_socket_setsockopt_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&lwip_socket_makefile_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
};
STATIC MP_DEFINE_CONST_DICT(lwip_socket_locals_dict, lwip_socket_locals_dict_table);
STATIC const mp_stream_p_t lwip_socket_stream_p = {
.read = lwip_socket_read,
.write = lwip_socket_write,
};
STATIC const mp_obj_type_t lwip_socket_type = {
{ &mp_type_type },
.name = MP_QSTR_socket,
.print = lwip_socket_print,
.make_new = lwip_socket_make_new,
.stream_p = &lwip_socket_stream_p,
.locals_dict = (mp_obj_t)&lwip_socket_locals_dict,
};
@@ -937,41 +1086,59 @@ STATIC mp_obj_t mod_lwip_callback() {
}
MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_callback_obj, mod_lwip_callback);
typedef struct _getaddrinfo_state_t {
volatile int status;
volatile ip_addr_t ipaddr;
} getaddrinfo_state_t;
// Callback for incoming DNS requests.
STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
getaddrinfo_state_t *state = arg;
if (ipaddr != NULL) {
state->status = 1;
state->ipaddr = *ipaddr;
} else {
// error
state->status = -2;
}
}
// lwip.getaddrinfo
STATIC mp_obj_t lwip_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
mp_uint_t hlen;
const char *host = mp_obj_str_get_data(host_in, &hlen);
mp_int_t port = mp_obj_get_int(port_in);
ip_addr_t result;
lwip_dns_returned = 0;
getaddrinfo_state_t state;
state.status = 0;
switch (dns_gethostbyname(host, &result, _lwip_dns_incoming, NULL)) {
case ERR_OK: {
break;
}
case ERR_INPROGRESS: {
while(!lwip_dns_returned) {
mp_hal_delay_ms(100);
}
if (lwip_dns_returned == 2) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOENT)));
err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state);
switch (ret) {
case ERR_OK:
// cached
state.status = 1;
break;
case ERR_INPROGRESS:
while (state.status == 0) {
poll_sockets();
}
break;
}
default: {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOENT)));
}
default:
state.status = ret;
}
if (state.status < 0) {
// TODO: CPython raises gaierror, we raise with native lwIP negative error
// values, to differentiate from normal errno's at least in such way.
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(state.status)));
}
uint8_t out_ip[NETUTILS_IPV4ADDR_BUFSIZE];
memcpy(out_ip, lwip_dns_result, sizeof(lwip_dns_result));
mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
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_2(lwip_getaddrinfo_obj, lwip_getaddrinfo);
@@ -995,6 +1162,9 @@ STATIC const mp_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_DGRAM) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_RAW) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOL_SOCKET), MP_OBJ_NEW_SMALL_INT(1) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SO_REUSEADDR), MP_OBJ_NEW_SMALL_INT(SOF_REUSEADDR) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);

View File

@@ -281,18 +281,15 @@ STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_sizeof_obj, uctypes_struct_sizeof);
STATIC inline mp_obj_t get_unaligned(uint val_type, void *p, int big_endian) {
mp_int_t val = mp_binary_get_int(GET_SCALAR_SIZE(val_type), val_type & 1, big_endian, p);
if (val_type == UINT32) {
return mp_obj_new_int_from_uint(val);
} else {
return mp_obj_new_int(val);
}
STATIC inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
char struct_type = big_endian ? '>' : '<';
static const char type2char[16] = "BbHhIiQq------fd";
return mp_binary_get_val(struct_type, type2char[val_type], &p);
}
STATIC inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
char struct_type = big_endian ? '>' : '<';
static const char type2char[8] = "BbHhIiQq";
static const char type2char[16] = "BbHhIiQq------fd";
mp_binary_set_val(struct_type, type2char[val_type], val, &p);
}
@@ -352,6 +349,17 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
}
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
#if MICROPY_PY_BUILTINS_FLOAT
if (val_type == FLOAT32 || val_type == FLOAT64) {
mp_float_t v = mp_obj_get_float(val);
if (val_type == FLOAT32) {
((float*)p)[index] = v;
} else {
((double*)p)[index] = v;
}
return;
}
#endif
mp_int_t v = mp_obj_get_int(val);
switch (val_type) {
case UINT8:
@@ -395,7 +403,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
offset &= VALUE_MASK(VAL_TYPE_BITS);
//printf("scalar type=%d offset=%x\n", val_type, offset);
if (val_type <= INT64) {
if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) {
// printf("size=%d\n", GET_SCALAR_SIZE(val_type));
if (self->flags == LAYOUT_NATIVE) {
if (set_val == MP_OBJ_NULL) {
@@ -689,6 +697,11 @@ STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) },
{ MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) },
#if MICROPY_PY_BUILTINS_FLOAT
{ MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) },
{ MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) },
#endif
{ MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) },
{ MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) },
};

View File

@@ -92,7 +92,7 @@ STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
mp_printf(print, "<re %p>", self);
}
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
(void)n_args;
mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
Subject subj;
@@ -116,12 +116,12 @@ STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
}
STATIC mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {
return re_exec(true, n_args, args);
return ure_exec(true, n_args, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
STATIC mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {
return re_exec(false, n_args, args);
return ure_exec(false, n_args, args);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
@@ -211,7 +211,7 @@ STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args)
mp_obj_t self = mod_re_compile(1, args);
const mp_obj_t args2[] = {self, args[1]};
mp_obj_t match = re_exec(is_anchored, 2, args2);
mp_obj_t match = ure_exec(is_anchored, 2, args2);
return match;
}

266
extmod/modwebsocket.c Normal file
View File

@@ -0,0 +1,266 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "py/nlr.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "extmod/modwebsocket.h"
#if MICROPY_PY_WEBSOCKET
enum { FRAME_HEADER, FRAME_OPT, PAYLOAD };
enum { BLOCKING_WRITE = 0x80 };
typedef struct _mp_obj_websocket_t {
mp_obj_base_t base;
mp_obj_t sock;
uint32_t msg_sz;
byte mask[4];
byte state;
byte to_recv;
byte mask_pos;
byte buf_pos;
byte buf[6];
byte opts;
// Copy of current frame's flags
byte ws_flags;
} mp_obj_websocket_t;
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_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t);
o->base.type = type;
o->sock = args[0];
o->state = FRAME_HEADER;
o->to_recv = 2;
o->mask_pos = 0;
o->buf_pos = 0;
o->opts = FRAME_TXT;
if (n_args > 1 && args[1] == mp_const_true) {
o->opts |= BLOCKING_WRITE;
}
return o;
}
STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_websocket_t *self = self_in;
const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
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);
if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
return out_sz;
}
self->buf_pos += out_sz;
self->to_recv -= out_sz;
if (self->to_recv != 0) {
*errcode = EAGAIN;
return MP_STREAM_ERROR;
}
}
switch (self->state) {
case FRAME_HEADER: {
// TODO: Split frame handling below is untested so far, so conservatively disable it
assert(self->buf[0] & 0x80);
// "Control frames MAY be injected in the middle of a fragmented message."
// So, they must be processed before data frames (and not alter
// self->ws_flags)
if ((self->buf[0] & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {
// TODO: implement
assert(0);
}
if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {
// Preserve previous frame type
self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);
} else {
self->ws_flags = self->buf[0];
}
// Reset mask in case someone will use "simplified" protocol
// without masks.
memset(self->mask, 0, sizeof(self->mask));
int to_recv = 0;
size_t sz = self->buf[1] & 0x7f;
if (sz == 126) {
// Msg size is next 2 bytes
to_recv += 2;
} else if (sz == 127) {
// Msg size is next 2 bytes
assert(0);
}
if (self->buf[1] & 0x80) {
// Next 4 bytes is mask
to_recv += 4;
}
self->buf_pos = 0;
self->to_recv = to_recv;
self->msg_sz = sz; // May be overriden by FRAME_OPT
if (to_recv != 0) {
self->state = FRAME_OPT;
} else {
self->state = PAYLOAD;
}
continue;
}
case FRAME_OPT: {
if ((self->buf_pos & 3) == 2) {
// First two bytes are message length
self->msg_sz = (self->buf[0] << 8) | self->buf[1];
}
if (self->buf_pos >= 4) {
// Last 4 bytes is mask
memcpy(self->mask, self->buf + self->buf_pos - 4, 4);
}
self->buf_pos = 0;
self->state = PAYLOAD;
continue;
}
case PAYLOAD: {
size_t sz = MIN(size, self->msg_sz);
mp_uint_t out_sz = stream_p->read(self->sock, buf, sz, errcode);
if (out_sz == MP_STREAM_ERROR) {
return out_sz;
}
sz = out_sz;
for (byte *p = buf; sz--; p++) {
*p ^= self->mask[self->mask_pos++ & 3];
}
self->msg_sz -= out_sz;
if (self->msg_sz == 0) {
self->state = FRAME_HEADER;
self->to_recv = 2;
self->mask_pos = 0;
self->buf_pos = 0;
}
return out_sz;
}
}
}
}
STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_websocket_t *self = self_in;
assert(size < 0x10000);
byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)};
int hdr_sz;
if (size < 126) {
header[1] = size;
hdr_sz = 2;
} else {
header[1] = 126;
header[2] = size >> 8;
header[3] = size & 0xff;
hdr_sz = 4;
}
mp_obj_t dest[3];
if (self->opts & BLOCKING_WRITE) {
mp_load_method(self->sock, MP_QSTR_setblocking, dest);
dest[2] = mp_const_true;
mp_call_method_n_kw(1, 0, dest);
}
mp_uint_t out_sz = mp_stream_writeall(self->sock, header, hdr_sz, errcode);
if (out_sz != MP_STREAM_ERROR) {
out_sz = mp_stream_writeall(self->sock, buf, size, errcode);
}
if (self->opts & BLOCKING_WRITE) {
dest[2] = mp_const_false;
mp_call_method_n_kw(1, 0, dest);
}
return out_sz;
}
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_GET_DATA_OPTS:
return self->ws_flags & FRAME_OPCODE_MASK;
case MP_STREAM_SET_DATA_OPTS: {
int cur = self->opts & FRAME_OPCODE_MASK;
self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK);
return cur;
}
default:
*errcode = EINVAL;
return MP_STREAM_ERROR;
}
}
STATIC const mp_map_elem_t websocket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&mp_stream_ioctl_obj },
};
STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);
STATIC const mp_stream_p_t websocket_stream_p = {
.read = websocket_read,
.write = websocket_write,
.ioctl = websocket_ioctl,
};
STATIC const mp_obj_type_t websocket_type = {
{ &mp_type_type },
.name = MP_QSTR_websocket,
.make_new = websocket_make_new,
.stream_p = &websocket_stream_p,
.locals_dict = (mp_obj_t)&websocket_locals_dict,
};
STATIC const mp_map_elem_t websocket_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_websocket) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_websocket), (mp_obj_t)&websocket_type },
};
STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table);
const mp_obj_module_t mp_module_websocket = {
.base = { &mp_type_module },
.name = MP_QSTR_websocket,
.globals = (mp_obj_dict_t*)&websocket_module_globals,
};
#endif // MICROPY_PY_WEBSOCKET

5
extmod/modwebsocket.h Normal file
View File

@@ -0,0 +1,5 @@
#define FRAME_OPCODE_MASK 0x0f
enum {
FRAME_CONT, FRAME_TXT, FRAME_BIN,
FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG
};

View File

@@ -458,6 +458,7 @@ int tinf_uncompress(void *dest, unsigned int *destLen,
d.destStart = (unsigned char *)dest;
d.destRemaining = *destLen;
d.destSize = *destLen;
res = tinf_uncompress_dyn(&d);

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