summaryrefslogtreecommitdiffstatshomepage
path: root/esp8266
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-08-13 21:33:40 +1000
committerDamien George <damien.p.george@gmail.com>2017-08-13 21:33:40 +1000
commite52758da223e57b6cd9458f039f8ccc50ee76ddb (patch)
tree2d5218ad0e1f30c686f51f5807b5676fe0007fe5 /esp8266
parentbe2387885bf251fb44b6b64aeadff147a4ae7266 (diff)
parent9b39263b118a4be65c58bf9c396203fa535bebe1 (diff)
downloadmicropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.tar.gz
micropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.zip
Merge tag 'v1.8.1' into parse-bytecode
Many ESP8266 improvements, enhanced WebREPL, and support for STM32L4 MCUs This release brings general improvements and bug fixes, and some new features. There is now a uerror module for consistent errno handling across ports, as well as textual names of OS errors that are printed when an OSError is raised. There is support for frozen packages, via both frozen scripts and frozen bytecode. WebREPL on the ESP8266 is greatly improved with many bug fixes and now supports an unlimited (or very large) number of reconnects. The os module on the ESP8266 now has rename, chdir, getcwd and stat. The unix port now includes the ussl module by default. The stmhal port has support for STM32L4 MCUs including the STM32L476 Discovery board and the LimiFrog board. README: - add explicit note that subdirs contain more READMEs - add "make deplibs" to quick build section - "quick build": Use "make axtls" after all CODECONVENTIONS.md: - describe git commit messages conventions py core: - obj: add warning note about get_array return value and GC blocks - objstr: binary type of str/bytes for buffer protocol is 'B' - runtime: properly handle passing user mappings to ** keyword args - repl: if there're no better alternatives, try to complete "import" - mpz: fix bug with overflowing C-shift in division routine - mpz: do Python style division/modulo within bignum divmod routine - mpz: fix mpn_div so that it doesn't modify memory of denominator - vstr: vstr_null_terminated_str(): Extend string by at most one byte - vstr: change allocation policy, +16 to requested size, instead of *2 - add mperrno.h file with uPy defined errno constants - add uerrno module, with errno constants and dict - parse: add uerrno to list of modules to look for constants in - mperrno: add EAFNOSUPPORT definition - repl: fix handling of backslash in quotes when checking continuation - gc: gc_dump_alloc_table(): Show byte/str and (byte)array objects - gc: make (byte)array type dumping conditional on these types being enabled - gc: use '=' char for tail blocks when dumping heap - mperrno: add some more MP_Exxx constants, related to networking - moduerrno: add more constants to the errno module - add mp_errno_to_str() and use it to provide nicer OSError msgs - objfloat, py/modmath: ensure M_PI and M_E defined - emitglue: fix build on AArch64 (ARMv8, etc.) related to loading .mpy files - objexcept: don't convert errno to str in constructor, do it in print - moduerrno: add EACCES, pretty common error on Unix - gc: gc_dump_alloc_table(): dump heap offset instead of actual address - objstr: make dedicated splitlines function, supporting diff newlines - objstringio: add TODO comment about avoiding copying on .getvalue() - modstruct: raise ValueError on unsupported format char - stream: support both "exact size" and "one underlying call" operations - declare constant data as properly constant - stream: add mp_stream_close() helper function - mphal.h: provide default prototypes for mp_hal_delay_us/mp_hal_ticks_us - rework frozen modules support to support packages - objstr: implement str.center() - allow to stat and import frozen mpy files using new frozen "VFS" - makeqstrdata.py: allow to have double-quote characters in qstrs - objnamedtuple: allow passing field names as a tuple - moduerrno: add EEXIST, EISDIR, ECONNREFUSED - modstruct: allow to have "0s" in struct format extmod: - modlwip: convert errno's to use MP_Exxx symbols - modlwip: rework how Python accept callback is called - when including extmod headers, prefix path with extmod/ - modwebsocket: add close() method - modwebrepl: add close() method - moduos_dupterm: dumpterm subsystem is responsible for closing stream - modussl: make more compatible with non-default obj representations - machine_i2c: redo mp_hal_pin macros to use open_drain and od_low - virtpin: initial implementation of open-ended C-level Pin interface - vfs_fat: replace text error messages by POSIX error numbers - vfs_fat: add chdir() method - vfs_fat: add getcwd() method - vfs_fat: add vfs.stat() method - add machine time_pulse_us function (at C and Python level) - machine: add MICROPY_PY_MACHINE_PULSE config for time_pulse_us lib: - timeutils/timeutils: timeutils_mktime may accept negative time values drivers: - cc3000: rename timeval to cc3000_timeval, to avoid clash - add C-level function to read DHT11 and DHT22 devices - display/ssd1306: update SSD1306_SPI to work with new API tools: - make-frozen.py: properly escape hex chars when making C strings - make-frozen.py: quick fix to support package-modules - mpy-tool.py: add checks for critical configuration vars - make-frozen.py: update for latest changes in frozen modules support - mpy-tool.py: include .py extension in frozen filename - mpy-tool.py: don't strip directories from the frozen source name - upgrade upip to 0.7: SSL cert warning, use uerrno, better usage message tests: - run-tests: factor out list of supported external boards - disable memoryview tests that overflow int conversion - basics/string_splitlines: reinstate feature test for splitlines - struct1: add testcase for an unknown type char - add testcase for str.center() - extmod/vfs_fat_ramdisk: add testcases for chdir(), getcwd() - misc/recursive_iternext.py: increase depth N from 1000 to 2000 - misc/recursive_iternext.py: provide more fine-grained selection of N - pyb/rtc: make RTC test on pyboard more reliable by calling init() mpy-cross: - add -s option to specify the embedded source filename unix port: - mphalport: add mp_hal_delay_us() for consistency with other ports - enable uerrno module - add ability to include frozen bytecode in the build - mpconfigport_coverage.h: add dedicated config file for coverage build - unix_mphal: implement mp_hal_ticks_us() - support frozen packages - Makefile: nanbox build is not compatible with modussl, disable - enable "ussl" module - mpconfigport.mk: document MICROPY_STANDALONE make-level option - Makefile: "make axtls": automatically fetch submodules if missing windows port: - enable multi-processor compilation for msvc stmhal port: - l4: adapt DMA to be able to support STM32L4 MCU series - l4: adapt startup code, clock configuration and interrupts - l4: make CCM/DTCM RAM start-up conditional on MCU type - l4: add support for machine.sleep on STM32L4 MCUs - dma: make DAC DMA descriptors conditional on having a DAC - add board files for LIMIFROG board - for LIMIFROG board, add early-init function to get to DFU mode - dma: fix builds for boards with an F4 or F7 but no DAC - sdcard: fix initialisation of DMA TX so that writes work - can: allow to get existing CAN obj if constructed without args - fix clock configuration for STM32L476-discovery; also add I2C2 - convert to use internal errno symbols; enable uerrno module - for network drivers, convert to use MP_Exxx errno symbols - led: allow LEDs to be in PWM mode with TIM1 and channels 1-4 - i2c: expose I2CHandle3 for use by custom C code - sdcard: allow to do unaligned read-from/write-to SD card - support frozen packages using .mpy files - moduos: getcwd(): use mp_obj_new_exception_arg1() - dac: add DAC deinit() method - uart: fix wrong baudrate calculation for stm32l4 series esp8266 port: - scripts/: remove use of pin.PULL_NONE - scripts/inisetup: don't start WebREPL on boot in master branch - scripts/: add fill() to NeoPixel - scripts/webrepl: add optional password argument to webrepl.start() - scripts/webrepl: add start_foreground() method - main: bump heap size to 28K - mpconfigport: reduce various parser-related allocation params - help: add "sta_if.active(True)" command - convert to use new MP_Exxx errno symbols - enable uerrno module, weak linked also as errno - change to use internal errno's - moduos.c: addition of the rename method to module uos - scripts/port_diag: add network diagnostic output - scripts/webrepl_setup: show password placeholder char - scripts/webrepl_setup: add max password length check - README: add a very first start section - add APA102 serial individually controllable LEDs support - enable collections.OrderedDict - main: update _boot module loading for recent frozen modules refactors - scripts/port_diag: dump network interface IP settings - esp_mphal: fix NLR buffer leak in call_dupterm_read() - esp_mphal: handle Ctrl+C from dupterm (e.g. WebREPL) - esp_mphal: mp_uos_dupterm_deactivate() may raise exception - add mp_hal_pin_input() and mp_hal_pin_output() functions - modpybspi: configure pins when initialising an SPI object - xtirq: add xtirq.h for controlling xtensa irqs - ets_alt_task: don't run ets_loop_iter if irqs are disabled - modmachine: add disable_irq and enable_irq functions - enable DHT C-level driver - add dht.py script for high-level control of DHT11/DHT22 sensor - Makefile: document "disable" value for UART_OS - modnetwork: scan() is only supported by STA when it's enabled - modnetwork: protect scan() callback against memory errors - modnetwork: allow to press ctrl-C while scan() is running - uart: properly initialise UART0 RXD pin in uart_config - moduos: add chdir() and getcwd() functions - scripts/ntptime: allow to override NTP server - modmachine: add machine.time_pulse_us function - enable MICROPY_PY_IO_FILEIO to get compliant text/binary streams - moduos.c: add stat() to the module uos of esp8266 - rtc: set RTC user memory length to 0 on first boot - provide a dedicated variable to disable ets_loop_iter - modpybrtc: handle RTC overflow docs: - machine.UART: filter out unimplemented UART methods from esp8266 docs - esp8266/quickref: new way to get MAC address - esp8266/quickstart: remove i2c examples with stop=False - ustruct: describe supported type codes - ussl: add basic description of axTLS-based modussl - esp8266: Include ussl module in the docs - machine: make disable_irq and enable_irq docs available for all - library/machine: add documentation for machine.time_pulse_us - math, cmath: add port availability information - library/index: add intro paragraph regarding availability of modules - README: add some hints for PDF docs generation - wipy/tutorial: add note about screen key bindings on OS X - esp8266/quickref: update WebREPL section for 1.8.1 release - esp8266: fix ESP8266 Network tutorial - esp8266/quickref: use local image of Adafruit Huzzah board - esp8266/general: add note about RTC overflow travis: - install gcc-arm-none-eabi with --force-yes for now
Diffstat (limited to 'esp8266')
-rw-r--r--esp8266/Makefile10
-rw-r--r--esp8266/README.md28
-rw-r--r--esp8266/esp_mphal.c15
-rw-r--r--esp8266/esp_mphal.h13
-rw-r--r--esp8266/espapa102.c110
-rw-r--r--esp8266/espapa102.h27
-rw-r--r--esp8266/ets_alt_task.c6
-rw-r--r--esp8266/ets_alt_task.h1
-rw-r--r--esp8266/help.c2
-rw-r--r--esp8266/main.c4
-rw-r--r--esp8266/modesp.c22
-rw-r--r--esp8266/modmachine.c26
-rw-r--r--esp8266/modnetwork.c47
-rw-r--r--esp8266/modpybpin.c29
-rw-r--r--esp8266/modpybrtc.c40
-rw-r--r--esp8266/modpybspi.c7
-rw-r--r--esp8266/modpybuart.c6
-rw-r--r--esp8266/moduos.c36
-rw-r--r--esp8266/mpconfigport.h14
-rw-r--r--esp8266/scripts/apa102.py28
-rw-r--r--esp8266/scripts/dht.py32
-rw-r--r--esp8266/scripts/inisetup.py4
-rw-r--r--esp8266/scripts/neopixel.py9
-rw-r--r--esp8266/scripts/ntptime.py4
-rw-r--r--esp8266/scripts/onewire.py2
-rw-r--r--esp8266/scripts/port_diag.py12
-rw-r--r--esp8266/scripts/webrepl.py33
-rw-r--r--esp8266/scripts/webrepl_setup.py5
-rw-r--r--esp8266/uart.c5
-rw-r--r--esp8266/xtirq.h60
30 files changed, 568 insertions, 69 deletions
diff --git a/esp8266/Makefile b/esp8266/Makefile
index d8786301a8..65093d819b 100644
--- a/esp8266/Makefile
+++ b/esp8266/Makefile
@@ -26,7 +26,7 @@ INC += -I$(BUILD)
INC += -I$(ESP_SDK)/include
# UART for "os" messages. 0 is normal UART as used by MicroPython REPL,
-# 1 is debug UART (tx only).
+# 1 is debug UART (tx only), -1 to disable.
UART_OS = 0
CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \
@@ -65,6 +65,7 @@ SRC_C = \
esppwm.c \
esponewire.c \
espneopixel.c \
+ espapa102.c \
intr.c \
modpyb.c \
modpybpin.c \
@@ -123,6 +124,10 @@ LIB_SRC_C = $(addprefix lib/,\
fatfs/option/ccsbcs.c \
)
+DRIVERS_SRC_C = $(addprefix drivers/,\
+ dht/dht.c \
+ )
+
SRC_S = \
gchelper.s \
@@ -133,10 +138,11 @@ 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 += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
#OBJ += $(BUILD)/pins_$(BOARD).o
# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(EXTMOD_SRC_C)
+SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C)
# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
SRC_QSTR_AUTO_DEPS +=
diff --git a/esp8266/README.md b/esp8266/README.md
index e187d4da17..0509a3799b 100644
--- a/esp8266/README.md
+++ b/esp8266/README.md
@@ -69,6 +69,34 @@ $ make PORT=/dev/ttyUSB0 deploy
The image produced is `firmware-combined.bin`, to be flashed at 0x00000.
+First start
+-----------
+
+__Serial prompt__
+
+You can access the REPL (Python prompt) over UART (the same as used for
+programming).
+- Baudrate: 115200
+
+__WiFi__
+
+Initally, the device configures itself as a WiFi access point (AP).
+- ESSID: MicroPython-xxxxxx (x’s are replaced with part of the MAC address).
+- Password: micropythoN (note the upper-case N).
+- IP address of the board: 192.168.4.1.
+- DHCP-server is activated.
+
+__WebREPL__
+
+Python prompt over WiFi, connecting through a browser.
+- Hosted at http://micropython.org/webrepl.
+- GitHub repository https://github.com/micropython/webrepl.
+
+Please follow the instructions there.
+
+More detailed instructions can be found at
+http://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html
+
Troubleshooting
---------------
diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c
index 25f1a9322f..9f090a0973 100644
--- a/esp8266/esp_mphal.c
+++ b/esp8266/esp_mphal.c
@@ -166,21 +166,24 @@ static int call_dupterm_read(void) {
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) {
+ nlr_pop();
return -2;
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len == 0) {
- MP_STATE_PORT(term_obj) = NULL;
- mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n");
+ mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
+ nlr_pop();
return -1;
}
nlr_pop();
+ if (*(byte*)bufinfo.buf == interrupt_char) {
+ mp_keyboard_interrupt();
+ return -2;
+ }
return *(byte*)bufinfo.buf;
} else {
- MP_STATE_PORT(term_obj) = NULL;
- mp_printf(&mp_plat_print, "dupterm: Exception in read() method, deactivating: ");
- mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
+ mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
}
return -1;
@@ -213,7 +216,7 @@ void mp_hal_signal_dupterm_input(void) {
system_os_post(DUPTERM_TASK_ID, 0, 0);
}
-void mp_hal_pin_config_od(mp_hal_pin_obj_t pin_id) {
+void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) {
const pyb_pin_obj_t *pin = &pyb_pin_obj[pin_id];
if (pin->phys_port == 16) {
diff --git a/esp8266/esp_mphal.h b/esp8266/esp_mphal.h
index 13b1c8fdf0..91fee21198 100644
--- a/esp8266/esp_mphal.h
+++ b/esp8266/esp_mphal.h
@@ -28,6 +28,10 @@
#define _INCLUDED_MPHAL_H_
#include "py/ringbuf.h"
+#include "xtirq.h"
+
+void mp_keyboard_interrupt(void);
+extern int interrupt_char;
struct _mp_print_t;
// Structure for UART-only output via mp_printf()
@@ -59,14 +63,19 @@ void ets_event_poll(void);
#include "osapi.h"
#define mp_hal_delay_us_fast(us) os_delay_us(us)
+#define mp_hal_quiet_timing_enter() disable_irq()
+#define mp_hal_quiet_timing_exit(irq_state) enable_irq(irq_state)
+
// C-level pin HAL
#include "etshal.h"
#include "gpio.h"
#include "esp8266/modpyb.h"
#define mp_hal_pin_obj_t uint32_t
#define mp_hal_get_pin_obj(o) mp_obj_get_pin(o)
-void mp_hal_pin_config_od(mp_hal_pin_obj_t pin);
-#define mp_hal_pin_low(p) do { \
+void mp_hal_pin_input(mp_hal_pin_obj_t pin);
+void mp_hal_pin_output(mp_hal_pin_obj_t pin);
+void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin);
+#define mp_hal_pin_od_low(p) do { \
if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); } \
else { gpio_output_set(0, 1 << (p), 1 << (p), 0); } \
} while (0)
diff --git a/esp8266/espapa102.c b/esp8266/espapa102.c
new file mode 100644
index 0000000000..e5f3024b10
--- /dev/null
+++ b/esp8266/espapa102.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Robert Foss, Daniel Busch
+ *
+ * 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 "c_types.h"
+#include "eagle_soc.h"
+#include "user_interface.h"
+#include "espapa102.h"
+
+#define NOP asm volatile(" nop \n\t")
+
+static inline void _esp_apa102_send_byte(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t byte) {
+ for (uint32_t i = 0; i < 8; i++) {
+ if (byte & 0x80) {
+ // set data pin high
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
+ } else {
+ // set data pin low
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, dataPinMask);
+ }
+
+ // set clock pin high
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
+ byte <<= 1;
+ NOP;
+ NOP;
+
+ // set clock pin low
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
+ NOP;
+ NOP;
+ }
+}
+
+static inline void _esp_apa102_send_colors(uint32_t clockPinMask, uint32_t dataPinMask, uint8_t *pixels, uint32_t numBytes) {
+ for (uint32_t i = 0; i < numBytes / 4; i++) {
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 3] | 0xE0);
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 2]);
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4 + 1]);
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, pixels[i * 4]);
+ }
+}
+
+static inline void _esp_apa102_start_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
+ for (uint32_t i = 0; i < 4; i++) {
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, 0x00);
+ }
+}
+
+static inline void _esp_apa102_append_additionial_cycles(uint32_t clockPinMask, uint32_t dataPinMask, uint32_t numBytes) {
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, dataPinMask);
+
+ // we need to write some more clock cycles, because each led
+ // delays the data by one edge after inverting the clock
+ for (uint32_t i = 0; i < numBytes / 8 + ((numBytes / 4) % 2); i++) {
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, clockPinMask);
+ NOP;
+ NOP;
+
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, clockPinMask);
+ NOP;
+ NOP;
+ }
+}
+
+static inline void _esp_apa102_end_frame(uint32_t clockPinMask, uint32_t dataPinMask) {
+ for (uint32_t i = 0; i < 4; i++) {
+ _esp_apa102_send_byte(clockPinMask, dataPinMask, 0xFF);
+ }
+}
+
+void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes) {
+ uint32_t clockPinMask, dataPinMask;
+
+ clockPinMask = 1 << clockPin;
+ dataPinMask = 1 << dataPin;
+
+ // start the frame
+ _esp_apa102_start_frame(clockPinMask, dataPinMask);
+
+ // write pixels
+ _esp_apa102_send_colors(clockPinMask, dataPinMask, pixels, numBytes);
+
+ // end the frame
+ _esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes);
+ _esp_apa102_end_frame(clockPinMask, dataPinMask);
+}
diff --git a/esp8266/espapa102.h b/esp8266/espapa102.h
new file mode 100644
index 0000000000..82c92025d3
--- /dev/null
+++ b/esp8266/espapa102.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Robert Foss, Daniel Busch
+ *
+ * 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.
+ */
+
+void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes);
diff --git a/esp8266/ets_alt_task.c b/esp8266/ets_alt_task.c
index 91623f06df..62872affb9 100644
--- a/esp8266/ets_alt_task.c
+++ b/esp8266/ets_alt_task.c
@@ -5,6 +5,7 @@
#include <esp_sdk_ver.h>
#include "etshal.h"
#include "user_interface.h"
+#include "ets_alt_task.h"
// Use standard ets_task or alternative impl
#define USE_ETS_TASK 0
@@ -107,7 +108,12 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
#endif
}
+int ets_loop_iter_disable = 0;
+
bool ets_loop_iter(void) {
+ if (ets_loop_iter_disable) {
+ return false;
+ }
//static unsigned cnt;
bool progress = false;
for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
diff --git a/esp8266/ets_alt_task.h b/esp8266/ets_alt_task.h
index c423995841..4b5ba26dbd 100644
--- a/esp8266/ets_alt_task.h
+++ b/esp8266/ets_alt_task.h
@@ -1 +1,2 @@
+extern int ets_loop_iter_disable;
bool ets_loop_iter(void);
diff --git a/esp8266/help.c b/esp8266/help.c
index 3a4d6e83a2..5370ee71ea 100644
--- a/esp8266/help.c
+++ b/esp8266/help.c
@@ -37,7 +37,7 @@ STATIC const char *help_text =
"Basic WiFi configuration:\n"
"\n"
"import network\n"
-"sta_if = network.WLAN(network.STA_IF)\n"
+"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
"sta_if.scan() # Scan for available access points\n"
"sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n"
"sta_if.isconnected() # Check for successful connection\n"
diff --git a/esp8266/main.c b/esp8266/main.c
index 45ee85ac88..9cc955e44c 100644
--- a/esp8266/main.c
+++ b/esp8266/main.c
@@ -38,7 +38,7 @@
#include "gccollect.h"
#include "user_interface.h"
-STATIC char heap[24 * 1024];
+STATIC char heap[28 * 1024];
STATIC void mp_reset(void) {
mp_stack_set_top((void*)0x40000000);
@@ -58,7 +58,7 @@ STATIC void mp_reset(void) {
MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
pin_init0();
#if MICROPY_MODULE_FROZEN
- pyexec_frozen_module("_boot");
+ pyexec_frozen_module("_boot.py");
pyexec_file("boot.py");
pyexec_file("main.py");
#endif
diff --git a/esp8266/modesp.c b/esp8266/modesp.c
index 44401d3a61..0c6cc423e1 100644
--- a/esp8266/modesp.c
+++ b/esp8266/modesp.c
@@ -27,13 +27,14 @@
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
-#include <errno.h>
#include "py/nlr.h"
#include "py/obj.h"
#include "py/gc.h"
#include "py/runtime.h"
+#include "py/mperrno.h"
#include "py/mphal.h"
+#include "drivers/dht/dht.h"
#include "netutils.h"
#include "queue.h"
#include "ets_sys.h"
@@ -43,6 +44,7 @@
#include "spi_flash.h"
#include "mem.h"
#include "espneopixel.h"
+#include "espapa102.h"
#include "modpyb.h"
#define MODESP_ESPCONN (0)
@@ -577,7 +579,7 @@ STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) {
if (alloc_buf) {
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)));
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
@@ -594,7 +596,7 @@ STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) {
}
nlr_raise(mp_obj_new_exception_arg1(
&mp_type_OSError,
- MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO)));
+ MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
@@ -606,7 +608,7 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
}
nlr_raise(mp_obj_new_exception_arg1(
&mp_type_OSError,
- MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? ETIMEDOUT : EIO)));
+ MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
@@ -636,6 +638,16 @@ STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
+STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
+ esp_apa102_write(mp_obj_get_pin_obj(clockPin)->phys_port,
+ mp_obj_get_pin_obj(dataPin)->phys_port,
+ (uint8_t*)bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_apa102_write_obj, esp_apa102_write_);
+
STATIC mp_obj_t esp_freemem() {
return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size());
}
@@ -679,6 +691,8 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = {
{ 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_apa102_write), (mp_obj_t)&esp_apa102_write_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_dht_readinto), (mp_obj_t)&dht_readinto_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 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, // TODO delete/rename/move elsewhere
diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c
index c3c9494ac8..36872c9dff 100644
--- a/esp8266/modmachine.c
+++ b/esp8266/modmachine.c
@@ -30,10 +30,12 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "extmod/machine_mem.h"
+#include "extmod/machine_pulse.h"
#include "extmod/machine_i2c.h"
#include "modpyb.h"
#include "modpybrtc.h"
+#include "xtirq.h"
#include "os_type.h"
#include "osapi.h"
#include "etshal.h"
@@ -189,6 +191,25 @@ const mp_obj_type_t esp_timer_type = {
.locals_dict = (mp_obj_t)&esp_timer_locals_dict,
};
+// this bit is unused in the Xtensa PS register
+#define ETS_LOOP_ITER_BIT (12)
+
+STATIC mp_obj_t machine_disable_irq(void) {
+ uint32_t state = disable_irq();
+ state = (state & ~(1 << ETS_LOOP_ITER_BIT)) | (ets_loop_iter_disable << ETS_LOOP_ITER_BIT);
+ ets_loop_iter_disable = 1;
+ return mp_obj_new_int(state);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
+
+STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
+ uint32_t state = mp_obj_get_int(state_in);
+ ets_loop_iter_disable = (state >> ETS_LOOP_ITER_BIT) & 1;
+ enable_irq(state & ~(1 << ETS_LOOP_ITER_BIT));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
+
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) },
@@ -201,6 +222,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
diff --git a/esp8266/modnetwork.c b/esp8266/modnetwork.c
index 5e9273158c..c0763ce0eb 100644
--- a/esp8266/modnetwork.c
+++ b/esp8266/modnetwork.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
-#include <errno.h>
#include "py/nlr.h"
#include "py/objlist.h"
@@ -137,16 +136,25 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) {
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));
- t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid));
- t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel);
- 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);
- mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
+ // we need to catch any memory errors
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 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));
+ t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid));
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel);
+ 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);
+ mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
+ }
+ nlr_pop();
+ } else {
+ mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ // indicate error
+ *esp_scan_list = MP_OBJ_NULL;
}
} else {
// indicate error
@@ -156,14 +164,25 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) {
}
STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
- if (wifi_get_opmode() == SOFTAP_MODE) {
+ require_if(self_in, STATION_IF);
+ if ((wifi_get_opmode() & STATION_MODE) == 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
- "scan unsupported in AP mode"));
+ "STA must be active"));
}
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);
- ETS_POLL_WHILE(esp_scan_list != NULL);
+ while (esp_scan_list != NULL) {
+ // our esp_scan_cb is called via ets_loop_iter so it's safe to set the
+ // esp_scan_list variable to NULL without disabling interrupts
+ if (MP_STATE_VM(mp_pending_exception) != NULL) {
+ esp_scan_list = NULL;
+ mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
+ nlr_raise(obj);
+ }
+ ets_loop_iter();
+ }
if (list == MP_OBJ_NULL) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "scan failed"));
}
diff --git a/esp8266/modpybpin.c b/esp8266/modpybpin.c
index 6b9e20268b..166d6f566f 100644
--- a/esp8266/modpybpin.c
+++ b/esp8266/modpybpin.c
@@ -36,6 +36,7 @@
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/gc.h"
+#include "py/mphal.h"
#include "modpyb.h"
#define GET_TRIGGER(phys_port) \
@@ -123,6 +124,34 @@ uint mp_obj_get_pin(mp_obj_t pin_in) {
return mp_obj_get_pin_obj(pin_in)->phys_port;
}
+void mp_hal_pin_input(mp_hal_pin_obj_t pin_id) {
+ pin_mode[pin_id] = GPIO_MODE_INPUT;
+ if (pin_id == 16) {
+ 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)); // input
+ } else {
+ const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
+ PIN_FUNC_SELECT(self->periph, self->func);
+ PIN_PULLUP_DIS(self->periph);
+ gpio_output_set(0, 0, 0, 1 << self->phys_port);
+ }
+}
+
+void mp_hal_pin_output(mp_hal_pin_obj_t pin_id) {
+ pin_mode[pin_id] = GPIO_MODE_OUTPUT;
+ if (pin_id == 16) {
+ 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) | 1); // output
+ } else {
+ const pyb_pin_obj_t *self = &pyb_pin_obj[pin_id];
+ PIN_FUNC_SELECT(self->periph, self->func);
+ PIN_PULLUP_DIS(self->periph);
+ gpio_output_set(0, 0, 1 << self->phys_port, 0);
+ }
+}
+
int pin_get(uint pin) {
if (pin == 16) {
return READ_PERI_REG(RTC_GPIO_IN_DATA) & 1;
diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c
index e62dc88175..484d0d82fd 100644
--- a/esp8266/modpybrtc.c
+++ b/esp8266/modpybrtc.c
@@ -53,6 +53,9 @@ STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
uint32_t pyb_rtc_alarm0_wake; // see MACHINE_WAKE_xxx constants
uint64_t pyb_rtc_alarm0_expiry; // in microseconds
+// RTC overflow checking
+STATIC uint32_t rtc_last_ticks;
+
void mp_hal_rtc_init(void) {
uint32_t magic;
@@ -64,7 +67,11 @@ void mp_hal_rtc_init(void) {
int64_t delta = 0;
system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
+ uint32_t len = 0;
+ system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));
}
+ // system_get_rtc_time() is always 0 after reset/deepsleep
+ rtc_last_ticks = system_get_rtc_time();
// reset ALARM0 state
pyb_rtc_alarm0_wake = 0;
@@ -79,13 +86,11 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp
return (mp_obj_t)&pyb_rtc_obj;
}
-STATIC uint64_t pyb_rtc_raw_us(uint64_t cal) {
- return (system_get_rtc_time() * cal) >> 12;
-};
-
void pyb_rtc_set_us_since_2000(uint64_t nowus) {
uint32_t cal = system_rtc_clock_cali_proc();
- int64_t delta = nowus - pyb_rtc_raw_us(cal);
+ // Save RTC ticks for overflow detection.
+ rtc_last_ticks = system_get_rtc_time();
+ int64_t delta = nowus - (((uint64_t)rtc_last_ticks * cal) >> 12);
// As the calibration value jitters quite a bit, to make the
// clock at least somewhat practially usable, we need to store it
@@ -96,11 +101,23 @@ void pyb_rtc_set_us_since_2000(uint64_t nowus) {
uint64_t pyb_rtc_get_us_since_2000() {
uint32_t cal;
int64_t delta;
+ uint32_t rtc_ticks;
system_rtc_mem_read(MEM_CAL_ADDR, &cal, sizeof(cal));
system_rtc_mem_read(MEM_DELTA_ADDR, &delta, sizeof(delta));
- return pyb_rtc_raw_us(cal) + delta;
+ // ESP-SDK system_get_rtc_time() only returns uint32 and therefore
+ // overflow about every 7:45h. Thus, we have to check for
+ // overflow and handle it.
+ rtc_ticks = system_get_rtc_time();
+ if (rtc_ticks < rtc_last_ticks) {
+ // Adjust delta because of RTC overflow.
+ delta += (uint64_t)cal << 20;
+ system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
+ }
+ rtc_last_ticks = rtc_ticks;
+
+ return (((uint64_t)rtc_ticks * cal) >> 12) + delta;
};
STATIC mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) {
@@ -145,20 +162,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_d
STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
uint8_t rtcram[MEM_USER_MAXLEN];
uint32_t len;
- uint32_t magic;
if (n_args == 1) {
-
- system_rtc_mem_read(MEM_USER_MAGIC_ADDR, &magic, sizeof(magic));
- if (magic != MEM_MAGIC) {
- return mp_const_none;
- }
+ // read RTC memory
system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len));
system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, len + (4 - len % 4));
return mp_obj_new_bytes(rtcram, len);
} else {
+ // write RTC memory
+
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
@@ -167,8 +181,6 @@ STATIC mp_obj_t pyb_rtc_memory(mp_uint_t n_args, const mp_obj_t *args) {
"buffer too long"));
}
- magic = MEM_MAGIC;
- 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));
diff --git a/esp8266/modpybspi.c b/esp8266/modpybspi.c
index 1131e8ef6b..c2bcc33edc 100644
--- a/esp8266/modpybspi.c
+++ b/esp8266/modpybspi.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
-#include <errno.h>
#include "ets_sys.h"
#include "etshal.h"
@@ -124,6 +123,12 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
}
+
+ // configure pins
+ mp_hal_pin_write(self->sck, self->polarity);
+ mp_hal_pin_output(self->sck);
+ mp_hal_pin_output(self->mosi);
+ mp_hal_pin_input(self->miso);
}
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) {
diff --git a/esp8266/modpybuart.c b/esp8266/modpybuart.c
index eefb38d998..5971ffecec 100644
--- a/esp8266/modpybuart.c
+++ b/esp8266/modpybuart.c
@@ -27,13 +27,13 @@
#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 "py/mperrno.h"
#include "modpyb.h"
// baudrate is currently fixed to this value
@@ -136,7 +136,7 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
// wait for first char to become available
if (!uart_rx_wait(self->timeout * 1000)) {
- *errcode = EAGAIN;
+ *errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}
@@ -173,7 +173,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
}
STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
- *errcode = EINVAL;
+ *errcode = MP_EINVAL;
return MP_STREAM_ERROR;
}
diff --git a/esp8266/moduos.c b/esp8266/moduos.c
index d75062eaf7..74262d86b1 100644
--- a/esp8266/moduos.c
+++ b/esp8266/moduos.c
@@ -25,7 +25,6 @@
*/
#include <string.h>
-#include <errno.h>
#include "py/mpconfig.h"
#include "py/nlr.h"
@@ -33,6 +32,7 @@
#include "py/objtuple.h"
#include "py/objstr.h"
#include "py/runtime.h"
+#include "py/mperrno.h"
#include "extmod/misc.h"
#include "genhdr/mpversion.h"
#include "esp_mphal.h"
@@ -74,12 +74,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
#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)));
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_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));
+ if (args != NULL) {
+ memcpy(meth + 2, args, n_args * sizeof(*args));
+ }
return mp_call_method_n_kw(n_args, 0, meth);
}
@@ -93,10 +95,29 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);
+STATIC mp_obj_t os_chdir(mp_obj_t path_in) {
+ return vfs_proxy_call(MP_QSTR_chdir, 1, &path_in);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_chdir_obj, os_chdir);
+
+STATIC mp_obj_t os_getcwd(void) {
+ return vfs_proxy_call(MP_QSTR_getcwd, 0, NULL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd);
+
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);
+
+STATIC mp_obj_t os_rename(mp_obj_t path_old, mp_obj_t path_new) {
+ mp_obj_t args[2];
+ args[0] = path_old;
+ args[1] = path_new;
+ return vfs_proxy_call(MP_QSTR_rename, 2, args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename);
+
#endif
STATIC mp_obj_t os_urandom(mp_obj_t num) {
@@ -117,6 +138,11 @@ STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
+STATIC mp_obj_t os_stat(mp_obj_t path_in) {
+ return vfs_proxy_call(MP_QSTR_stat, 1, &path_in);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);
+
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) },
@@ -129,7 +155,11 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ 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_mkdir), MP_ROM_PTR(&os_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&os_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&os_getcwd_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) },
#endif
};
diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h
index e2c7f57e22..544edc408f 100644
--- a/esp8266/mpconfigport.h
+++ b/esp8266/mpconfigport.h
@@ -4,6 +4,11 @@
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
#define MICROPY_ALLOC_PATH_MAX (128)
+#define MICROPY_ALLOC_LEXER_INDENT_INIT (8)
+#define MICROPY_ALLOC_PARSE_RULE_INIT (48)
+#define MICROPY_ALLOC_PARSE_RULE_INC (8)
+#define MICROPY_ALLOC_PARSE_RESULT_INC (8)
+#define MICROPY_ALLOC_PARSE_CHUNK_INIT (64)
#define MICROPY_EMIT_X64 (0)
#define MICROPY_EMIT_THUMB (0)
#define MICROPY_EMIT_INLINE_THUMB (0)
@@ -19,6 +24,7 @@
#define MICROPY_ENABLE_SOURCE_LINE (1)
#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+#define MICROPY_USE_INTERNAL_ERRNO (1)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#define MICROPY_PY_BUILTINS_BYTEARRAY (1)
@@ -32,14 +38,17 @@
#define MICROPY_PY_ARRAY (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_COLLECTIONS (1)
+#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
#define MICROPY_PY_MATH (1)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (1)
+#define MICROPY_PY_IO_FILEIO (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_PY_UERRNO (1)
#define MICROPY_PY_UBINASCII (1)
#define MICROPY_PY_UCTYPES (1)
#define MICROPY_PY_UHASHLIB (1)
@@ -51,6 +60,7 @@
#define MICROPY_PY_UZLIB (1)
#define MICROPY_PY_LWIP (1)
#define MICROPY_PY_MACHINE (1)
+#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_WEBSOCKET (1)
#define MICROPY_PY_WEBREPL (1)
@@ -105,6 +115,9 @@ typedef uint32_t sys_prot_t; // for modlwip
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+#define mp_type_fileio fatfs_type_fileio
+#define mp_type_textio fatfs_type_textio
+
// extra built in names to add to the global namespace
#define MICROPY_PORT_BUILTINS \
{ MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \
@@ -135,6 +148,7 @@ extern const struct _mp_obj_module_t onewire_module;
{ 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 }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_errno), (mp_obj_t)&mp_module_uerrno }, \
#define MP_STATE_PORT MP_STATE_VM
diff --git a/esp8266/scripts/apa102.py b/esp8266/scripts/apa102.py
new file mode 100644
index 0000000000..126448cc20
--- /dev/null
+++ b/esp8266/scripts/apa102.py
@@ -0,0 +1,28 @@
+# APA102 driver for MicroPython on ESP8266
+# MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch
+
+from esp import apa102_write
+
+class APA102:
+ def __init__(self, clock_pin, data_pin, n):
+ self.clock_pin = clock_pin
+ self.data_pin = data_pin
+ self.n = n
+ self.buf = bytearray(n * 4)
+
+ self.clock_pin.init(clock_pin.OUT)
+ self.data_pin.init(data_pin.OUT)
+
+ def __setitem__(self, index, val):
+ r, g, b, brightness = val
+ self.buf[index * 4] = r
+ self.buf[index * 4 + 1] = g
+ self.buf[index * 4 + 2] = b
+ self.buf[index * 4 + 3] = brightness
+
+ def __getitem__(self, index):
+ i = index * 4
+ return self.buf[i], self.buf[i + 1], self.buf[i + 2], self.buf[i + 3]
+
+ def write(self):
+ apa102_write(self.clock_pin, self.data_pin, self.buf)
diff --git a/esp8266/scripts/dht.py b/esp8266/scripts/dht.py
new file mode 100644
index 0000000000..9a69e7e07e
--- /dev/null
+++ b/esp8266/scripts/dht.py
@@ -0,0 +1,32 @@
+# DHT11/DHT22 driver for MicroPython on ESP8266
+# MIT license; Copyright (c) 2016 Damien P. George
+
+import esp
+
+class DHTBase:
+ def __init__(self, pin):
+ self.pin = pin
+ self.buf = bytearray(5)
+
+ def measure(self):
+ buf = self.buf
+ esp.dht_readinto(self.pin, buf)
+ if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]:
+ raise Exception("checksum error")
+
+class DHT11(DHTBase):
+ def humidity(self):
+ return self.buf[0]
+
+ def temperature(self):
+ return self.buf[2]
+
+class DHT22(DHTBase):
+ def humidity(self):
+ return (self.buf[0] << 8 | self.buf[1]) * 0.1
+
+ def temperature(self):
+ t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1
+ if self.buf[2] & 0x80:
+ t = -t
+ return t
diff --git a/esp8266/scripts/inisetup.py b/esp8266/scripts/inisetup.py
index 93a05bd8a7..461690b162 100644
--- a/esp8266/scripts/inisetup.py
+++ b/esp8266/scripts/inisetup.py
@@ -40,7 +40,7 @@ def setup():
with open("/boot.py", "w") as f:
f.write("""\
# This file is executed on every boot (including wake-boot from deepsleep)
-import webrepl
-webrepl.start()
+#import webrepl
+#webrepl.start()
""")
return vfs
diff --git a/esp8266/scripts/neopixel.py b/esp8266/scripts/neopixel.py
index 4818c74a3b..8aa0348680 100644
--- a/esp8266/scripts/neopixel.py
+++ b/esp8266/scripts/neopixel.py
@@ -8,7 +8,7 @@ class NeoPixel:
self.pin = pin
self.n = n
self.buf = bytearray(n * 3)
- self.pin.init(pin.OUT, pin.PULL_NONE)
+ self.pin.init(pin.OUT)
def __setitem__(self, index, val):
r, g, b = val
@@ -20,5 +20,12 @@ class NeoPixel:
i = index * 3
return self.buf[i + 1], self.buf[i], self.buf[i + 2]
+ def fill(self, color):
+ r, g, b = color
+ for i in range(len(self.buf) / 3):
+ self.buf[i * 3] = g
+ self.buf[i * 3 + 1] = r
+ self.buf[i * 3 + 2] = b
+
def write(self):
neopixel_write(self.pin, self.buf, True)
diff --git a/esp8266/scripts/ntptime.py b/esp8266/scripts/ntptime.py
index 650cc2e85b..a97e08e60d 100644
--- a/esp8266/scripts/ntptime.py
+++ b/esp8266/scripts/ntptime.py
@@ -10,10 +10,12 @@ except:
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
+host = "pool.ntp.org"
+
def time():
NTP_QUERY = bytearray(48)
NTP_QUERY[0] = 0x1b
- addr = socket.getaddrinfo('pool.ntp.org', 123)[0][-1]
+ addr = socket.getaddrinfo(host, 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(1)
res = s.sendto(NTP_QUERY, addr)
diff --git a/esp8266/scripts/onewire.py b/esp8266/scripts/onewire.py
index 4980d0af5c..686616950a 100644
--- a/esp8266/scripts/onewire.py
+++ b/esp8266/scripts/onewire.py
@@ -13,7 +13,7 @@ class OneWire:
def __init__(self, pin):
self.pin = pin
- self.pin.init(pin.OPEN_DRAIN, pin.PULL_NONE)
+ self.pin.init(pin.OPEN_DRAIN)
def reset(self):
return _ow.reset(self.pin)
diff --git a/esp8266/scripts/port_diag.py b/esp8266/scripts/port_diag.py
index fd7ee52d14..aa696b1abb 100644
--- a/esp8266/scripts/port_diag.py
+++ b/esp8266/scripts/port_diag.py
@@ -1,5 +1,7 @@
import esp
import uctypes
+import network
+import lwip
def main():
@@ -7,6 +9,7 @@ def main():
ROM = uctypes.bytearray_at(0x40200000, 16)
fid = esp.flash_id()
+ print("FlashROM:")
print("Flash ID: %x (Vendor: %x Device: %x)" % (fid, fid & 0xff, fid & 0xff00 | fid >> 16))
print("Flash bootloader data:")
@@ -15,5 +18,14 @@ def main():
print("Byte @2: %02x" % ROM[2])
print("Byte @3: %02x (Flash size: %s Flash freq: %s)" % (ROM[3], SZ_MAP.get(ROM[3] >> 4, "?"), FREQ_MAP.get(ROM[3] & 0xf)))
+ print("\nNetworking:")
+ print("STA ifconfig:", network.WLAN(network.STA_IF).ifconfig())
+ print("AP ifconfig:", network.WLAN(network.AP_IF).ifconfig())
+ print("Free WiFi driver buffers of type:")
+ for i in range(5):
+ print("%d: %d" % (i, esp.esf_free_bufs(i)))
+ print("lwIP PCBs:")
+ lwip.print_pcbs()
+
main()
diff --git a/esp8266/scripts/webrepl.py b/esp8266/scripts/webrepl.py
index 1a2c82277e..da3e70c595 100644
--- a/esp8266/scripts/webrepl.py
+++ b/esp8266/scripts/webrepl.py
@@ -10,7 +10,7 @@ listen_s = None
client_s = None
def setup_conn(port, accept_handler):
- global listen_s, client_s
+ global listen_s
listen_s = socket.socket()
listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -19,11 +19,13 @@ def setup_conn(port, accept_handler):
listen_s.bind(addr)
listen_s.listen(1)
- listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler)
+ if accept_handler:
+ listen_s.setsockopt(socket.SOL_SOCKET, 20, accept_handler)
for i in (network.AP_IF, network.STA_IF):
iface = network.WLAN(i)
if iface.active():
print("WebREPL daemon started on ws://%s:%d" % (iface.ifconfig()[0], port))
+ return listen_s
def accept_conn(listen_sock):
@@ -49,14 +51,25 @@ def stop():
listen_s.close()
-def start(port=8266):
+def start(port=8266, password=None):
stop()
- try:
- import port_config
- _webrepl.password(port_config.WEBREPL_PASS)
+ if password is None:
+ try:
+ import port_config
+ _webrepl.password(port_config.WEBREPL_PASS)
+ setup_conn(port, accept_conn)
+ print("Started webrepl in normal mode")
+ except:
+ import webrepl_setup
+ setup_conn(port, webrepl_setup.handle_conn)
+ print("Started webrepl in setup mode")
+ else:
+ _webrepl.password(password)
setup_conn(port, accept_conn)
print("Started webrepl in normal mode")
- except:
- import webrepl_setup
- setup_conn(port, webrepl_setup.handle_conn)
- print("Started webrepl in setup mode")
+
+
+def start_foreground(port=8266):
+ stop()
+ s = setup_conn(port, None)
+ accept_conn(s)
diff --git a/esp8266/scripts/webrepl_setup.py b/esp8266/scripts/webrepl_setup.py
index 7c4068750c..d0bf8465d5 100644
--- a/esp8266/scripts/webrepl_setup.py
+++ b/esp8266/scripts/webrepl_setup.py
@@ -26,7 +26,7 @@ def getpass(stream, prompt):
stream.write("\r\n")
return passwd
passwd += c
-# stream.write("*")
+ stream.write("*")
def handle_conn(listen_sock):
cl, remote_addr = listen_sock.accept()
@@ -60,6 +60,9 @@ some boards, you may need to press reset button or reconnect power.\r
if len(passwd1) < 4:
ws.write("Password too short\r\n")
continue
+ elif len(passwd1) > 9:
+ ws.write("Password too long\r\n")
+ continue
passwd2 = getpass(ws, "Confirm password: ")
if passwd1 == passwd2:
break
diff --git a/esp8266/uart.c b/esp8266/uart.c
index 573f0cb072..1c317a1cb6 100644
--- a/esp8266/uart.c
+++ b/esp8266/uart.c
@@ -19,6 +19,9 @@
#include "user_interface.h"
#include "esp_mphal.h"
+// seems that this is missing in the Espressif SDK
+#define FUNC_U0RXD 0
+
#define UART_REPL UART0
// UartDev is defined and initialized in rom code.
@@ -53,7 +56,7 @@ static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL);
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
}
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
diff --git a/esp8266/xtirq.h b/esp8266/xtirq.h
new file mode 100644
index 0000000000..856ff075ac
--- /dev/null
+++ b/esp8266/xtirq.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef __MICROPY_INCLUDED_ESP8266_XTIRQ_H__
+#define __MICROPY_INCLUDED_ESP8266_XTIRQ_H__
+
+#include <stdint.h>
+
+// returns the value of "intlevel" from the PS register
+static inline uint32_t query_irq(void) {
+ uint32_t ps;
+ __asm__ volatile("rsr %0, ps" : "=a" (ps));
+ return ps & 0xf;
+}
+
+// irqs with a priority value lower or equal to "intlevel" will be disabled
+// "intlevel" should be between 0 and 15 inclusive, and should be an integer
+static inline uint32_t raise_irq_pri(uint32_t intlevel) {
+ uint32_t old_ps;
+ __asm__ volatile ("rsil %0, %1" : "=a" (old_ps) : "I" (intlevel));
+ return old_ps;
+}
+
+// "ps" should be the value returned from raise_irq_pri
+static inline void restore_irq_pri(uint32_t ps) {
+ __asm__ volatile ("wsr %0, ps; rsync" :: "a" (ps));
+}
+
+static inline uint32_t disable_irq(void) {
+ return raise_irq_pri(15);
+}
+
+static inline void enable_irq(uint32_t irq_state) {
+ restore_irq_pri(irq_state);
+}
+
+#endif // __MICROPY_INCLUDED_ESP8266_XTIRQ_H__