aboutsummaryrefslogtreecommitdiff
path: root/ports/esp8266
diff options
context:
space:
mode:
authorDamien George2017-09-06 13:40:51 +1000
committerDamien George2017-09-06 13:40:51 +1000
commit01dd7804b87d60b2deab16712eccb3b97351a9b7 (patch)
tree1aa21f38a872b8e62a3d4e4f74f68033c6f827e4 /ports/esp8266
parenta9862b30068fc9df1022f08019fb35aaa5085f64 (diff)
ports: Make new ports/ sub-directory and move all ports there.
This is to keep the top-level directory clean, to make it clear what is core and what is a port, and to allow the repository to grow with new ports in a sustainable way.
Diffstat (limited to 'ports/esp8266')
-rw-r--r--ports/esp8266/Makefile236
-rw-r--r--ports/esp8266/README.md141
-rw-r--r--ports/esp8266/axtls_helpers.c63
-rw-r--r--ports/esp8266/eagle.rom.addr.v6.ld351
-rw-r--r--ports/esp8266/esp8266.ld12
-rw-r--r--ports/esp8266/esp8266_512k.ld12
-rw-r--r--ports/esp8266/esp8266_common.ld298
-rw-r--r--ports/esp8266/esp8266_ota.ld13
-rw-r--r--ports/esp8266/esp_init_data.c77
-rw-r--r--ports/esp8266/esp_mphal.c236
-rw-r--r--ports/esp8266/esp_mphal.h95
-rw-r--r--ports/esp8266/espapa102.c115
-rw-r--r--ports/esp8266/espapa102.h31
-rw-r--r--ports/esp8266/espneopixel.c65
-rw-r--r--ports/esp8266/espneopixel.h6
-rw-r--r--ports/esp8266/esppwm.c428
-rw-r--r--ports/esp8266/esppwm.h17
-rw-r--r--ports/esp8266/ets_alt_task.c214
-rw-r--r--ports/esp8266/ets_alt_task.h9
-rw-r--r--ports/esp8266/etshal.h45
-rw-r--r--ports/esp8266/fatfs_port.c43
-rw-r--r--ports/esp8266/gccollect.c56
-rw-r--r--ports/esp8266/gccollect.h45
-rw-r--r--ports/esp8266/gchelper.s22
-rw-r--r--ports/esp8266/help.c54
-rw-r--r--ports/esp8266/hspi.c331
-rw-r--r--ports/esp8266/hspi.h79
-rw-r--r--ports/esp8266/hspi_register.h278
-rw-r--r--ports/esp8266/intr.c37
-rw-r--r--ports/esp8266/lexerstr32.c69
-rw-r--r--ports/esp8266/machine_adc.c83
-rw-r--r--ports/esp8266/machine_hspi.c179
-rw-r--r--ports/esp8266/machine_pin.c519
-rw-r--r--ports/esp8266/machine_pwm.c172
-rw-r--r--ports/esp8266/machine_rtc.c272
-rw-r--r--ports/esp8266/machine_uart.c299
-rw-r--r--ports/esp8266/machine_wdt.c85
-rw-r--r--ports/esp8266/main.c143
-rw-r--r--ports/esp8266/makeimg.py40
-rw-r--r--ports/esp8266/modesp.c392
-rw-r--r--ports/esp8266/modmachine.c279
-rw-r--r--ports/esp8266/modmachine.h41
-rw-r--r--ports/esp8266/modnetwork.c488
-rw-r--r--ports/esp8266/modpyb.c79
-rw-r--r--ports/esp8266/modules/_boot.py13
-rw-r--r--ports/esp8266/modules/apa102.py17
-rw-r--r--ports/esp8266/modules/dht.py32
l---------ports/esp8266/modules/ds18x20.py1
-rw-r--r--ports/esp8266/modules/flashbdev.py35
-rw-r--r--ports/esp8266/modules/inisetup.py52
-rw-r--r--ports/esp8266/modules/neopixel.py32
-rw-r--r--ports/esp8266/modules/ntptime.py36
l---------ports/esp8266/modules/onewire.py1
-rw-r--r--ports/esp8266/modules/port_diag.py33
l---------ports/esp8266/modules/upip.py1
l---------ports/esp8266/modules/upip_utarfile.py1
-rw-r--r--ports/esp8266/modules/webrepl.py77
-rw-r--r--ports/esp8266/modules/webrepl_setup.py111
-rw-r--r--ports/esp8266/modules/websocket_helper.py74
-rw-r--r--ports/esp8266/moduos.c116
-rw-r--r--ports/esp8266/modutime.c131
-rw-r--r--ports/esp8266/mpconfigport.h198
-rw-r--r--ports/esp8266/mpconfigport_512k.h34
-rw-r--r--ports/esp8266/qstrdefsport.h31
-rw-r--r--ports/esp8266/strtoll.c29
-rw-r--r--ports/esp8266/uart.c296
-rw-r--r--ports/esp8266/uart.h106
-rw-r--r--ports/esp8266/uart_register.h128
-rw-r--r--ports/esp8266/user_config.h1
-rw-r--r--ports/esp8266/xtirq.h59
70 files changed, 8194 insertions, 0 deletions
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
new file mode 100644
index 000000000..fce11a7d4
--- /dev/null
+++ b/ports/esp8266/Makefile
@@ -0,0 +1,236 @@
+include ../py/mkenv.mk
+
+# qstr definitions (must come before including py.mk)
+QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h
+
+MICROPY_PY_USSL = 1
+MICROPY_SSL_AXTLS = 1
+MICROPY_FATFS = 1
+MICROPY_PY_BTREE = 1
+
+FROZEN_DIR ?= scripts
+FROZEN_MPY_DIR ?= modules
+
+# include py core make definitions
+include $(TOP)/py/py.mk
+
+FWBIN = $(BUILD)/firmware-combined.bin
+PORT ?= /dev/ttyACM0
+BAUD ?= 115200
+FLASH_MODE ?= qio
+FLASH_SIZE ?= detect
+CROSS_COMPILE = xtensa-lx106-elf-
+ESP_SDK = $(shell $(CC) -print-sysroot)/usr
+
+INC += -I.
+INC += -I$(TOP)
+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 to disable.
+UART_OS = 0
+
+CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \
+ -D__ets__ -DICACHE_FLASH \
+ -fno-inline-functions \
+ -Wl,-EL -mlongcalls -mtext-section-literals -mforce-l32 \
+ -DLWIP_OPEN_SRC
+
+CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \
+ $(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
+
+LDSCRIPT = esp8266.ld
+LDFLAGS = -nostdlib -T $(LDSCRIPT) -Map=$(@:.elf=.map) --cref
+LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211 $(LDFLAGS_MOD)
+
+LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
+
+# Debugging/Optimization
+ifeq ($(DEBUG), 1)
+CFLAGS += -g
+COPT = -O0
+else
+CFLAGS += -fdata-sections -ffunction-sections
+COPT += -Os -DNDEBUG
+LDFLAGS += --gc-sections
+endif
+
+SRC_C = \
+ strtoll.c \
+ main.c \
+ help.c \
+ esp_mphal.c \
+ esp_init_data.c \
+ gccollect.c \
+ lexerstr32.c \
+ uart.c \
+ esppwm.c \
+ espneopixel.c \
+ espapa102.c \
+ intr.c \
+ modpyb.c \
+ modmachine.c \
+ machine_pin.c \
+ machine_pwm.c \
+ machine_rtc.c \
+ machine_adc.c \
+ machine_uart.c \
+ machine_wdt.c \
+ machine_hspi.c \
+ modesp.c \
+ modnetwork.c \
+ modutime.c \
+ moduos.c \
+ ets_alt_task.c \
+ fatfs_port.c \
+ axtls_helpers.c \
+ hspi.c \
+ $(SRC_MOD)
+
+EXTMOD_SRC_C = $(addprefix extmod/,\
+ modlwip.c \
+ modonewire.c \
+ )
+
+LIB_SRC_C = $(addprefix lib/,\
+ libc/string0.c \
+ libm/math.c \
+ libm/fmodf.c \
+ libm/nearbyintf.c \
+ libm/ef_sqrt.c \
+ libm/kf_rem_pio2.c \
+ libm/kf_sin.c \
+ libm/kf_cos.c \
+ libm/kf_tan.c \
+ libm/ef_rem_pio2.c \
+ libm/sf_sin.c \
+ libm/sf_cos.c \
+ libm/sf_tan.c \
+ libm/sf_frexp.c \
+ libm/sf_modf.c \
+ libm/sf_ldexp.c \
+ libm/asinfacosf.c \
+ libm/atanf.c \
+ libm/atan2f.c \
+ mp-readline/readline.c \
+ netutils/netutils.c \
+ timeutils/timeutils.c \
+ utils/pyexec.c \
+ utils/interrupt_char.c \
+ utils/sys_stdio_mphal.c \
+ )
+
+ifeq ($(MICROPY_FATFS), 1)
+LIB_SRC_C += \
+ lib/oofatfs/ff.c \
+ lib/oofatfs/option/unicode.c
+endif
+
+DRIVERS_SRC_C = $(addprefix drivers/,\
+ dht/dht.c \
+ )
+
+SRC_S = \
+ gchelper.s \
+
+OBJ =
+OBJ += $(PY_O)
+OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.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) $(EXTMOD_SRC_C) $(LIB_SRC_C) $(DRIVERS_SRC_C)
+# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
+SRC_QSTR_AUTO_DEPS +=
+
+all: $(BUILD)/libaxtls.a $(FWBIN)
+
+CONFVARS_FILE = $(BUILD)/confvars
+
+ifeq ($(wildcard $(CONFVARS_FILE)),)
+$(shell $(MKDIR) -p $(BUILD))
+$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
+else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_DIR) $(UART_OS))
+$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
+endif
+
+$(BUILD)/uart.o: $(CONFVARS_FILE)
+
+FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
+
+.PHONY: deploy
+
+deploy: $(BUILD)/firmware-combined.bin
+ $(ECHO) "Writing $< to the board"
+ $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $<
+
+erase:
+ $(ECHO) "Erase flash"
+ $(Q)esptool.py --port $(PORT) --baud $(BAUD) erase_flash
+
+reset:
+ echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT)
+
+$(FWBIN): $(BUILD)/firmware.elf
+ $(ECHO) "Create $@"
+ $(Q)esptool.py elf2image $^
+ $(Q)$(PYTHON) makeimg.py $(BUILD)/firmware.elf-0x00000.bin $(BUILD)/firmware.elf-0x[0-5][1-f]000.bin $@
+
+$(BUILD)/firmware.elf: $(OBJ)
+ $(ECHO) "LINK $@"
+ $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(SIZE) $@
+
+512k:
+ $(MAKE) LDSCRIPT=esp8266_512k.ld CFLAGS_EXTRA='-DMP_CONFIGFILE="<mpconfigport_512k.h>"' MICROPY_FATFS=0 MICROPY_PY_BTREE=0
+
+ota:
+ rm -f $(BUILD)/firmware.elf $(BUILD)/firmware.elf*.bin
+ $(MAKE) LDSCRIPT=esp8266_ota.ld FWBIN=$(BUILD)/firmware-ota.bin
+
+#MAKE_PINS = boards/make-pins.py
+#BOARD_PINS = boards/$(BOARD)/pins.csv
+#AF_FILE = boards/stm32f4xx_af.csv
+#PREFIX_FILE = boards/stm32f4xx_prefix.c
+#GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
+#GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
+#GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
+#GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
+#GEN_PINS_AF_PY = $(BUILD)/pins_af.py
+
+# Making OBJ use an order-only depenedency on the generated pins.h file
+# has the side effect of making the pins.h file before we actually compile
+# any of the objects. The normal dependency generation will deal with the
+# case when pins.h is modified. But when it doesn't exist, we don't know
+# which source files might need it.
+#$(OBJ): | $(HEADER_BUILD)/pins.h
+
+# Use a pattern rule here so that make will only call make-pins.py once to make
+# both pins_$(BOARD).c and pins.h
+#$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
+# $(ECHO) "Create $@"
+# $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
+#
+#$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
+# $(call compile_c)
+
+include $(TOP)/py/mkrules.mk
+
+axtls: $(BUILD)/libaxtls.a
+
+$(BUILD)/libaxtls.a:
+ cd $(TOP)/lib/axtls; cp config/upyconfig config/.config
+ cd $(TOP)/lib/axtls; $(MAKE) oldconfig -B
+ cd $(TOP)/lib/axtls; $(MAKE) clean
+ cd $(TOP)/lib/axtls; $(MAKE) all CC="$(CC)" LD="$(LD)" AR="$(AR)" CFLAGS_EXTRA="$(CFLAGS_XTENSA) -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096"
+ cp $(TOP)/lib/axtls/_stage/libaxtls.a $@
+
+clean-modules:
+ git clean -f -d modules
+ rm -f build/frozen*.c
diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md
new file mode 100644
index 000000000..252e195d8
--- /dev/null
+++ b/ports/esp8266/README.md
@@ -0,0 +1,141 @@
+MicroPython port to ESP8266
+===========================
+
+This is an experimental port of MicroPython for the WiFi modules based
+on Espressif ESP8266 chip.
+
+WARNING: The port is experimental and many APIs are subject to change.
+
+Supported features include:
+- REPL (Python prompt) over UART0.
+- Garbage collector, exceptions.
+- Unicode support.
+- Builtin modules: gc, array, collections, io, struct, sys, esp, network,
+ many more.
+- Arbitrary-precision long integers and 30-bit precision floats.
+- WiFi support.
+- Sockets using modlwip.
+- GPIO and bit-banging I2C, SPI support.
+- 1-Wire and WS2812 (aka Neopixel) protocols support.
+- Internal filesystem using the flash.
+- WebREPL over WiFi from a browser (clients at https://github.com/micropython/webrepl).
+- Modules for HTTP, MQTT, many other formats and protocols via
+ https://github.com/micropython/micropython-lib .
+
+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. 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.
+
+The MicroPython cross-compiler must be built to pre-compile some of the
+built-in scripts to bytecode. This can be done using:
+```bash
+$ make -C mpy-cross
+```
+
+Then, to build MicroPython for the ESP8266, just run:
+```bash
+$ cd esp8266
+$ make axtls
+$ make
+```
+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 mode, and connected to a serial port on your PC.
+The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is
+`detect` (auto-detect based on Flash ID). To specify other values, use, eg (note
+that flash size is in megabits):
+```bash
+$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy
+```
+
+The image produced is `build/firmware-combined.bin`, to be flashed at 0x00000.
+
+__512KB FlashROM version__
+
+The normal build described above requires modules with at least 1MB of FlashROM
+onboard. There's a special configuration for 512KB modules, which can be
+built with `make 512k`. This configuration is highly limited, lacks filesystem
+support, WebREPL, and has many other features disabled. It's mostly suitable
+for advanced users who are interested to fine-tune options to achieve a required
+setup. If you are an end user, please consider using a module with at least 1MB
+of FlashROM.
+
+First start
+-----------
+
+__Serial prompt__
+
+You can access the REPL (Python prompt) over UART (the same as used for
+programming).
+- Baudrate: 115200
+
+__WiFi__
+
+Initially, 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.
+
+Documentation
+-------------
+
+More detailed documentation and instructions can be found at
+http://docs.micropython.org/en/latest/esp8266/ , which includes Quick
+Reference, Tutorial, General Information related to ESP8266 port, and
+to MicroPython in general.
+
+Troubleshooting
+---------------
+
+While the port is in beta, 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.
+
+Additional information may be available by the documentation links above.
diff --git a/ports/esp8266/axtls_helpers.c b/ports/esp8266/axtls_helpers.c
new file mode 100644
index 000000000..6d508fdeb
--- /dev/null
+++ b/ports/esp8266/axtls_helpers.c
@@ -0,0 +1,63 @@
+/*
+ * 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 <stdint.h>
+#include <stdio.h>
+#include "py/mphal.h"
+#include "py/gc.h"
+
+// Functions for axTLS
+
+void *malloc(size_t size) {
+ return gc_alloc(size, false);
+}
+void free(void *ptr) {
+ gc_free(ptr);
+}
+void *calloc(size_t nmemb, size_t size) {
+ return m_malloc0(nmemb * size);
+}
+void *realloc(void *ptr, size_t size) {
+ return gc_realloc(ptr, size, true);
+}
+
+#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
+#undef htonl
+#undef ntohl
+uint32_t ntohl(uint32_t netlong) {
+ return PLATFORM_HTONL(netlong);
+}
+uint32_t htonl(uint32_t netlong) {
+ return PLATFORM_HTONL(netlong);
+}
+
+time_t time(time_t *t) {
+ return mp_hal_ticks_ms() / 1000;
+}
+
+time_t mktime(void *tm) {
+ return 0;
+}
diff --git a/ports/esp8266/eagle.rom.addr.v6.ld b/ports/esp8266/eagle.rom.addr.v6.ld
new file mode 100644
index 000000000..1b3ce55d0
--- /dev/null
+++ b/ports/esp8266/eagle.rom.addr.v6.ld
@@ -0,0 +1,351 @@
+PROVIDE ( Cache_Read_Disable = 0x400047f0 );
+PROVIDE ( Cache_Read_Enable = 0x40004678 );
+PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 );
+PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c );
+PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 );
+PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 );
+PROVIDE ( GetUartDevice = 0x40003f4c );
+PROVIDE ( MD5Final = 0x40009900 );
+PROVIDE ( MD5Init = 0x40009818 );
+PROVIDE ( MD5Update = 0x40009834 );
+PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 );
+PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c );
+PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 );
+PROVIDE ( RcvMsg = 0x40003eac );
+PROVIDE ( SHA1Final = 0x4000b648 );
+PROVIDE ( SHA1Init = 0x4000b584 );
+PROVIDE ( SHA1Transform = 0x4000a364 );
+PROVIDE ( SHA1Update = 0x4000b5a8 );
+PROVIDE ( SPI_read_status = 0x400043c8 );
+PROVIDE ( SPI_write_status = 0x40004400 );
+PROVIDE ( SPI_write_enable = 0x4000443c );
+PROVIDE ( Wait_SPI_Idle = 0x4000448c );
+PROVIDE ( Enable_QMode = 0x400044c0 );
+PROVIDE ( SPIEraseArea = 0x40004b44 );
+PROVIDE ( SPIEraseBlock = 0x400049b4 );
+PROVIDE ( SPIEraseChip = 0x40004984 );
+PROVIDE ( SPIEraseSector = 0x40004a00 );
+PROVIDE ( SPILock = 0x400048a8 );
+PROVIDE ( SPIParamCfg = 0x40004c2c );
+PROVIDE ( SPIRead = 0x40004b1c );
+PROVIDE ( SPIReadModeCnfig = 0x400048ec );
+PROVIDE ( SPIUnlock = 0x40004878 );
+PROVIDE ( SPIWrite = 0x40004a4c );
+PROVIDE ( SelectSpiFunction = 0x40003f58 );
+PROVIDE ( SendMsg = 0x40003cf4 );
+PROVIDE ( UartConnCheck = 0x40003230 );
+PROVIDE ( UartConnectProc = 0x400037a0 );
+PROVIDE ( UartDwnLdProc = 0x40003368 );
+PROVIDE ( UartGetCmdLn = 0x40003ef4 );
+PROVIDE ( UartRegReadProc = 0x4000381c );
+PROVIDE ( UartRegWriteProc = 0x400037ac );
+PROVIDE ( UartRxString = 0x40003c30 );
+PROVIDE ( Uart_Init = 0x40003a14 );
+PROVIDE ( _DebugExceptionVector = 0x40000010 );
+PROVIDE ( _DoubleExceptionVector = 0x40000070 );
+PROVIDE ( _KernelExceptionVector = 0x40000030 );
+PROVIDE ( _NMIExceptionVector = 0x40000020 );
+PROVIDE ( _ResetHandler = 0x400000a4 );
+PROVIDE ( _ResetVector = 0x40000080 );
+PROVIDE ( _UserExceptionVector = 0x40000050 );
+__adddf3 = 0x4000c538;
+__addsf3 = 0x4000c180;
+__divdf3 = 0x4000cb94;
+__divdi3 = 0x4000ce60;
+__divsi3 = 0x4000dc88;
+__extendsfdf2 = 0x4000cdfc;
+__fixdfsi = 0x4000ccb8;
+__fixunsdfsi = 0x4000cd00;
+__fixunssfsi = 0x4000c4c4;
+__floatsidf = 0x4000e2f0;
+__floatsisf = 0x4000e2ac;
+__floatunsidf = 0x4000e2e8;
+__floatunsisf = 0x4000e2a4;
+__muldf3 = 0x4000c8f0;
+__muldi3 = 0x40000650;
+__mulsf3 = 0x4000c3dc;
+__subdf3 = 0x4000c688;
+__subsf3 = 0x4000c268;
+__truncdfsf2 = 0x4000cd5c;
+__udivdi3 = 0x4000d310;
+__udivsi3 = 0x4000e21c;
+__umoddi3 = 0x4000d770;
+__umodsi3 = 0x4000e268;
+__umulsidi3 = 0x4000dcf0;
+PROVIDE ( _rom_store = 0x4000e388 );
+PROVIDE ( _rom_store_table = 0x4000e328 );
+PROVIDE ( _start = 0x4000042c );
+PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 );
+PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 );
+PROVIDE ( _xtos_cause3_handler = 0x40000590 );
+PROVIDE ( _xtos_ints_off = 0x4000bda4 );
+PROVIDE ( _xtos_ints_on = 0x4000bd84 );
+PROVIDE ( _xtos_l1int_handler = 0x4000048c );
+PROVIDE ( _xtos_p_none = 0x4000dbf8 );
+PROVIDE ( _xtos_restore_intlevel = 0x4000056c );
+PROVIDE ( _xtos_return_from_exc = 0x4000dc54 );
+PROVIDE ( _xtos_set_exception_handler = 0x40000454 );
+PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 );
+PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 );
+PROVIDE ( _xtos_set_intlevel = 0x4000dbfc );
+PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 );
+PROVIDE ( _xtos_set_vpri = 0x40000574 );
+PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 );
+PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 );
+PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c );
+PROVIDE ( aes_decrypt = 0x400092d4 );
+PROVIDE ( aes_decrypt_deinit = 0x400092e4 );
+PROVIDE ( aes_decrypt_init = 0x40008ea4 );
+PROVIDE ( aes_unwrap = 0x40009410 );
+PROVIDE ( base64_decode = 0x40009648 );
+PROVIDE ( base64_encode = 0x400094fc );
+PROVIDE ( bzero = 0x4000de84 );
+PROVIDE ( cmd_parse = 0x40000814 );
+PROVIDE ( conv_str_decimal = 0x40000b24 );
+PROVIDE ( conv_str_hex = 0x40000cb8 );
+PROVIDE ( convert_para_str = 0x40000a60 );
+PROVIDE ( dtm_get_intr_mask = 0x400026d0 );
+PROVIDE ( dtm_params_init = 0x4000269c );
+PROVIDE ( dtm_set_intr_mask = 0x400026c8 );
+PROVIDE ( dtm_set_params = 0x400026dc );
+PROVIDE ( eprintf = 0x40001d14 );
+PROVIDE ( eprintf_init_buf = 0x40001cb8 );
+PROVIDE ( eprintf_to_host = 0x40001d48 );
+PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 );
+PROVIDE ( est_reset_printf_buf_len = 0x4000249c );
+PROVIDE ( ets_bzero = 0x40002ae8 );
+PROVIDE ( ets_char2xdigit = 0x40002b74 );
+PROVIDE ( ets_delay_us = 0x40002ecc );
+PROVIDE ( ets_enter_sleep = 0x400027b8 );
+PROVIDE ( ets_external_printf = 0x40002578 );
+PROVIDE ( ets_get_cpu_frequency = 0x40002f0c );
+PROVIDE ( ets_getc = 0x40002bcc );
+PROVIDE ( ets_install_external_printf = 0x40002450 );
+PROVIDE ( ets_install_putc1 = 0x4000242c );
+PROVIDE ( ets_install_putc2 = 0x4000248c );
+PROVIDE ( ets_install_uart_printf = 0x40002438 );
+PROVIDE ( ets_intr_lock = 0x40000f74 );
+PROVIDE ( ets_intr_unlock = 0x40000f80 );
+PROVIDE ( ets_isr_attach = 0x40000f88 );
+PROVIDE ( ets_isr_mask = 0x40000f98 );
+PROVIDE ( ets_isr_unmask = 0x40000fa8 );
+PROVIDE ( ets_memcmp = 0x400018d4 );
+PROVIDE ( ets_memcpy = 0x400018b4 );
+PROVIDE ( ets_memmove = 0x400018c4 );
+PROVIDE ( ets_memset = 0x400018a4 );
+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_set_user_start = 0x40000fbc );
+PROVIDE ( ets_str2macaddr = 0x40002af8 );
+PROVIDE ( ets_strcmp = 0x40002aa8 );
+PROVIDE ( ets_strcpy = 0x40002a88 );
+PROVIDE ( ets_strlen = 0x40002ac8 );
+PROVIDE ( ets_strncmp = 0x40002ab8 );
+PROVIDE ( ets_strncpy = 0x40002a98 );
+PROVIDE ( ets_strstr = 0x40002ad8 );
+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_setfn = 0x40002c48 );
+PROVIDE ( ets_uart_printf = 0x40002544 );
+PROVIDE ( ets_update_cpu_frequency = 0x40002f04 );
+PROVIDE ( ets_vprintf = 0x40001f00 );
+PROVIDE ( ets_wdt_disable = 0x400030f0 );
+PROVIDE ( ets_wdt_enable = 0x40002fa0 );
+PROVIDE ( ets_wdt_get_mode = 0x40002f34 );
+PROVIDE ( ets_wdt_init = 0x40003170 );
+PROVIDE ( ets_wdt_restore = 0x40003158 );
+PROVIDE ( ets_write_char = 0x40001da0 );
+PROVIDE ( get_first_seg = 0x4000091c );
+PROVIDE ( gpio_init = 0x40004c50 );
+PROVIDE ( gpio_input_get = 0x40004cf0 );
+PROVIDE ( gpio_intr_ack = 0x40004dcc );
+PROVIDE ( gpio_intr_handler_register = 0x40004e28 );
+PROVIDE ( gpio_intr_pending = 0x40004d88 );
+PROVIDE ( gpio_intr_test = 0x40004efc );
+PROVIDE ( gpio_output_set = 0x40004cd0 );
+PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 );
+PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 );
+PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 );
+PROVIDE ( gpio_register_get = 0x40004d5c );
+PROVIDE ( gpio_register_set = 0x40004d04 );
+PROVIDE ( hmac_md5 = 0x4000a2cc );
+PROVIDE ( hmac_md5_vector = 0x4000a160 );
+PROVIDE ( hmac_sha1 = 0x4000ba28 );
+PROVIDE ( hmac_sha1_vector = 0x4000b8b4 );
+PROVIDE ( lldesc_build_chain = 0x40004f40 );
+PROVIDE ( lldesc_num2link = 0x40005050 );
+PROVIDE ( lldesc_set_owner = 0x4000507c );
+PROVIDE ( main = 0x40000fec );
+PROVIDE ( md5_vector = 0x400097ac );
+PROVIDE ( mem_calloc = 0x40001c2c );
+PROVIDE ( mem_free = 0x400019e0 );
+PROVIDE ( mem_init = 0x40001998 );
+PROVIDE ( mem_malloc = 0x40001b40 );
+PROVIDE ( mem_realloc = 0x40001c6c );
+PROVIDE ( mem_trim = 0x40001a14 );
+PROVIDE ( mem_zalloc = 0x40001c58 );
+PROVIDE ( memcmp = 0x4000dea8 );
+PROVIDE ( memcpy = 0x4000df48 );
+PROVIDE ( memmove = 0x4000e04c );
+PROVIDE ( memset = 0x4000e190 );
+PROVIDE ( multofup = 0x400031c0 );
+PROVIDE ( pbkdf2_sha1 = 0x4000b840 );
+PROVIDE ( phy_get_romfuncs = 0x40006b08 );
+PROVIDE ( rand = 0x40000600 );
+PROVIDE ( rc4_skip = 0x4000dd68 );
+PROVIDE ( recv_packet = 0x40003d08 );
+PROVIDE ( remove_head_space = 0x40000a04 );
+PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 );
+PROVIDE ( rijndaelKeySetupEnc = 0x40009300 );
+PROVIDE ( rom_abs_temp = 0x400060c0 );
+PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 );
+PROVIDE ( rom_cal_tos_v50 = 0x40007a28 );
+PROVIDE ( rom_chip_50_set_channel = 0x40006f84 );
+PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 );
+PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec );
+PROVIDE ( rom_chip_v5_rx_init = 0x4000711c );
+PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c );
+PROVIDE ( rom_chip_v5_tx_init = 0x4000718c );
+PROVIDE ( rom_dc_iq_est = 0x4000615c );
+PROVIDE ( rom_en_pwdet = 0x400061b8 );
+PROVIDE ( rom_get_bb_atten = 0x40006238 );
+PROVIDE ( rom_get_corr_power = 0x40006260 );
+PROVIDE ( rom_get_fm_sar_dout = 0x400062dc );
+PROVIDE ( rom_get_noisefloor = 0x40006394 );
+PROVIDE ( rom_get_power_db = 0x400063b0 );
+PROVIDE ( rom_i2c_readReg = 0x40007268 );
+PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c );
+PROVIDE ( rom_i2c_writeReg = 0x400072d8 );
+PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c );
+PROVIDE ( rom_iq_est_disable = 0x40006400 );
+PROVIDE ( rom_iq_est_enable = 0x40006430 );
+PROVIDE ( rom_linear_to_db = 0x40006484 );
+PROVIDE ( rom_mhz2ieee = 0x400065a4 );
+PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 );
+PROVIDE ( rom_pbus_debugmode = 0x4000737c );
+PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 );
+PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 );
+PROVIDE ( rom_pbus_force_test = 0x4000747c );
+PROVIDE ( rom_pbus_rd = 0x400074d8 );
+PROVIDE ( rom_pbus_set_rxgain = 0x4000754c );
+PROVIDE ( rom_pbus_set_txgain = 0x40007610 );
+PROVIDE ( rom_pbus_workmode = 0x40007648 );
+PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 );
+PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc );
+PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc );
+PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 );
+PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 );
+PROVIDE ( rom_phy_reset_req = 0x40007804 );
+PROVIDE ( rom_restart_cal = 0x4000781c );
+PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 );
+PROVIDE ( rom_rfcal_rxiq = 0x4000804c );
+PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 );
+PROVIDE ( rom_rfcal_txcap = 0x40008388 );
+PROVIDE ( rom_rfcal_txiq = 0x40008610 );
+PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 );
+PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 );
+PROVIDE ( rom_rfpll_reset = 0x40007868 );
+PROVIDE ( rom_rfpll_set_freq = 0x40007968 );
+PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c );
+PROVIDE ( rom_rxiq_get_mis = 0x40006628 );
+PROVIDE ( rom_sar_init = 0x40006738 );
+PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c );
+PROVIDE ( rom_set_channel_freq = 0x40006c50 );
+PROVIDE ( rom_set_loopback_gain = 0x400067c8 );
+PROVIDE ( rom_set_noise_floor = 0x40006830 );
+PROVIDE ( rom_set_rxclk_en = 0x40006550 );
+PROVIDE ( rom_set_txbb_atten = 0x40008c6c );
+PROVIDE ( rom_set_txclk_en = 0x4000650c );
+PROVIDE ( rom_set_txiq_cal = 0x40008d34 );
+PROVIDE ( rom_start_noisefloor = 0x40006874 );
+PROVIDE ( rom_start_tx_tone = 0x400068b4 );
+PROVIDE ( rom_stop_tx_tone = 0x4000698c );
+PROVIDE ( rom_tx_mac_disable = 0x40006a98 );
+PROVIDE ( rom_tx_mac_enable = 0x40006ad4 );
+PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c );
+PROVIDE ( rom_write_rfpll_sdm = 0x400078dc );
+PROVIDE ( roundup2 = 0x400031b4 );
+PROVIDE ( rtc_enter_sleep = 0x40002870 );
+PROVIDE ( rtc_get_reset_reason = 0x400025e0 );
+PROVIDE ( rtc_intr_handler = 0x400029ec );
+PROVIDE ( rtc_set_sleep_mode = 0x40002668 );
+PROVIDE ( save_rxbcn_mactime = 0x400027a4 );
+PROVIDE ( save_tsf_us = 0x400027ac );
+PROVIDE ( send_packet = 0x40003c80 );
+PROVIDE ( sha1_prf = 0x4000ba48 );
+PROVIDE ( sha1_vector = 0x4000a2ec );
+PROVIDE ( sip_alloc_to_host_evt = 0x40005180 );
+PROVIDE ( sip_get_ptr = 0x400058a8 );
+PROVIDE ( sip_get_state = 0x40005668 );
+PROVIDE ( sip_init_attach = 0x4000567c );
+PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c );
+PROVIDE ( sip_install_rx_data_cb = 0x4000545c );
+PROVIDE ( sip_post = 0x400050fc );
+PROVIDE ( sip_post_init = 0x400056c4 );
+PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c );
+PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 );
+PROVIDE ( sip_send = 0x40005808 );
+PROVIDE ( sip_to_host_chain_append = 0x40005864 );
+PROVIDE ( sip_to_host_evt_send_done = 0x40005234 );
+PROVIDE ( slc_add_credits = 0x400060ac );
+PROVIDE ( slc_enable = 0x40005d90 );
+PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 );
+PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 );
+PROVIDE ( slc_init_attach = 0x40005c50 );
+PROVIDE ( slc_init_credit = 0x4000608c );
+PROVIDE ( slc_pause_from_host = 0x40006014 );
+PROVIDE ( slc_reattach = 0x40005c1c );
+PROVIDE ( slc_resume_from_host = 0x4000603c );
+PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 );
+PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 );
+PROVIDE ( slc_send_to_host_chain = 0x40005de4 );
+PROVIDE ( slc_set_host_io_max_window = 0x40006068 );
+PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 );
+PROVIDE ( software_reset = 0x4000264c );
+PROVIDE ( spi_flash_attach = 0x40004644 );
+PROVIDE ( srand = 0x400005f0 );
+PROVIDE ( strcmp = 0x4000bdc8 );
+PROVIDE ( strcpy = 0x4000bec8 );
+PROVIDE ( strlen = 0x4000bf4c );
+PROVIDE ( strncmp = 0x4000bfa8 );
+PROVIDE ( strncpy = 0x4000c0a0 );
+PROVIDE ( strstr = 0x4000e1e0 );
+PROVIDE ( timer_insert = 0x40002c64 );
+PROVIDE ( uartAttach = 0x4000383c );
+PROVIDE ( uart_baudrate_detect = 0x40003924 );
+PROVIDE ( uart_buff_switch = 0x400038a4 );
+PROVIDE ( uart_div_modify = 0x400039d8 );
+PROVIDE ( uart_rx_intr_handler = 0x40003bbc );
+PROVIDE ( uart_rx_one_char = 0x40003b8c );
+PROVIDE ( uart_rx_one_char_block = 0x40003b64 );
+PROVIDE ( uart_rx_readbuff = 0x40003ec8 );
+PROVIDE ( uart_tx_one_char = 0x40003b30 );
+PROVIDE ( wepkey_128 = 0x4000bc40 );
+PROVIDE ( wepkey_64 = 0x4000bb3c );
+PROVIDE ( xthal_bcopy = 0x40000688 );
+PROVIDE ( xthal_copy123 = 0x4000074c );
+PROVIDE ( xthal_get_ccompare = 0x4000dd4c );
+PROVIDE ( xthal_get_ccount = 0x4000dd38 );
+PROVIDE ( xthal_get_interrupt = 0x4000dd58 );
+PROVIDE ( xthal_get_intread = 0x4000dd58 );
+PROVIDE ( xthal_memcpy = 0x400006c4 );
+PROVIDE ( xthal_set_ccompare = 0x4000dd40 );
+PROVIDE ( xthal_set_intclear = 0x4000dd60 );
+PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 );
+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);
diff --git a/ports/esp8266/esp8266.ld b/ports/esp8266/esp8266.ld
new file mode 100644
index 000000000..deeb82b45
--- /dev/null
+++ b/ports/esp8266/esp8266.ld
@@ -0,0 +1,12 @@
+/* GNU linker script for ESP8266 */
+
+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 = 0x40209000, len = 0x8f000
+}
+
+/* define common sections and symbols */
+INCLUDE esp8266_common.ld
diff --git a/ports/esp8266/esp8266_512k.ld b/ports/esp8266/esp8266_512k.ld
new file mode 100644
index 000000000..0ae663db1
--- /dev/null
+++ b/ports/esp8266/esp8266_512k.ld
@@ -0,0 +1,12 @@
+/* GNU linker script for ESP8266 */
+
+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 = 0x40209000, len = 0x72000
+}
+
+/* define common sections and symbols */
+INCLUDE esp8266_common.ld
diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld
new file mode 100644
index 000000000..de5268c8f
--- /dev/null
+++ b/ports/esp8266/esp8266_common.ld
@@ -0,0 +1,298 @@
+/* GNU linker script for ESP8266, common sections and symbols */
+
+/* define the top of RAM */
+_heap_end = ORIGIN(dram0_0_seg) + LENGTH(dram0_0_seg);
+
+PHDRS
+{
+ dport0_0_phdr PT_LOAD;
+ dram0_0_phdr PT_LOAD;
+ dram0_0_bss_phdr PT_LOAD;
+ iram1_0_phdr PT_LOAD;
+ irom0_0_phdr PT_LOAD;
+}
+
+ENTRY(firmware_start)
+EXTERN(_DebugExceptionVector)
+EXTERN(_DoubleExceptionVector)
+EXTERN(_KernelExceptionVector)
+EXTERN(_NMIExceptionVector)
+EXTERN(_UserExceptionVector)
+
+_firmware_size = ORIGIN(irom0_0_seg) + LENGTH(irom0_0_seg) - 0x40200000;
+
+PROVIDE(_memmap_vecbase_reset = 0x40000000);
+
+/* Various memory-map dependent cache attribute settings: */
+_memmap_cacheattr_wb_base = 0x00000110;
+_memmap_cacheattr_wt_base = 0x00000110;
+_memmap_cacheattr_bp_base = 0x00000220;
+_memmap_cacheattr_unused_mask = 0xFFFFF00F;
+_memmap_cacheattr_wb_trapnull = 0x2222211F;
+_memmap_cacheattr_wba_trapnull = 0x2222211F;
+_memmap_cacheattr_wbna_trapnull = 0x2222211F;
+_memmap_cacheattr_wt_trapnull = 0x2222211F;
+_memmap_cacheattr_bp_trapnull = 0x2222222F;
+_memmap_cacheattr_wb_strict = 0xFFFFF11F;
+_memmap_cacheattr_wt_strict = 0xFFFFF11F;
+_memmap_cacheattr_bp_strict = 0xFFFFF22F;
+_memmap_cacheattr_wb_allvalid = 0x22222112;
+_memmap_cacheattr_wt_allvalid = 0x22222112;
+_memmap_cacheattr_bp_allvalid = 0x22222222;
+PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
+
+SECTIONS
+{
+
+ .dport0.rodata : ALIGN(4)
+ {
+ _dport0_rodata_start = ABSOLUTE(.);
+ *(.dport0.rodata)
+ *(.dport.rodata)
+ _dport0_rodata_end = ABSOLUTE(.);
+ } >dport0_0_seg :dport0_0_phdr
+
+ .dport0.literal : ALIGN(4)
+ {
+ _dport0_literal_start = ABSOLUTE(.);
+ *(.dport0.literal)
+ *(.dport.literal)
+ _dport0_literal_end = ABSOLUTE(.);
+ } >dport0_0_seg :dport0_0_phdr
+
+ .dport0.data : ALIGN(4)
+ {
+ _dport0_data_start = ABSOLUTE(.);
+ *(.dport0.data)
+ *(.dport.data)
+ _dport0_data_end = ABSOLUTE(.);
+ } >dport0_0_seg :dport0_0_phdr
+
+ .irom0.text : ALIGN(4)
+ {
+ _irom0_text_start = ABSOLUTE(.);
+ *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)
+
+ /* we put some specific text in this section */
+
+ *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/persistentcode*.o*(.literal* .text*)
+ *py/formatfloat.o*(.literal* .text*)
+ *py/frozenmod.o*(.literal* .text*)
+ *py/gc.o*(.literal* .text*)
+ *py/reader*.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/scheduler.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/oofatfs/*.o*(.literal*, .text*)
+ */libaxtls.a:(.literal*, .text*)
+ *lib/berkeley-db-1.xx/*.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*)
+
+ build/main.o(.literal* .text*)
+ *gccollect.o(.literal* .text*)
+ *gchelper.o(.literal* .text*)
+ *help.o(.literal* .text*)
+ *lexerstr32.o(.literal* .text*)
+ *utils.o(.literal* .text*)
+ *modpyb.o(.literal*, .text*)
+ *machine_pin.o(.literal*, .text*)
+ *machine_pwm.o(.literal*, .text*)
+ *machine_rtc.o(.literal*, .text*)
+ *machine_adc.o(.literal*, .text*)
+ *machine_uart.o(.literal*, .text*)
+ *modpybi2c.o(.literal*, .text*)
+ *modmachine.o(.literal*, .text*)
+ *machine_wdt.o(.literal*, .text*)
+ *machine_spi.o(.literal*, .text*)
+ *machine_hspi.o(.literal*, .text*)
+ *hspi.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*)
+ *modonewire.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)
+ *.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
+
+ .text : ALIGN(4)
+ {
+ _stext = .;
+ _text_start = ABSOLUTE(.);
+ *(.UserEnter.text)
+ . = ALIGN(16);
+ *(.DebugExceptionVector.text)
+ . = ALIGN(16);
+ *(.NMIExceptionVector.text)
+ . = ALIGN(16);
+ *(.KernelExceptionVector.text)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ . = ALIGN(16);
+ *(.UserExceptionVector.text)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ . = ALIGN(16);
+ *(.DoubleExceptionVector.text)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ LONG(0)
+ . = ALIGN (16);
+ *(.entry.text)
+ *(.init.literal)
+ *(.init)
+ *(.literal .text .literal.* .text.* .iram0.literal .iram0.text .iram0.text.*.literal .iram0.text.*)
+ *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
+ *(.fini.literal)
+ *(.fini)
+ *(.gnu.version)
+ _text_end = ABSOLUTE(.);
+ _etext = .;
+ } >iram1_0_seg :iram1_0_phdr
+
+ .lit4 : ALIGN(4)
+ {
+ _lit4_start = ABSOLUTE(.);
+ *(*.lit4)
+ *(.lit4.*)
+ *(.gnu.linkonce.lit4.*)
+ _lit4_end = ABSOLUTE(.);
+ } >iram1_0_seg :iram1_0_phdr
+
+ .data : ALIGN(4)
+ {
+ _data_start = ABSOLUTE(.);
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ *(.data1)
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ *(.sdata2)
+ *(.sdata2.*)
+ *(.gnu.linkonce.s2.*)
+ *(.jcr)
+ _data_end = ABSOLUTE(.);
+ } >dram0_0_seg :dram0_0_phdr
+
+ .rodata : ALIGN(4)
+ {
+ _rodata_start = ABSOLUTE(.);
+ *(.sdk.version)
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+ *(.rodata1)
+ __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);
+ *(.xt_except_table)
+ *(.gcc_except_table)
+ *(.gnu.linkonce.e.*)
+ *(.gnu.version_r)
+ *(.eh_frame)
+ /* C++ constructor and destructor tables, properly ordered: */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ /* C++ exception handlers table: */
+ __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);
+ *(.xt_except_desc)
+ *(.gnu.linkonce.h.*)
+ __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
+ *(.xt_except_desc_end)
+ *(.dynamic)
+ *(.gnu.version_d)
+ . = ALIGN(4); /* this table MUST be 4-byte aligned */
+ _bss_table_start = ABSOLUTE(.);
+ LONG(_bss_start)
+ LONG(_bss_end)
+ _bss_table_end = ABSOLUTE(.);
+ _rodata_end = ABSOLUTE(.);
+ } >dram0_0_seg :dram0_0_phdr
+
+ .bss ALIGN(8) (NOLOAD) : ALIGN(4)
+ {
+ . = ALIGN (8);
+ _bss_start = ABSOLUTE(.);
+ *(.dynsbss)
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb.*)
+ *(.scommon)
+ *(.sbss2)
+ *(.sbss2.*)
+ *(.gnu.linkonce.sb2.*)
+ *(.dynbss)
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN (8);
+ _bss_end = ABSOLUTE(.);
+ _heap_start = ABSOLUTE(.);
+ } >dram0_0_seg :dram0_0_bss_phdr
+}
+
+/* get ROM code address */
+INCLUDE "eagle.rom.addr.v6.ld"
diff --git a/ports/esp8266/esp8266_ota.ld b/ports/esp8266/esp8266_ota.ld
new file mode 100644
index 000000000..604480a0a
--- /dev/null
+++ b/ports/esp8266/esp8266_ota.ld
@@ -0,0 +1,13 @@
+/* GNU linker script for ESP8266 */
+
+MEMORY
+{
+ dport0_0_seg : org = 0x3ff00000, len = 0x10
+ dram0_0_seg : org = 0x3ffe8000, len = 0x14000
+ iram1_0_seg : org = 0x40100000, len = 0x8000
+ /* 0x3c000 is size of bootloader, 0x9000 is size of packed RAM segments */
+ irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000
+}
+
+/* define common sections and symbols */
+INCLUDE esp8266_common.ld
diff --git a/ports/esp8266/esp_init_data.c b/ports/esp8266/esp_init_data.c
new file mode 100644
index 000000000..b14de573a
--- /dev/null
+++ b/ports/esp8266/esp_init_data.c
@@ -0,0 +1,77 @@
+/*
+ * 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 "ets_sys.h"
+#include "etshal.h"
+#include "esp_mphal.h"
+#include "user_interface.h"
+#include "extmod/misc.h"
+
+NORETURN void call_user_start(void);
+void ets_printf(const char *fmt, ...);
+extern char flashchip;
+
+static const uint8_t default_init_data[] __attribute__((aligned(4))) = {
+0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
+0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00,
+0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
+0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void firmware_start(void) {
+ // For SDK 1.5.2, either address has shifted and not mirrored in
+ // eagle.rom.addr.v6.ld, or extra initial member was added.
+ SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4);
+
+ char buf[128];
+ SPIRead(flash->chip_size - 4 * 0x1000, buf, sizeof(buf));
+ /*for (int i = 0; i < sizeof(buf); i++) {
+ static char hexf[] = "%x ";
+ ets_printf(hexf, buf[i]);
+ }*/
+
+ bool inited = false;
+ for (int i = 0; i < sizeof(buf); i++) {
+ if (buf[i] != 0xff) {
+ inited = true;
+ break;
+ }
+ }
+
+ if (!inited) {
+ static char msg[] = "Writing init data\n";
+ ets_printf(msg);
+ SPIRead((uint32_t)&default_init_data - 0x40200000, buf, sizeof(buf));
+ SPIWrite(flash->chip_size - 4 * 0x1000, buf, sizeof(buf));
+ }
+
+ asm("j call_user_start");
+}
diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c
new file mode 100644
index 000000000..61848fd34
--- /dev/null
+++ b/ports/esp8266/esp_mphal.c
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "ets_sys.h"
+#include "etshal.h"
+#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 "py/runtime.h"
+#include "extmod/misc.h"
+#include "lib/utils/pyexec.h"
+
+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);
+}
+
+void mp_hal_delay_us(uint32_t 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 = ringbuf_get(&input_buf);
+ if (c != -1) {
+ return c;
+ }
+ #if 0
+ // Idles CPU but need more testing before enabling
+ if (!ets_loop_iter()) {
+ asm("waiti 0");
+ }
+ #else
+ mp_hal_delay_us(1);
+ #endif
+ }
+}
+
+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--) {
+ 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');
+ }
+ uart_tx_one_char(UART0, *str++);
+ }
+}
+
+uint32_t mp_hal_ticks_ms(void) {
+ return ((uint64_t)system_time_high_word << 32 | (uint64_t)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 ets_event_poll(void) {
+ ets_loop_iter();
+ mp_handle_pending();
+}
+
+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 readinto_m[3];
+ mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_readinto, readinto_m);
+ readinto_m[2] = MP_STATE_PORT(dupterm_arr_obj);
+ mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
+ if (res == mp_const_none) {
+ nlr_pop();
+ return -2;
+ }
+ if (res == MP_OBJ_NEW_SMALL_INT(0)) {
+ mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
+ nlr_pop();
+ return -1;
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
+ nlr_pop();
+ if (*(byte*)bufinfo.buf == mp_interrupt_char) {
+ mp_keyboard_interrupt();
+ return -2;
+ }
+ return *(byte*)bufinfo.buf;
+ } else {
+ mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
+ }
+
+ return -1;
+}
+
+STATIC void dupterm_task_handler(os_event_t *evt) {
+ static byte lock;
+ if (lock) {
+ return;
+ }
+ lock = 1;
+ while (1) {
+ int c = call_dupterm_read();
+ if (c < 0) {
+ break;
+ }
+ ringbuf_put(&input_buf, c);
+ }
+ mp_hal_signal_input();
+ lock = 0;
+}
+
+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);
+}
+
+// Get pointer to esf_buf bookkeeping structure
+void *ets_get_esf_buf_ctlblk(void) {
+ // Get literal ptr before start of esf_rx_buf_alloc func
+ extern void *esf_rx_buf_alloc();
+ return ((void**)esf_rx_buf_alloc)[-1];
+}
+
+// Get number of esf_buf free buffers of given type, as encoded by index
+// idx 0 corresponds to buf types 1, 2; 1 - 4; 2 - 5; 3 - 7; 4 - 8
+// Only following buf types appear to be used:
+// 1 - tx buffer, 5 - management frame tx buffer; 8 - rx buffer
+int ets_esf_free_bufs(int idx) {
+ uint32_t *p = ets_get_esf_buf_ctlblk();
+ uint32_t *b = (uint32_t*)p[idx];
+ int cnt = 0;
+ while (b) {
+ b = (uint32_t*)b[0x20 / 4];
+ cnt++;
+ }
+ return cnt;
+}
+
+extern int mp_stream_errno;
+int *__errno() {
+ return &mp_stream_errno;
+}
diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h
new file mode 100644
index 000000000..913bd70dc
--- /dev/null
+++ b/ports/esp8266/esp_mphal.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/ringbuf.h"
+#include "lib/utils/interrupt_char.h"
+#include "xtirq.h"
+
+void mp_keyboard_interrupt(void);
+
+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);
+
+uint32_t mp_hal_ticks_us(void);
+__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
+ uint32_t ccount;
+ __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
+ return ccount;
+}
+
+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(); }
+
+// needed for machine.I2C
+#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/modmachine.h"
+#define MP_HAL_PIN_FMT "%u"
+#define mp_hal_pin_obj_t uint32_t
+#define mp_hal_get_pin_obj(o) mp_obj_get_pin(o)
+#define mp_hal_pin_name(p) (p)
+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)
+#define mp_hal_pin_od_high(p) do { \
+ if ((p) == 16) { WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1)); } \
+ else { gpio_output_set(1 << (p), 0, 1 << (p), 0); } \
+ } while (0)
+#define mp_hal_pin_read(p) pin_get(p)
+#define mp_hal_pin_write(p, v) pin_set((p), (v))
+
+void *ets_get_esf_buf_ctlblk(void);
+int ets_esf_free_bufs(int idx);
diff --git a/ports/esp8266/espapa102.c b/ports/esp8266/espapa102.c
new file mode 100644
index 000000000..4295fe42d
--- /dev/null
+++ b/ports/esp8266/espapa102.c
@@ -0,0 +1,115 @@
+/*
+ * 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 "py/mpconfig.h"
+#if MICROPY_ESP8266_APA102
+
+#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);
+}
+
+#endif
diff --git a/ports/esp8266/espapa102.h b/ports/esp8266/espapa102.h
new file mode 100644
index 000000000..dd7c5ab72
--- /dev/null
+++ b/ports/esp8266/espapa102.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_ESP8266_ESPAPA102_H
+#define MICROPY_INCLUDED_ESP8266_ESPAPA102_H
+
+void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32_t numBytes);
+
+#endif // MICROPY_INCLUDED_ESP8266_ESPAPA102_H
diff --git a/ports/esp8266/espneopixel.c b/ports/esp8266/espneopixel.c
new file mode 100644
index 000000000..6c7659186
--- /dev/null
+++ b/ports/esp8266/espneopixel.c
@@ -0,0 +1,65 @@
+// Original version from https://github.com/adafruit/Adafruit_NeoPixel
+// Modifications by dpgeorge to support auto-CPU-frequency detection
+
+// This is a mash-up of the Due show() code + insights from Michael Miller's
+// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
+// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
+
+#include "py/mpconfig.h"
+#if MICROPY_ESP8266_NEOPIXEL
+
+#include "c_types.h"
+#include "eagle_soc.h"
+#include "user_interface.h"
+#include "espneopixel.h"
+#include "esp_mphal.h"
+
+#define NEO_KHZ400 (1)
+
+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 / 2857143; // 0.35us
+ 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
+
+ uint32_t irq_state = mp_hal_quiet_timing_enter();
+ for(t = time0;; t = time0) {
+ if(pix & mask) t = time1; // Bit high duration
+ while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
+ GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
+ startTime = c; // Save start time
+ while(((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
+ GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
+ if(!(mask >>= 1)) { // Next bit/byte
+ if(p >= end) break;
+ pix = *p++;
+ mask = 0x80;
+ }
+ }
+ while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
+ mp_hal_quiet_timing_exit(irq_state);
+}
+
+#endif // MICROPY_ESP8266_NEOPIXEL
diff --git a/ports/esp8266/espneopixel.h b/ports/esp8266/espneopixel.h
new file mode 100644
index 000000000..c444740ff
--- /dev/null
+++ b/ports/esp8266/espneopixel.h
@@ -0,0 +1,6 @@
+#ifndef MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
+#define MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
+
+void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz);
+
+#endif // MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H
diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c
new file mode 100644
index 000000000..f1d7060df
--- /dev/null
+++ b/ports/esp8266/esppwm.c
@@ -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;
+}
diff --git a/ports/esp8266/esppwm.h b/ports/esp8266/esppwm.h
new file mode 100644
index 000000000..1ee4a2f55
--- /dev/null
+++ b/ports/esp8266/esppwm.h
@@ -0,0 +1,17 @@
+#ifndef MICROPY_INCLUDED_ESP8266_ESPPWM_H
+#define MICROPY_INCLUDED_ESP8266_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 // MICROPY_INCLUDED_ESP8266_ESPPWM_H
diff --git a/ports/esp8266/ets_alt_task.c b/ports/esp8266/ets_alt_task.c
new file mode 100644
index 000000000..ff7dba186
--- /dev/null
+++ b/ports/esp8266/ets_alt_task.c
@@ -0,0 +1,214 @@
+#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"
+#include "ets_alt_task.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 1;
+ }
+ 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 0;
+#endif
+}
+
+int ets_loop_iter_disable = 0;
+
+// to implement a 64-bit wide microsecond counter
+static uint32_t system_time_prev = 0;
+uint32_t system_time_high_word = 0;
+
+bool ets_loop_iter(void) {
+ if (ets_loop_iter_disable) {
+ return false;
+ }
+
+ // handle overflow of system microsecond counter
+ ets_intr_lock();
+ uint32_t system_time_cur = system_get_time();
+ if (system_time_cur < system_time_prev) {
+ system_time_high_word += 1; // record overflow of low 32-bits
+ }
+ system_time_prev = system_time_cur;
+ ets_intr_unlock();
+
+ //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;
+}
diff --git a/ports/esp8266/ets_alt_task.h b/ports/esp8266/ets_alt_task.h
new file mode 100644
index 000000000..33a9d3a00
--- /dev/null
+++ b/ports/esp8266/ets_alt_task.h
@@ -0,0 +1,9 @@
+#ifndef MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H
+#define MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H
+
+extern int ets_loop_iter_disable;
+extern uint32_t system_time_high_word;
+
+bool ets_loop_iter(void);
+
+#endif // MICROPY_INCLUDED_ESP8266_ETS_ALT_TASK_H
diff --git a/ports/esp8266/etshal.h b/ports/esp8266/etshal.h
new file mode 100644
index 000000000..34787779f
--- /dev/null
+++ b/ports/esp8266/etshal.h
@@ -0,0 +1,45 @@
+#ifndef MICROPY_INCLUDED_ESP8266_ETSHAL_H
+#define MICROPY_INCLUDED_ESP8266_ETSHAL_H
+
+#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 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);
+
+extern void ets_wdt_disable(void);
+extern void wdt_feed(void);
+
+// Opaque structure
+#ifndef MD5_CTX
+typedef char MD5_CTX[88];
+#endif
+
+void MD5Init(MD5_CTX *context);
+void MD5Update(MD5_CTX *context, const void *data, unsigned int len);
+void MD5Final(unsigned char digest[16], MD5_CTX *context);
+
+// These prototypes are for recent SDKs with "malloc tracking"
+void *pvPortMalloc(unsigned sz, const char *fname, int line);
+void *pvPortZalloc(unsigned sz, const char *fname, int line);
+void *pvPortRealloc(void *p, unsigned sz, const char *fname, int line);
+void vPortFree(void *p, const char *fname, int line);
+
+uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len);
+uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len);
+uint32_t SPIEraseSector(int sector);
+
+#endif // MICROPY_INCLUDED_ESP8266_ETSHAL_H
diff --git a/ports/esp8266/fatfs_port.c b/ports/esp8266/fatfs_port.c
new file mode 100644
index 000000000..a8865c817
--- /dev/null
+++ b/ports/esp8266/fatfs_port.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "lib/timeutils/timeutils.h"
+#include "lib/oofatfs/ff.h"
+#include "modmachine.h"
+
+DWORD get_fattime(void) {
+
+ // TODO: Optimize division (there's no HW division support on ESP8266,
+ // so it's expensive).
+ uint32_t secs = (uint32_t)(pyb_rtc_get_us_since_2000() / 1000000);
+
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_2000_to_struct_time(secs, &tm);
+
+ return (((DWORD)(tm.tm_year - 1980) << 25) | ((DWORD)tm.tm_mon << 21) | ((DWORD)tm.tm_mday << 16) |
+ ((DWORD)tm.tm_hour << 11) | ((DWORD)tm.tm_min << 5) | ((DWORD)tm.tm_sec >> 1));
+}
diff --git a/ports/esp8266/gccollect.c b/ports/esp8266/gccollect.c
new file mode 100644
index 000000000..cd5d4932c
--- /dev/null
+++ b/ports/esp8266/gccollect.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "py/gc.h"
+#include "gccollect.h"
+
+// As we do not have control over the application entry point, there is no way
+// to figure out the real stack base on runtime, so it needs to be hardcoded
+#define STACK_END 0x40000000
+
+mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs);
+
+void gc_collect(void) {
+ // start the GC
+ gc_collect_start();
+
+ // get the registers and the sp
+ mp_uint_t regs[8];
+ mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
+
+ // trace the stack, including the registers (since they live on the stack in this function)
+ gc_collect_root((void**)sp, (STACK_END - sp) / sizeof(uint32_t));
+
+ #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
+ // trace any native code because it can contain pointers to the heap
+ esp_native_code_gc_collect();
+ #endif
+
+ // end the GC
+ gc_collect_end();
+}
diff --git a/ports/esp8266/gccollect.h b/ports/esp8266/gccollect.h
new file mode 100644
index 000000000..5735d8a39
--- /dev/null
+++ b/ports/esp8266/gccollect.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ESP8266_GCCOLLECT_H
+#define MICROPY_INCLUDED_ESP8266_GCCOLLECT_H
+
+extern uint32_t _text_start;
+extern uint32_t _text_end;
+extern uint32_t _irom0_text_start;
+extern uint32_t _irom0_text_end;
+extern uint32_t _data_start;
+extern uint32_t _data_end;
+extern uint32_t _rodata_start;
+extern uint32_t _rodata_end;
+extern uint32_t _bss_start;
+extern uint32_t _bss_end;
+extern uint32_t _heap_start;
+extern uint32_t _heap_end;
+
+void gc_collect(void);
+void esp_native_code_gc_collect(void);
+
+#endif // MICROPY_INCLUDED_ESP8266_GCCOLLECT_H
diff --git a/ports/esp8266/gchelper.s b/ports/esp8266/gchelper.s
new file mode 100644
index 000000000..cf543be80
--- /dev/null
+++ b/ports/esp8266/gchelper.s
@@ -0,0 +1,22 @@
+ .file "gchelper.s"
+ .text
+
+ .align 4
+ .global gc_helper_get_regs_and_sp
+ .type gc_helper_get_regs_and_sp, @function
+gc_helper_get_regs_and_sp:
+ # store regs into given array
+ s32i.n a8, a2, 0
+ s32i.n a9, a2, 4
+ s32i.n a10, a2, 8
+ s32i.n a11, a2, 12
+ s32i.n a12, a2, 16
+ s32i.n a13, a2, 20
+ s32i.n a14, a2, 24
+ s32i.n a15, a2, 28
+
+ # return the sp
+ mov a2, a1
+ ret.n
+
+ .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp
diff --git a/ports/esp8266/help.c b/ports/esp8266/help.c
new file mode 100644
index 000000000..2035cdd6c
--- /dev/null
+++ b/ports/esp8266/help.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/builtin.h"
+
+const char *esp_help_text =
+"Welcome to MicroPython!\n"
+"\n"
+"For online docs please visit http://docs.micropython.org/en/latest/esp8266/ .\n"
+"For diagnostic information to include in bug reports execute 'import port_diag'.\n"
+"\n"
+"Basic WiFi configuration:\n"
+"\n"
+"import network\n"
+"sta_if = network.WLAN(network.STA_IF); sta_if.active(True)\n"
+"sta_if.scan() # Scan for available access points\n"
+"sta_if.connect(\"<AP_name>\", \"<password>\") # Connect to an AP\n"
+"sta_if.isconnected() # Check for successful connection\n"
+"# Change name/password of ESP8266's AP:\n"
+"ap_if = network.WLAN(network.AP_IF)\n"
+"ap_if.config(essid=\"<AP_NAME>\", authmode=network.AUTH_WPA_WPA2_PSK, password=\"<password>\")\n"
+"\n"
+"Control commands:\n"
+" CTRL-A -- on a blank line, enter raw REPL mode\n"
+" CTRL-B -- on a blank line, enter normal REPL mode\n"
+" CTRL-C -- interrupt a running program\n"
+" CTRL-D -- on a blank line, do a soft reset of the board\n"
+" CTRL-E -- on a blank line, enter paste mode\n"
+"\n"
+"For further help on a specific object, type help(obj)\n"
+;
diff --git a/ports/esp8266/hspi.c b/ports/esp8266/hspi.c
new file mode 100644
index 000000000..554a50460
--- /dev/null
+++ b/ports/esp8266/hspi.c
@@ -0,0 +1,331 @@
+/*
+* The MIT License (MIT)
+*
+* Copyright (c) 2015 David Ogilvy (MetalPhreak)
+* Modified 2016 by Radomir Dopieralski
+*
+* 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 "hspi.h"
+
+/*
+Wrapper to setup HSPI/SPI GPIO pins and default SPI clock
+ spi_no - SPI (0) or HSPI (1)
+Not used in MicroPython.
+*/
+void spi_init(uint8_t spi_no) {
+ spi_init_gpio(spi_no, SPI_CLK_USE_DIV);
+ spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
+ spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
+ spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
+
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD);
+ CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
+}
+
+
+/*
+Configures SPI mode parameters for clock edge and clock polarity.
+ spi_no - SPI (0) or HSPI (1)
+ spi_cpha - (0) Data is valid on clock leading edge
+ (1) Data is valid on clock trailing edge
+ spi_cpol - (0) Clock is low when inactive
+ (1) Clock is high when inactive
+For MicroPython this version is different from original.
+*/
+void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) {
+ if (spi_cpol) {
+ SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
+ } else {
+ CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
+ }
+ if (spi_cpha == spi_cpol) {
+ // Mode 3 - MOSI is set on falling edge of clock
+ // Mode 0 - MOSI is set on falling edge of clock
+ CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
+ SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
+ } else {
+ // Mode 2 - MOSI is set on rising edge of clock
+ // Mode 1 - MOSI is set on rising edge of clock
+ SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
+ CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
+ }
+}
+
+
+/*
+Initialise the GPIO pins for use as SPI pins.
+ spi_no - SPI (0) or HSPI (1)
+ sysclk_as_spiclk -
+ SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock.
+ SPI_CLK_USE_DIV (0) if using divider for lower speed.
+*/
+void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) {
+ uint32_t clock_div_flag = 0;
+ if (sysclk_as_spiclk) {
+ clock_div_flag = 0x0001;
+ }
+ if (spi_no == SPI) {
+ // Set bit 8 if 80MHz sysclock required
+ WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8));
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);
+ } else if (spi_no == HSPI) {
+ // Set bit 9 if 80MHz sysclock required
+ WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9));
+ // GPIO12 is HSPI MISO pin (Master Data In)
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
+ // GPIO13 is HSPI MOSI pin (Master Data Out)
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
+ // GPIO14 is HSPI CLK pin (Clock)
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
+ // GPIO15 is HSPI CS pin (Chip Select / Slave Select)
+ // In MicroPython, we are handling CS ourself in drivers.
+ // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
+ }
+}
+
+
+/*
+Set up the control registers for the SPI clock
+ spi_no - SPI (0) or HSPI (1)
+ prediv - predivider value (actual division value)
+ cntdiv - postdivider value (actual division value)
+Set either divider to 0 to disable all division (80MHz sysclock)
+*/
+void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) {
+ if (prediv == 0 || cntdiv == 0) {
+ WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK);
+ } else {
+ WRITE_PERI_REG(SPI_CLOCK(spi_no),
+ (((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
+ (((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
+ (((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
+ ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)
+ );
+ }
+}
+
+
+/*
+Setup the byte order for shifting data out of buffer
+ spi_no - SPI (0) or HSPI (1)
+ byte_order -
+ SPI_BYTE_ORDER_HIGH_TO_LOW (1)
+ Data is sent out starting with Bit31 and down to Bit0
+ SPI_BYTE_ORDER_LOW_TO_HIGH (0)
+ Data is sent out starting with the lowest BYTE, from MSB to LSB,
+ followed by the second lowest BYTE, from MSB to LSB, followed by
+ the second highest BYTE, from MSB to LSB, followed by the highest
+ BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB.
+*/
+void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) {
+ if (byte_order) {
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
+ } else {
+ CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
+ }
+}
+
+
+/*
+Setup the byte order for shifting data into buffer
+ spi_no - SPI (0) or HSPI (1)
+ byte_order -
+ SPI_BYTE_ORDER_HIGH_TO_LOW (1)
+ Data is read in starting with Bit31 and down to Bit0
+ SPI_BYTE_ORDER_LOW_TO_HIGH (0)
+ Data is read in starting with the lowest BYTE, from MSB to LSB,
+ followed by the second lowest BYTE, from MSB to LSB, followed by
+ the second highest BYTE, from MSB to LSB, followed by the highest
+ BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB
+*/
+void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) {
+ if (byte_order) {
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
+ } else {
+ CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
+ }
+}
+
+
+/*
+SPI transaction function
+ spi_no - SPI (0) or HSPI (1)
+ cmd_bits - actual number of bits to transmit
+ cmd_data - command data
+ addr_bits - actual number of bits to transmit
+ addr_data - address data
+ dout_bits - actual number of bits to transmit
+ dout_data - output data
+ din_bits - actual number of bits to receive
+Returns: read data - uint32_t containing read in data only if RX was set
+ 0 - something went wrong (or actual read data was 0)
+ 1 - data sent ok (or actual read data is 1)
+Note: all data is assumed to be stored in the lower bits of the data variables
+(for anything <32 bits).
+*/
+uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
+ uint32_t addr_bits, uint32_t addr_data,
+ uint32_t dout_bits, uint32_t dout_data,
+ uint32_t din_bits, uint32_t dummy_bits) {
+ while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
+
+// Enable SPI Functions
+ // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
+ CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
+ SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
+
+ // Enable functions based on number of bits. 0 bits = disabled.
+ // This is rather inefficient but allows for a very generic function.
+ // CMD ADDR and MOSI are set below to save on an extra if statement.
+ if (din_bits) {
+ if (dout_bits) {
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN);
+ } else {
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
+ }
+ }
+ if (dummy_bits) {
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);
+ }
+
+// Setup Bitlengths
+ WRITE_PERI_REG(SPI_USER1(spi_no),
+ // Number of bits in Address
+ ((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S |
+ // Number of bits to Send
+ ((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
+ // Number of bits to receive
+ ((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S |
+ // Number of Dummy bits to insert
+ ((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S);
+
+// Setup Command Data
+ if (cmd_bits) {
+ // Enable COMMAND function in SPI module
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);
+ // Align command data to high bits
+ uint16_t command = cmd_data << (16-cmd_bits);
+ // Swap byte order
+ command = ((command>>8)&0xff) | ((command<<8)&0xff00);
+ WRITE_PERI_REG(SPI_USER2(spi_no), (
+ (((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
+ (command & SPI_USR_COMMAND_VALUE)
+ ));
+ }
+
+// Setup Address Data
+ if (addr_bits) {
+ // Enable ADDRess function in SPI module
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);
+ // Align address data to high bits
+ WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits));
+ }
+
+// Setup DOUT data
+ if (dout_bits) {
+ // Enable MOSI function in SPI module
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
+ // Copy data to W0
+ if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) {
+ WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits));
+ } else {
+ uint8_t dout_extra_bits = dout_bits%8;
+
+ if (dout_extra_bits) {
+ // If your data isn't a byte multiple (8/16/24/32 bits) and you
+ // don't have SPI_WR_BYTE_ORDER set, you need this to move the
+ // non-8bit remainder to the MSBs. Not sure if there's even a use
+ // case for this, but it's here if you need it... For example,
+ // 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output
+ // as if it were 0x0DA4, of which 0xA4, and then 0x0 would be
+ // shifted out (first 8 bits of low byte, then 4 MSB bits of high
+ // byte - ie reverse byte order).
+ // The code below shifts it out as 0xA4 followed by 0xD as you
+ // might require.
+ WRITE_PERI_REG(SPI_W0(spi_no), (
+ (0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data)
+ << (8-dout_extra_bits) |
+ ((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits)))
+ & dout_data)
+ ));
+ } else {
+ WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
+ }
+ }
+}
+
+// Begin SPI Transaction
+ SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+
+// Return DIN data
+ if (din_bits) {
+ while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete
+ if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) {
+ // Assuming data in is written to MSB. TBC
+ return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits);
+ } else {
+ // Read in the same way as DOUT is sent. Note existing contents of
+ // SPI_W0 remain unless overwritten!
+ return READ_PERI_REG(SPI_W0(spi_no));
+ }
+ return 0; // Something went wrong
+ }
+
+ // Transaction completed
+ return 1; // Success
+}
+
+
+/*
+Just do minimal work needed to send 8 bits.
+*/
+inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) {
+ while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
+
+// Enable SPI Functions
+ // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
+ CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
+ SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
+
+// Setup Bitlengths
+ WRITE_PERI_REG(SPI_USER1(spi_no),
+ // Number of bits to Send
+ ((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
+ // Number of bits to receive
+ ((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S);
+
+
+// Setup DOUT data
+ // Enable MOSI function in SPI module
+ SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
+ // Copy data to W0
+ if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) {
+ WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8));
+ } else {
+ WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
+ }
+
+// Begin SPI Transaction
+ SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+}
diff --git a/ports/esp8266/hspi.h b/ports/esp8266/hspi.h
new file mode 100644
index 000000000..c68366ef4
--- /dev/null
+++ b/ports/esp8266/hspi.h
@@ -0,0 +1,79 @@
+/*
+* The MIT License (MIT)
+*
+* Copyright (c) 2015 David Ogilvy (MetalPhreak)
+* Modified 2016 by Radomir Dopieralski
+*
+* 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 SPI_APP_H
+#define SPI_APP_H
+
+#include "hspi_register.h"
+#include "ets_sys.h"
+#include "osapi.h"
+#include "os_type.h"
+
+// Define SPI hardware modules
+#define SPI 0
+#define HSPI 1
+
+#define SPI_CLK_USE_DIV 0
+#define SPI_CLK_80MHZ_NODIV 1
+
+#define SPI_BYTE_ORDER_HIGH_TO_LOW 1
+#define SPI_BYTE_ORDER_LOW_TO_HIGH 0
+
+#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h
+#define CPU_CLK_FREQ (80 * 1000000)
+#endif
+
+// Define some default SPI clock settings
+#define SPI_CLK_PREDIV 10
+#define SPI_CLK_CNTDIV 2
+#define SPI_CLK_FREQ (CPU_CLK_FREQ / (SPI_CLK_PREDIV * SPI_CLK_CNTDIV))
+// 80 / 20 = 4 MHz
+
+void spi_init(uint8_t spi_no);
+void spi_mode(uint8_t spi_no, uint8_t spi_cpha,uint8_t spi_cpol);
+void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk);
+void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv);
+void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order);
+void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order);
+uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
+ uint32_t addr_bits, uint32_t addr_data,
+ uint32_t dout_bits, uint32_t dout_data,
+ uint32_t din_bits, uint32_t dummy_bits);
+void spi_tx8fast(uint8_t spi_no, uint8_t dout_data);
+
+// Expansion Macros
+#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR
+
+#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32_t) data, 0, 0)
+#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32_t) data, 0, 0)
+#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32_t) data, 0, 0)
+#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32_t) data, 0, 0)
+
+#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0)
+#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0)
+#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0)
+#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0)
+
+#endif
diff --git a/ports/esp8266/hspi_register.h b/ports/esp8266/hspi_register.h
new file mode 100644
index 000000000..4dd335b40
--- /dev/null
+++ b/ports/esp8266/hspi_register.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2010 - 2011 Espressif System
+ * Modified by David Ogilvy (MetalPhreak)
+ * Based on original file included in SDK 1.0.0
+ *
+ * Missing defines from previous SDK versions have
+ * been added and are noted with comments. The
+ * names of these defines are likely to change.
+ */
+
+#ifndef SPI_REGISTER_H_INCLUDED
+#define SPI_REGISTER_H_INCLUDED
+
+#define REG_SPI_BASE(i) (0x60000200-i*0x100)
+
+#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0)
+#define SPI_FLASH_READ (BIT(31)) //From previous SDK
+#define SPI_FLASH_WREN (BIT(30)) //From previous SDK
+#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK
+#define SPI_FLASH_RDID (BIT(28)) //From previous SDK
+#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK
+#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK
+#define SPI_FLASH_PP (BIT(25)) //From previous SDK
+#define SPI_FLASH_SE (BIT(24)) //From previous SDK
+#define SPI_FLASH_BE (BIT(23)) //From previous SDK
+#define SPI_FLASH_CE (BIT(22)) //From previous SDK
+#define SPI_FLASH_DP (BIT(21)) //From previous SDK
+#define SPI_FLASH_RES (BIT(20)) //From previous SDK
+#define SPI_FLASH_HPM (BIT(19)) //From previous SDK
+#define SPI_USR (BIT(18))
+
+#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4)
+
+#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8)
+#define SPI_WR_BIT_ORDER (BIT(26))
+#define SPI_RD_BIT_ORDER (BIT(25))
+#define SPI_QIO_MODE (BIT(24))
+#define SPI_DIO_MODE (BIT(23))
+#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK
+#define SPI_WP_REG (BIT(21)) //From previous SDK
+#define SPI_QOUT_MODE (BIT(20))
+#define SPI_SHARE_BUS (BIT(19)) //From previous SDK
+#define SPI_HOLD_MODE (BIT(18)) //From previous SDK
+#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK
+#define SPI_SST_AAI (BIT(16)) //From previous SDK
+#define SPI_RESANDRES (BIT(15)) //From previous SDK
+#define SPI_DOUT_MODE (BIT(14))
+#define SPI_FASTRD_MODE (BIT(13))
+
+#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers.
+#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS
+#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS
+#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS
+#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS
+#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK
+#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK
+
+
+#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10)
+#define SPI_STATUS_EXT 0x000000FF //From previous SDK
+#define SPI_STATUS_EXT_S 24 //From previous SDK
+#define SPI_WB_MODE 0x000000FF //From previous SDK
+#define SPI_WB_MODE_S 16 //From previous SDK
+#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK
+#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK
+#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK
+#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK
+#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK
+#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK
+#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK
+
+#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14)
+#define SPI_CS_DELAY_NUM 0x0000000F
+#define SPI_CS_DELAY_NUM_S 28
+#define SPI_CS_DELAY_MODE 0x00000003
+#define SPI_CS_DELAY_MODE_S 26
+#define SPI_MOSI_DELAY_NUM 0x00000007
+#define SPI_MOSI_DELAY_NUM_S 23
+#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk
+ //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk
+ //mode 2 : Do not use this mode.
+#define SPI_MOSI_DELAY_MODE_S 21
+#define SPI_MISO_DELAY_NUM 0x00000007
+#define SPI_MISO_DELAY_NUM_S 18
+#define SPI_MISO_DELAY_MODE 0x00000003
+#define SPI_MISO_DELAY_MODE_S 16
+#define SPI_CK_OUT_HIGH_MODE 0x0000000F
+#define SPI_CK_OUT_HIGH_MODE_S 12
+#define SPI_CK_OUT_LOW_MODE 0x0000000F
+#define SPI_CK_OUT_LOW_MODE_S 8
+#define SPI_HOLD_TIME 0x0000000F
+#define SPI_HOLD_TIME_S 4
+#define SPI_SETUP_TIME 0x0000000F
+#define SPI_SETUP_TIME_S 0
+
+#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18)
+#define SPI_CLK_EQU_SYSCLK (BIT(31))
+#define SPI_CLKDIV_PRE 0x00001FFF
+#define SPI_CLKDIV_PRE_S 18
+#define SPI_CLKCNT_N 0x0000003F
+#define SPI_CLKCNT_N_S 12
+#define SPI_CLKCNT_H 0x0000003F
+#define SPI_CLKCNT_H_S 6
+#define SPI_CLKCNT_L 0x0000003F
+#define SPI_CLKCNT_L_S 0
+
+#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C)
+#define SPI_USR_COMMAND (BIT(31))
+#define SPI_USR_ADDR (BIT(30))
+#define SPI_USR_DUMMY (BIT(29))
+#define SPI_USR_MISO (BIT(28))
+#define SPI_USR_MOSI (BIT(27))
+#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK
+#define SPI_USR_MOSI_HIGHPART (BIT(25))
+#define SPI_USR_MISO_HIGHPART (BIT(24))
+#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK
+#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK
+#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK
+#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK
+#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK
+#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK
+#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK
+#define SPI_SIO (BIT(16))
+#define SPI_FWRITE_QIO (BIT(15))
+#define SPI_FWRITE_DIO (BIT(14))
+#define SPI_FWRITE_QUAD (BIT(13))
+#define SPI_FWRITE_DUAL (BIT(12))
+#define SPI_WR_BYTE_ORDER (BIT(11))
+#define SPI_RD_BYTE_ORDER (BIT(10))
+#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK
+#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK
+#define SPI_CK_OUT_EDGE (BIT(7))
+#define SPI_CK_I_EDGE (BIT(6))
+#define SPI_CS_SETUP (BIT(5))
+#define SPI_CS_HOLD (BIT(4))
+#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK
+#define SPI_FLASH_MODE (BIT(2))
+#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK
+#define SPI_DOUTDIN (BIT(0)) //From previous SDK
+
+//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ?
+
+
+#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20)
+#define SPI_USR_ADDR_BITLEN 0x0000003F
+#define SPI_USR_ADDR_BITLEN_S 26
+#define SPI_USR_MOSI_BITLEN 0x000001FF
+#define SPI_USR_MOSI_BITLEN_S 17
+#define SPI_USR_MISO_BITLEN 0x000001FF
+#define SPI_USR_MISO_BITLEN_S 8
+#define SPI_USR_DUMMY_CYCLELEN 0x000000FF
+#define SPI_USR_DUMMY_CYCLELEN_S 0
+
+#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24)
+#define SPI_USR_COMMAND_BITLEN 0x0000000F
+#define SPI_USR_COMMAND_BITLEN_S 28
+#define SPI_USR_COMMAND_VALUE 0x0000FFFF
+#define SPI_USR_COMMAND_VALUE_S 0
+
+#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28)
+ //previously defined as SPI_FLASH_USER3. No further info available.
+
+#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C)
+#define SPI_IDLE_EDGE (BIT(29))
+#define SPI_CS2_DIS (BIT(2))
+#define SPI_CS1_DIS (BIT(1))
+#define SPI_CS0_DIS (BIT(0))
+
+#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30)
+#define SPI_SYNC_RESET (BIT(31))
+#define SPI_SLAVE_MODE (BIT(30))
+#define SPI_SLV_WR_RD_BUF_EN (BIT(29))
+#define SPI_SLV_WR_RD_STA_EN (BIT(28))
+#define SPI_SLV_CMD_DEFINE (BIT(27))
+#define SPI_TRANS_CNT 0x0000000F
+#define SPI_TRANS_CNT_S 23
+#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK
+#define SPI_SLV_LAST_STATE_S 20 //From previous SDK
+#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK
+#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK
+#define SPI_CS_I_MODE 0x00000003 //From previous SDK
+#define SPI_CS_I_MODE_S 10 //From previous SDK
+#define SPI_TRANS_DONE_EN (BIT(9))
+#define SPI_SLV_WR_STA_DONE_EN (BIT(8))
+#define SPI_SLV_RD_STA_DONE_EN (BIT(7))
+#define SPI_SLV_WR_BUF_DONE_EN (BIT(6))
+#define SPI_SLV_RD_BUF_DONE_EN (BIT(5))
+#define SLV_SPI_INT_EN 0x0000001f
+#define SLV_SPI_INT_EN_S 5
+#define SPI_TRANS_DONE (BIT(4))
+#define SPI_SLV_WR_STA_DONE (BIT(3))
+#define SPI_SLV_RD_STA_DONE (BIT(2))
+#define SPI_SLV_WR_BUF_DONE (BIT(1))
+#define SPI_SLV_RD_BUF_DONE (BIT(0))
+
+#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34)
+#define SPI_SLV_STATUS_BITLEN 0x0000001F
+#define SPI_SLV_STATUS_BITLEN_S 27
+#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK
+#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK
+#define SPI_SLV_BUF_BITLEN 0x000001FF
+#define SPI_SLV_BUF_BITLEN_S 16
+#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F
+#define SPI_SLV_RD_ADDR_BITLEN_S 10
+#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F
+#define SPI_SLV_WR_ADDR_BITLEN_S 4
+#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3))
+#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2))
+#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1))
+#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0))
+
+
+
+#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38)
+#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF
+#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24
+#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF
+#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16
+#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF
+#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8
+#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF
+#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0
+
+#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C)
+#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF
+#define SPI_SLV_WRSTA_CMD_VALUE_S 24
+#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF
+#define SPI_SLV_RDSTA_CMD_VALUE_S 16
+#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF
+#define SPI_SLV_WRBUF_CMD_VALUE_S 8
+#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF
+#define SPI_SLV_RDBUF_CMD_VALUE_S 0
+
+//Previous SDKs referred to these following registers as SPI_C0 etc.
+
+#define SPI_W0(i) (REG_SPI_BASE(i) +0x40)
+#define SPI_W1(i) (REG_SPI_BASE(i) +0x44)
+#define SPI_W2(i) (REG_SPI_BASE(i) +0x48)
+#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C)
+#define SPI_W4(i) (REG_SPI_BASE(i) +0x50)
+#define SPI_W5(i) (REG_SPI_BASE(i) +0x54)
+#define SPI_W6(i) (REG_SPI_BASE(i) +0x58)
+#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C)
+#define SPI_W8(i) (REG_SPI_BASE(i) +0x60)
+#define SPI_W9(i) (REG_SPI_BASE(i) +0x64)
+#define SPI_W10(i) (REG_SPI_BASE(i) +0x68)
+#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C)
+#define SPI_W12(i) (REG_SPI_BASE(i) +0x70)
+#define SPI_W13(i) (REG_SPI_BASE(i) +0x74)
+#define SPI_W14(i) (REG_SPI_BASE(i) +0x78)
+#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C)
+
+ // +0x80 to +0xBC could be SPI_W16 through SPI_W31?
+
+ // +0xC0 to +0xEC not currently defined.
+
+#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers.
+#define SPI_T_PP_ENA (BIT(31)) //From previous SDK
+#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK
+#define SPI_T_PP_SHIFT_S 16 //From previous SDK
+#define SPI_T_PP_TIME 0x00000FFF //From previous SDK
+#define SPI_T_PP_TIME_S 0 //From previous SDK
+
+#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers.
+#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK
+#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK
+#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK
+#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK
+#define SPI_T_ERASE_TIME_S 0 //From previous SDK
+
+#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers.
+#define SPI_ST 0x00000007 //From previous SDK
+#define SPI_ST_S 0 //From previous SDK
+
+#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
+#define SPI_INT_HOLD_ENA 0x00000003
+#define SPI_INT_HOLD_ENA_S 0
+#endif // SPI_REGISTER_H_INCLUDED
diff --git a/ports/esp8266/intr.c b/ports/esp8266/intr.c
new file mode 100644
index 000000000..456d6cb04
--- /dev/null
+++ b/ports/esp8266/intr.c
@@ -0,0 +1,37 @@
+/*
+ * 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 "etshal.h"
+#include "ets_alt_task.h"
+
+#include "modmachine.h"
+
+// this is in a separate file so it can go in iRAM
+void pin_intr_handler_iram(void *arg) {
+ uint32_t status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
+ GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, status);
+ pin_intr_handler(status);
+}
diff --git a/ports/esp8266/lexerstr32.c b/ports/esp8266/lexerstr32.c
new file mode 100644
index 000000000..6fb84bb74
--- /dev/null
+++ b/ports/esp8266/lexerstr32.c
@@ -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(void *sb_in) {
+ mp_lexer_str32_buf_t *sb = (mp_lexer_str32_buf_t*)sb_in;
+ byte c = sb->val & 0xff;
+ if (c == 0) {
+ return MP_READER_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(void *sb_in) {
+ mp_lexer_str32_buf_t *sb = (mp_lexer_str32_buf_t*)sb_in;
+ 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(mp_lexer_str32_buf_t);
+ 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;
+ mp_reader_t reader = {sb, str32_buf_next_byte, str32_buf_free};
+ return mp_lexer_new(src_name, reader);
+}
+
+#endif // MICROPY_ENABLE_COMPILER
diff --git a/ports/esp8266/machine_adc.c b/ports/esp8266/machine_adc.c
new file mode 100644
index 000000000..c8c08695b
--- /dev/null
+++ b/ports/esp8266/machine_adc.c
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "user_interface.h"
+
+const mp_obj_type_t pyb_adc_type;
+
+typedef struct _pyb_adc_obj_t {
+ mp_obj_base_t base;
+ bool isvdd;
+} pyb_adc_obj_t;
+
+STATIC pyb_adc_obj_t pyb_adc_vdd3 = {{&pyb_adc_type}, true};
+STATIC pyb_adc_obj_t pyb_adc_adc = {{&pyb_adc_type}, false};
+
+STATIC mp_obj_t pyb_adc_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw,
+ const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ mp_int_t chn = mp_obj_get_int(args[0]);
+
+ switch (chn) {
+ case 0:
+ return &pyb_adc_adc;
+ case 1:
+ return &pyb_adc_vdd3;
+ default:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "not a valid ADC Channel: %d", chn));
+ }
+}
+
+STATIC mp_obj_t pyb_adc_read(mp_obj_t self_in) {
+ pyb_adc_obj_t *adc = self_in;
+
+ if (adc->isvdd) {
+ return mp_obj_new_int(system_get_vdd33());
+ } else {
+ return mp_obj_new_int(system_adc_read());
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_adc_read_obj, pyb_adc_read);
+
+STATIC const mp_rom_map_elem_t pyb_adc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_adc_read_obj) }
+};
+STATIC MP_DEFINE_CONST_DICT(pyb_adc_locals_dict, pyb_adc_locals_dict_table);
+
+const mp_obj_type_t pyb_adc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ADC,
+ .make_new = pyb_adc_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_adc_locals_dict,
+};
diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c
new file mode 100644
index 000000000..eaabbab7e
--- /dev/null
+++ b/ports/esp8266/machine_hspi.c
@@ -0,0 +1,179 @@
+/*
+ * 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 "ets_alt_task.h"
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mphal.h"
+#include "extmod/machine_spi.h"
+#include "modmachine.h"
+#include "hspi.h"
+
+typedef struct _machine_hspi_obj_t {
+ mp_obj_base_t base;
+ uint32_t baudrate;
+ uint8_t polarity;
+ uint8_t phase;
+} machine_hspi_obj_t;
+
+STATIC void machine_hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
+ (void)self_in;
+
+ if (dest == NULL) {
+ // fast case when we only need to write data
+ size_t chunk_size = 1024;
+ size_t count = len / chunk_size;
+ size_t i = 0;
+ for (size_t j = 0; j < count; ++j) {
+ for (size_t k = 0; k < chunk_size; ++k) {
+ spi_tx8fast(HSPI, src[i]);
+ ++i;
+ }
+ ets_loop_iter();
+ }
+ while (i < len) {
+ spi_tx8fast(HSPI, src[i]);
+ ++i;
+ }
+ } else {
+ // we need to read and write data
+
+ // Process data in chunks, let the pending tasks run in between
+ size_t chunk_size = 1024; // TODO this should depend on baudrate
+ size_t count = len / chunk_size;
+ size_t i = 0;
+ for (size_t j = 0; j < count; ++j) {
+ for (size_t k = 0; k < chunk_size; ++k) {
+ dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
+ ++i;
+ }
+ ets_loop_iter();
+ }
+ while (i < len) {
+ dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
+ ++i;
+ }
+ }
+}
+
+/******************************************************************************/
+// MicroPython bindings for HSPI
+
+STATIC void machine_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "HSPI(id=1, baudrate=%u, polarity=%u, phase=%u)",
+ self->baudrate, self->polarity, self->phase);
+}
+
+STATIC void machine_hspi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ machine_hspi_obj_t *self = (machine_hspi_obj_t*)self_in;
+
+ enum { ARG_baudrate, ARG_polarity, ARG_phase };
+ 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_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 (self->baudrate == 80000000L) {
+ // Special case for full speed.
+ spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV);
+ spi_clock(HSPI, 0, 0);
+ } else if (self->baudrate > 40000000L) {
+ mp_raise_ValueError("impossible baudrate");
+ } else {
+ uint32_t divider = 40000000L / self->baudrate;
+ uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1);
+ uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even
+ if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) {
+ mp_raise_ValueError("impossible baudrate");
+ }
+ self->baudrate = 80000000L / (prediv * cntdiv);
+ spi_init_gpio(HSPI, SPI_CLK_USE_DIV);
+ spi_clock(HSPI, prediv, cntdiv);
+ }
+ // TODO: Make the byte order configurable too (discuss param names)
+ spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
+ spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
+ CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE | SPI_USR_MISO |
+ SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY);
+ // Clear Dual or Quad lines transmission mode
+ CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_QIO_MODE | SPI_DIO_MODE |
+ SPI_DOUT_MODE | SPI_QOUT_MODE);
+ spi_mode(HSPI, self->phase, self->polarity);
+}
+
+mp_obj_t machine_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // args[0] holds the id of the peripheral
+ if (args[0] != MP_OBJ_NEW_SMALL_INT(1)) {
+ // FlashROM is on SPI0, so far we don't support its usage
+ mp_raise_ValueError("");
+ }
+
+ machine_hspi_obj_t *self = m_new_obj(machine_hspi_obj_t);
+ self->base.type = &machine_hspi_type;
+ // set defaults
+ self->baudrate = 80000000L;
+ self->polarity = 0;
+ self->phase = 0;
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ machine_hspi_init((mp_obj_base_t*)self, n_args - 1, args + 1, &kw_args);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC const mp_machine_spi_p_t machine_hspi_p = {
+ .init = machine_hspi_init,
+ .transfer = machine_hspi_transfer,
+};
+
+const mp_obj_type_t machine_hspi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_HSPI,
+ .print = machine_hspi_print,
+ .make_new = mp_machine_spi_make_new, // delegate to master constructor
+ .protocol = &machine_hspi_p,
+ .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict,
+};
diff --git a/ports/esp8266/machine_pin.c b/ports/esp8266/machine_pin.c
new file mode 100644
index 000000000..3ead3f4c2
--- /dev/null
+++ b/ports/esp8266/machine_pin.c
@@ -0,0 +1,519 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014, 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 <string.h>
+
+#include "etshal.h"
+#include "c_types.h"
+#include "user_interface.h"
+#include "gpio.h"
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "py/mphal.h"
+#include "extmod/virtpin.h"
+#include "modmachine.h"
+
+#define GET_TRIGGER(phys_port) \
+ GPIO_PIN_INT_TYPE_GET(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)))
+#define SET_TRIGGER(phys_port, trig) \
+ (GPIO_REG_WRITE(GPIO_PIN_ADDR(phys_port), \
+ (GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)) & ~GPIO_PIN_INT_TYPE_MASK) \
+ | GPIO_PIN_INT_TYPE_SET(trig))) \
+
+#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 _pin_irq_obj_t {
+ mp_obj_base_t base;
+ uint16_t phys_port;
+} pin_irq_obj_t;
+
+const pyb_pin_obj_t pyb_pin_obj[16 + 1] = {
+ {{&pyb_pin_type}, 0, FUNC_GPIO0, PERIPHS_IO_MUX_GPIO0_U},
+ {{&pyb_pin_type}, 1, FUNC_GPIO1, PERIPHS_IO_MUX_U0TXD_U},
+ {{&pyb_pin_type}, 2, FUNC_GPIO2, PERIPHS_IO_MUX_GPIO2_U},
+ {{&pyb_pin_type}, 3, FUNC_GPIO3, PERIPHS_IO_MUX_U0RXD_U},
+ {{&pyb_pin_type}, 4, FUNC_GPIO4, PERIPHS_IO_MUX_GPIO4_U},
+ {{&pyb_pin_type}, 5, FUNC_GPIO5, PERIPHS_IO_MUX_GPIO5_U},
+ {{NULL}, 0, 0, 0},
+ {{NULL}, 0, 0, 0},
+ {{NULL}, 0, 0, 0},
+ {{&pyb_pin_type}, 9, FUNC_GPIO9, PERIPHS_IO_MUX_SD_DATA2_U},
+ {{&pyb_pin_type}, 10, FUNC_GPIO10, PERIPHS_IO_MUX_SD_DATA3_U},
+ {{NULL}, 0, 0, 0},
+ {{&pyb_pin_type}, 12, FUNC_GPIO12, PERIPHS_IO_MUX_MTDI_U},
+ {{&pyb_pin_type}, 13, FUNC_GPIO13, PERIPHS_IO_MUX_MTCK_U},
+ {{&pyb_pin_type}, 14, FUNC_GPIO14, PERIPHS_IO_MUX_MTMS_U},
+ {{&pyb_pin_type}, 15, FUNC_GPIO15, PERIPHS_IO_MUX_MTDO_U},
+ // GPIO16 is special, belongs to different register set, and
+ // otherwise handled specially.
+ {{&pyb_pin_type}, 16, -1, -1},
+};
+
+STATIC uint8_t pin_mode[16 + 1];
+
+// forward declaration
+STATIC const pin_irq_obj_t pin_irq_obj[16];
+
+// whether the irq is hard or soft
+STATIC bool pin_irq_is_hard[16];
+
+void pin_init0(void) {
+ ETS_GPIO_INTR_DISABLE();
+ ETS_GPIO_INTR_ATTACH(pin_intr_handler_iram, NULL);
+ // disable all interrupts
+ memset(&MP_STATE_PORT(pin_irq_handler)[0], 0, 16 * sizeof(mp_obj_t));
+ memset(pin_irq_is_hard, 0, sizeof(pin_irq_is_hard));
+ for (int p = 0; p < 16; ++p) {
+ GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << p);
+ SET_TRIGGER(p, 0);
+ }
+ ETS_GPIO_INTR_ENABLE();
+}
+
+void pin_intr_handler(uint32_t status) {
+ mp_sched_lock();
+ gc_lock();
+ status &= 0xffff;
+ for (int p = 0; status; ++p, status >>= 1) {
+ if (status & 1) {
+ mp_obj_t handler = MP_STATE_PORT(pin_irq_handler)[p];
+ if (handler != MP_OBJ_NULL) {
+ if (pin_irq_is_hard[p]) {
+ mp_call_function_1_protected(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
+ } else {
+ mp_sched_schedule(handler, MP_OBJ_FROM_PTR(&pyb_pin_obj[p]));
+ }
+ }
+ }
+ }
+ gc_unlock();
+ mp_sched_unlock();
+}
+
+pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) {
+ if (mp_obj_get_type(pin_in) != &pyb_pin_type) {
+ mp_raise_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;
+}
+
+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);
+ }
+}
+
+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) {
+ // configure GPIO16 as input with output register holding 0
+ 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
+ WRITE_PERI_REG(RTC_GPIO_OUT, (READ_PERI_REG(RTC_GPIO_OUT) & ~1)); // out=0
+ return;
+ }
+
+ ETS_GPIO_INTR_DISABLE();
+ PIN_FUNC_SELECT(pin->periph, pin->func);
+ GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)),
+ GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->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 << pin->phys_port));
+ ETS_GPIO_INTR_ENABLE();
+}
+
+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;
+
+ // pin name
+ mp_printf(print, "Pin(%u)", self->phys_port);
+}
+
+// pin.init(mode, pull=None, *, value)
+STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_mode, ARG_pull, ARG_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}},
+ { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // get io mode
+ uint mode = args[ARG_mode].u_int;
+
+ // get pull mode
+ uint pull = GPIO_PULL_NONE;
+ if (args[ARG_pull].u_obj != mp_const_none) {
+ pull = mp_obj_get_int(args[ARG_pull].u_obj);
+ }
+
+ // get initial value
+ int value;
+ if (args[ARG_value].u_obj == MP_OBJ_NULL) {
+ value = -1;
+ } else {
+ value = mp_obj_is_true(args[ARG_value].u_obj);
+ }
+
+ // save the mode
+ pin_mode[self->phys_port] = mode;
+
+ // configure the GPIO as requested
+ if (self->phys_port == 16) {
+ // only pull-down seems to be supported by the hardware, and
+ // we only expose pull-up behaviour in software
+ if (pull != GPIO_PULL_NONE) {
+ mp_raise_ValueError("Pin(16) doesn't support pull");
+ }
+ } 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);
+ }
+ }
+
+ pin_set(self->phys_port, value);
+
+ return mp_const_none;
+}
+
+// constructor(id, ...)
+mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
+
+ // get the wanted pin object
+ int wanted_pin = mp_obj_get_int(args[0]);
+ pyb_pin_obj_t *pin = NULL;
+ if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
+ pin = (pyb_pin_obj_t*)&pyb_pin_obj[wanted_pin];
+ }
+ if (pin == NULL || pin->base.type == NULL) {
+ mp_raise_ValueError("invalid pin");
+ }
+
+ if (n_args > 1 || n_kw > 0) {
+ // pin mode given, so configure this GPIO
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
+ }
+
+ return (mp_obj_t)pin;
+}
+
+// fast method for getting/setting pin value
+STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ pyb_pin_obj_t *self = self_in;
+ if (n_args == 0) {
+ // get pin
+ return MP_OBJ_NEW_SMALL_INT(pin_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(size_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);
+}
+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(size_t n_args, const mp_obj_t *args) {
+ 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);
+
+STATIC mp_obj_t pyb_pin_off(mp_obj_t self_in) {
+ pyb_pin_obj_t *self = self_in;
+ pin_set(self->phys_port, 0);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_off_obj, pyb_pin_off);
+
+STATIC mp_obj_t pyb_pin_on(mp_obj_t self_in) {
+ pyb_pin_obj_t *self = self_in;
+ pin_set(self->phys_port, 1);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_pin_on_obj, pyb_pin_on);
+
+// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False)
+STATIC mp_obj_t pyb_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_handler, ARG_trigger, ARG_hard };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
+ { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
+ };
+ pyb_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (self->phys_port >= 16) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "pin does not have IRQ capabilities"));
+ }
+
+ if (n_args > 1 || kw_args->used != 0) {
+ // configure irq
+ mp_obj_t handler = args[ARG_handler].u_obj;
+ uint32_t trigger = args[ARG_trigger].u_int;
+ if (handler == mp_const_none) {
+ handler = MP_OBJ_NULL;
+ trigger = 0;
+ }
+ ETS_GPIO_INTR_DISABLE();
+ MP_STATE_PORT(pin_irq_handler)[self->phys_port] = handler;
+ pin_irq_is_hard[self->phys_port] = args[ARG_hard].u_bool;
+ SET_TRIGGER(self->phys_port, trigger);
+ GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->phys_port);
+ ETS_GPIO_INTR_ENABLE();
+ }
+
+ // return the irq object
+ return MP_OBJ_FROM_PTR(&pin_irq_obj[self->phys_port]);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_pin_irq_obj, 1, pyb_pin_irq);
+
+STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode);
+STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ (void)errcode;
+ pyb_pin_obj_t *self = self_in;
+
+ switch (request) {
+ case MP_PIN_READ: {
+ return pin_get(self->phys_port);
+ }
+ case MP_PIN_WRITE: {
+ pin_set(self->phys_port, arg);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+STATIC const mp_rom_map_elem_t pyb_pin_locals_dict_table[] = {
+ // instance methods
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_pin_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&pyb_pin_value_obj) },
+ { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&pyb_pin_off_obj) },
+ { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&pyb_pin_on_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_pin_irq_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) },
+ { MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_OUTPUT) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_OPEN_DRAIN) },
+ { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
+ //{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
+
+ // IRQ triggers, can be or'd together
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pyb_pin_locals_dict, pyb_pin_locals_dict_table);
+
+STATIC const mp_pin_p_t pin_pin_p = {
+ .ioctl = pin_ioctl,
+};
+
+const mp_obj_type_t pyb_pin_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Pin,
+ .print = pyb_pin_print,
+ .make_new = mp_pin_make_new,
+ .call = pyb_pin_call,
+ .protocol = &pin_pin_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_pin_locals_dict,
+};
+
+/******************************************************************************/
+// Pin IRQ object
+
+STATIC const mp_obj_type_t pin_irq_type;
+
+STATIC const pin_irq_obj_t pin_irq_obj[16] = {
+ {{&pin_irq_type}, 0},
+ {{&pin_irq_type}, 1},
+ {{&pin_irq_type}, 2},
+ {{&pin_irq_type}, 3},
+ {{&pin_irq_type}, 4},
+ {{&pin_irq_type}, 5},
+ {{&pin_irq_type}, 6},
+ {{&pin_irq_type}, 7},
+ {{&pin_irq_type}, 8},
+ {{&pin_irq_type}, 9},
+ {{&pin_irq_type}, 10},
+ {{&pin_irq_type}, 11},
+ {{&pin_irq_type}, 12},
+ {{&pin_irq_type}, 13},
+ {{&pin_irq_type}, 14},
+ {{&pin_irq_type}, 15},
+};
+
+STATIC mp_obj_t pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ pin_irq_obj_t *self = self_in;
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ pin_intr_handler(1 << self->phys_port);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
+ pin_irq_obj_t *self = args[0];
+ uint32_t orig_trig = GET_TRIGGER(self->phys_port);
+ if (n_args == 2) {
+ // set trigger
+ SET_TRIGGER(self->phys_port, mp_obj_get_int(args[1]));
+ }
+ // return original trigger value
+ return MP_OBJ_NEW_SMALL_INT(orig_trig);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_irq_trigger_obj, 1, 2, pin_irq_trigger);
+
+STATIC const mp_rom_map_elem_t pin_irq_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&pin_irq_trigger_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(pin_irq_locals_dict, pin_irq_locals_dict_table);
+
+STATIC const mp_obj_type_t pin_irq_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_IRQ,
+ .call = pin_irq_call,
+ .locals_dict = (mp_obj_dict_t*)&pin_irq_locals_dict,
+};
diff --git a/ports/esp8266/machine_pwm.c b/ports/esp8266/machine_pwm.c
new file mode 100644
index 000000000..8d73e6bb1
--- /dev/null
+++ b/ports/esp8266/machine_pwm.c
@@ -0,0 +1,172 @@
+/*
+ * 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 "esppwm.h"
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "modmachine.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->phys_port);
+ 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,
+};
diff --git a/ports/esp8266/machine_rtc.c b/ports/esp8266/machine_rtc.c
new file mode 100644
index 000000000..f6a13c095
--- /dev/null
+++ b/ports/esp8266/machine_rtc.c
@@ -0,0 +1,272 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "lib/timeutils/timeutils.h"
+#include "user_interface.h"
+#include "modmachine.h"
+
+typedef struct _pyb_rtc_obj_t {
+ mp_obj_base_t base;
+} pyb_rtc_obj_t;
+
+#define MEM_MAGIC 0x75507921
+#define MEM_DELTA_ADDR 64
+#define MEM_CAL_ADDR (MEM_DELTA_ADDR + 2)
+#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1)
+#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1)
+#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1)
+#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4)
+
+// singleton RTC object
+STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
+
+// ALARM0 state
+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;
+
+ 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));
+ 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;
+ pyb_rtc_alarm0_expiry = 0;
+}
+
+STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check arguments
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+
+ // return constant object
+ return (mp_obj_t)&pyb_rtc_obj;
+}
+
+void pyb_rtc_set_us_since_2000(uint64_t nowus) {
+ uint32_t cal = system_rtc_clock_cali_proc();
+ // 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 practically usable, we need to store it
+ system_rtc_mem_write(MEM_CAL_ADDR, &cal, sizeof(cal));
+ system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
+};
+
+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));
+
+ // 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;
+};
+
+void rtc_prepare_deepsleep(uint64_t sleep_us) {
+ // RTC time will reset at wake up. Let's be preared for this.
+ int64_t delta = pyb_rtc_get_us_since_2000() + sleep_us;
+ system_rtc_mem_write(MEM_DELTA_ADDR, &delta, sizeof(delta));
+}
+
+STATIC mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 1) {
+ // Get time
+ uint64_t msecs = pyb_rtc_get_us_since_2000() / 1000;
+
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_2000_to_struct_time(msecs / 1000, &tm);
+
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(tm.tm_year),
+ mp_obj_new_int(tm.tm_mon),
+ mp_obj_new_int(tm.tm_mday),
+ mp_obj_new_int(tm.tm_wday),
+ mp_obj_new_int(tm.tm_hour),
+ mp_obj_new_int(tm.tm_min),
+ mp_obj_new_int(tm.tm_sec),
+ mp_obj_new_int(msecs % 1000)
+ };
+
+ return mp_obj_new_tuple(8, tuple);
+ } else {
+ // Set time
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 8, &items);
+
+ pyb_rtc_set_us_since_2000(
+ ((uint64_t)timeutils_seconds_since_2000(
+ mp_obj_get_int(items[0]),
+ mp_obj_get_int(items[1]),
+ mp_obj_get_int(items[2]),
+ mp_obj_get_int(items[4]),
+ mp_obj_get_int(items[5]),
+ mp_obj_get_int(items[6])) * 1000 + mp_obj_get_int(items[7])) * 1000);
+
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
+
+STATIC mp_obj_t pyb_rtc_memory(size_t n_args, const mp_obj_t *args) {
+ uint8_t rtcram[MEM_USER_MAXLEN];
+ uint32_t len;
+
+ if (n_args == 1) {
+ // read RTC memory
+
+ system_rtc_mem_read(MEM_USER_LEN_ADDR, &len, sizeof(len));
+ system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3);
+
+ return mp_obj_new_bytes(rtcram, len);
+ } else {
+ // write RTC memory
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
+
+ if (bufinfo.len > MEM_USER_MAXLEN) {
+ mp_raise_ValueError("buffer too long");
+ }
+
+ len = bufinfo.len;
+ system_rtc_mem_write(MEM_USER_LEN_ADDR, &len, sizeof(len));
+
+ int i = 0;
+ for (; i < bufinfo.len; i++) {
+ rtcram[i] = ((uint8_t *)bufinfo.buf)[i];
+ }
+
+ system_rtc_mem_write(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3);
+
+ return mp_const_none;
+ }
+
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory);
+
+STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) {
+ (void)self_in; // unused
+
+ // check we want alarm0
+ if (mp_obj_get_int(alarm_id) != 0) {
+ mp_raise_ValueError("invalid alarm");
+ }
+
+ // set expiry time (in microseconds)
+ pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000;
+
+ return mp_const_none;
+
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm);
+
+STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) {
+ // check we want alarm0
+ if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
+ mp_raise_ValueError("invalid alarm");
+ }
+
+ uint64_t now = pyb_rtc_get_us_since_2000();
+ if (pyb_rtc_alarm0_expiry <= now) {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ } else {
+ return mp_obj_new_int((pyb_rtc_alarm0_expiry - now) / 1000);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
+
+STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_trigger, ARG_wake };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // check we want alarm0
+ if (args[ARG_trigger].u_int != 0) {
+ mp_raise_ValueError("invalid alarm");
+ }
+
+ // set the wake value
+ pyb_rtc_alarm0_wake = args[ARG_wake].u_int;
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
+
+STATIC const mp_rom_map_elem_t pyb_rtc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_datetime), MP_ROM_PTR(&pyb_rtc_datetime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_memory), MP_ROM_PTR(&pyb_rtc_memory_obj) },
+ { MP_ROM_QSTR(MP_QSTR_alarm), MP_ROM_PTR(&pyb_rtc_alarm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_alarm_left), MP_ROM_PTR(&pyb_rtc_alarm_left_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&pyb_rtc_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ALARM0), MP_ROM_INT(0) },
+};
+STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
+
+const mp_obj_type_t pyb_rtc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_RTC,
+ .make_new = pyb_rtc_make_new,
+ .locals_dict = (mp_obj_dict_t*)&pyb_rtc_locals_dict,
+};
diff --git a/ports/esp8266/machine_uart.c b/ports/esp8266/machine_uart.c
new file mode 100644
index 000000000..e8be5e538
--- /dev/null
+++ b/ports/esp8266/machine_uart.c
@@ -0,0 +1,299 @@
+/*
+ * 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 "uart.h"
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "modmachine.h"
+
+// UartDev is defined and initialized in rom code.
+extern UartDevice UartDev;
+
+typedef struct _pyb_uart_obj_t {
+ mp_obj_base_t base;
+ uint8_t uart_id;
+ uint8_t bits;
+ uint8_t parity;
+ uint8_t stop;
+ uint32_t baudrate;
+ uint16_t timeout; // timeout waiting for first char (in ms)
+ uint16_t timeout_char; // timeout waiting between chars (in ms)
+} pyb_uart_obj_t;
+
+STATIC const char *_parity_name[] = {"None", "1", "0"};
+
+/******************************************************************************/
+// 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, baudrate=%u, bits=%u, parity=%s, stop=%u, timeout=%u, timeout_char=%u)",
+ self->uart_id, self->baudrate, self->bits, _parity_name[self->parity],
+ self->stop, self->timeout, self->timeout_char);
+}
+
+STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_timeout_char };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} },
+ //{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ //{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // set baudrate
+ if (args[ARG_baudrate].u_int > 0) {
+ self->baudrate = args[ARG_baudrate].u_int;
+ UartDev.baut_rate = self->baudrate; // Sic!
+ }
+
+ // set data bits
+ switch (args[ARG_bits].u_int) {
+ case 0:
+ break;
+ case 5:
+ UartDev.data_bits = UART_FIVE_BITS;
+ self->bits = 5;
+ break;
+ case 6:
+ UartDev.data_bits = UART_SIX_BITS;
+ self->bits = 6;
+ break;
+ case 7:
+ UartDev.data_bits = UART_SEVEN_BITS;
+ self->bits = 7;
+ break;
+ case 8:
+ UartDev.data_bits = UART_EIGHT_BITS;
+ self->bits = 8;
+ break;
+ default:
+ mp_raise_ValueError("invalid data bits");
+ break;
+ }
+
+ // set parity
+ if (args[ARG_parity].u_obj != MP_OBJ_NULL) {
+ if (args[ARG_parity].u_obj == mp_const_none) {
+ UartDev.parity = UART_NONE_BITS;
+ UartDev.exist_parity = UART_STICK_PARITY_DIS;
+ self->parity = 0;
+ } else {
+ mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj);
+ UartDev.exist_parity = UART_STICK_PARITY_EN;
+ if (parity & 1) {
+ UartDev.parity = UART_ODD_BITS;
+ self->parity = 1;
+ } else {
+ UartDev.parity = UART_EVEN_BITS;
+ self->parity = 2;
+ }
+ }
+ }
+
+ // set stop bits
+ switch (args[ARG_stop].u_int) {
+ case 0:
+ break;
+ case 1:
+ UartDev.stop_bits = UART_ONE_STOP_BIT;
+ self->stop = 1;
+ break;
+ case 2:
+ UartDev.stop_bits = UART_TWO_STOP_BIT;
+ self->stop = 2;
+ break;
+ default:
+ mp_raise_ValueError("invalid stop bits");
+ break;
+ }
+
+ // set timeout
+ self->timeout = args[ARG_timeout].u_int;
+
+ // set timeout_char
+ // make sure it is at least as long as a whole character (13 bits to be safe)
+ self->timeout_char = args[ARG_timeout_char].u_int;
+ uint32_t min_timeout_char = 13000 / self->baudrate + 1;
+ if (self->timeout_char < min_timeout_char) {
+ self->timeout_char = min_timeout_char;
+ }
+
+ // setup
+ uart_setup(self->uart_id);
+}
+
+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;
+ self->baudrate = 115200;
+ self->bits = 8;
+ self->parity = 0;
+ self->stop = 1;
+ self->timeout = 0;
+ self->timeout_char = 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 mp_obj_t pyb_uart_any(mp_obj_t self_in) {
+ pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(uart_rx_any(self->uart_id));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_any_obj, pyb_uart_any);
+
+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_any), MP_ROM_PTR(&pyb_uart_any_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(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) {
+ pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->uart_id == 1) {
+ mp_raise_msg(&mp_type_OSError, "UART(1) can't read");
+ }
+
+ // make sure we want at least 1 char
+ if (size == 0) {
+ return 0;
+ }
+
+ // wait for first char to become available
+ if (!uart_rx_wait(self->timeout * 1000)) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+
+ // read the data
+ uint8_t *buf = buf_in;
+ for (;;) {
+ *buf++ = uart_rx_char();
+ if (--size == 0 || !uart_rx_wait(self->timeout_char * 1000)) {
+ // return number of bytes read
+ return buf - (uint8_t*)buf_in;
+ }
+ }
+}
+
+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) {
+ pyb_uart_obj_t *self = self_in;
+ mp_uint_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self->uart_id)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if ((flags & MP_STREAM_POLL_WR) && uart_tx_any_room(self->uart_id)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC const mp_stream_p_t uart_stream_p = {
+ .read = 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_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &uart_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&pyb_uart_locals_dict,
+};
diff --git a/ports/esp8266/machine_wdt.c b/ports/esp8266/machine_wdt.c
new file mode 100644
index 000000000..5e23ff782
--- /dev/null
+++ b/ports/esp8266/machine_wdt.c
@@ -0,0 +1,85 @@
+/*
+ * 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 <string.h>
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "user_interface.h"
+#include "etshal.h"
+
+const mp_obj_type_t esp_wdt_type;
+
+typedef struct _machine_wdt_obj_t {
+ mp_obj_base_t base;
+} machine_wdt_obj_t;
+
+STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}};
+
+STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+ mp_int_t id = 0;
+ if (n_args > 0) {
+ id = mp_obj_get_int(args[0]);
+ }
+
+ switch (id) {
+ case 0:
+ return &wdt_default;
+ default:
+ mp_raise_ValueError("");
+ }
+}
+
+STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
+ (void)self_in;
+ system_soft_wdt_feed();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
+
+STATIC mp_obj_t machine_wdt_deinit(mp_obj_t self_in) {
+ (void)self_in;
+ ets_wdt_disable();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_deinit_obj, machine_wdt_deinit);
+
+STATIC const mp_rom_map_elem_t machine_wdt_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_feed), MP_ROM_PTR(&machine_wdt_feed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_wdt_deinit_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
+
+const mp_obj_type_t esp_wdt_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_WDT,
+ .make_new = machine_wdt_make_new,
+ .locals_dict = (mp_obj_dict_t*)&machine_wdt_locals_dict,
+};
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
new file mode 100644
index 000000000..957198aa0
--- /dev/null
+++ b/ports/esp8266/main.c
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/compile.h"
+#include "py/runtime0.h"
+#include "py/runtime.h"
+#include "py/stackctrl.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "py/gc.h"
+#include "lib/mp-readline/readline.h"
+#include "lib/utils/pyexec.h"
+#include "gccollect.h"
+#include "user_interface.h"
+
+STATIC char heap[36 * 1024];
+
+STATIC void mp_reset(void) {
+ 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_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
+ mp_obj_list_init(mp_sys_argv, 0);
+ MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
+ MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL;
+ #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
+ extern void esp_native_code_init(void);
+ esp_native_code_init();
+ #endif
+ pin_init0();
+ readline_init0();
+ dupterm_task_init();
+#if MICROPY_MODULE_FROZEN
+ pyexec_frozen_module("_boot.py");
+ pyexec_file("boot.py");
+ if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
+ pyexec_file("main.py");
+ }
+#endif
+}
+
+void soft_reset(void) {
+ 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();
+ #endif
+
+ #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);
+}
+
+#if !MICROPY_VFS
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
+ mp_raise_OSError(MP_ENOENT);
+}
+
+mp_import_stat_t mp_import_stat(const char *path) {
+ (void)path;
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+
+mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
+
+#endif
+
+void MP_FASTCODE(nlr_jump_fail)(void *val) {
+ printf("NLR jump failed\n");
+ for (;;) {
+ }
+}
+
+//void __assert(const char *file, int line, const char *func, const char *expr) {
+void __assert(const char *file, int line, const char *expr) {
+ printf("Assertion '%s' failed, at file %s:%d\n", expr, file, line);
+ for (;;) {
+ }
+}
diff --git a/ports/esp8266/makeimg.py b/ports/esp8266/makeimg.py
new file mode 100644
index 000000000..091854fa4
--- /dev/null
+++ b/ports/esp8266/makeimg.py
@@ -0,0 +1,40 @@
+import sys
+import struct
+import hashlib
+
+SEGS_MAX_SIZE = 0x9000
+
+assert len(sys.argv) == 4
+
+md5 = hashlib.md5()
+
+with open(sys.argv[3], 'wb') as fout:
+
+ with open(sys.argv[1], 'rb') as f:
+ data_flash = f.read()
+ fout.write(data_flash)
+ # First 4 bytes include flash size, etc. which may be changed
+ # by esptool.py, etc.
+ md5.update(data_flash[4:])
+ print('flash ', len(data_flash))
+
+ with open(sys.argv[2], 'rb') as f:
+ data_rom = f.read()
+
+ pad = b'\xff' * (SEGS_MAX_SIZE - len(data_flash))
+ assert len(pad) >= 4
+ fout.write(pad[:-4])
+ md5.update(pad[:-4])
+ len_data = struct.pack("I", SEGS_MAX_SIZE + len(data_rom))
+ fout.write(len_data)
+ md5.update(len_data)
+ print('padding ', len(pad))
+
+ fout.write(data_rom)
+ md5.update(data_rom)
+ print('irom0text', len(data_rom))
+
+ fout.write(md5.digest())
+
+ print('total ', SEGS_MAX_SIZE + len(data_rom))
+ print('md5 ', md5.hexdigest())
diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c
new file mode 100644
index 000000000..8f9db4fba
--- /dev/null
+++ b/ports/esp8266/modesp.c
@@ -0,0 +1,392 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 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 "py/gc.h"
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "drivers/dht/dht.h"
+#include "uart.h"
+#include "user_interface.h"
+#include "mem.h"
+#include "espneopixel.h"
+#include "espapa102.h"
+#include "modmachine.h"
+
+#define MODESP_INCLUDE_CONSTANTS (1)
+
+void error_check(bool status, const char *msg) {
+ if (!status) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg));
+ }
+}
+
+STATIC mp_obj_t esp_osdebug(mp_obj_t val) {
+ if (val == mp_const_none) {
+ uart_os_config(-1);
+ } else {
+ uart_os_config(mp_obj_get_int(val));
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_osdebug_obj, esp_osdebug);
+
+STATIC mp_obj_t esp_sleep_type(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ return mp_obj_new_int(wifi_get_sleep_type());
+ } else {
+ wifi_set_sleep_type(mp_obj_get_int(args[0]));
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_sleep_type_obj, 0, 1, esp_sleep_type);
+
+STATIC mp_obj_t esp_deepsleep(size_t n_args, const mp_obj_t *args) {
+ uint32_t sleep_us = n_args > 0 ? mp_obj_get_int(args[0]) : 0;
+ // prepare for RTC reset at wake up
+ rtc_prepare_deepsleep(sleep_us);
+ system_deep_sleep_set_option(n_args > 1 ? mp_obj_get_int(args[1]) : 0);
+ system_deep_sleep(sleep_us);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_deepsleep_obj, 0, 2, esp_deepsleep);
+
+STATIC mp_obj_t esp_flash_id() {
+ return mp_obj_new_int(spi_flash_get_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_or_buf_in) {
+ mp_int_t offset = mp_obj_get_int(offset_in);
+
+ 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) {
+ if (alloc_buf) {
+ return mp_obj_new_bytes(buf, len);
+ }
+ return mp_const_none;
+ }
+ if (alloc_buf) {
+ m_del(byte, buf, len);
+ }
+ mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_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) {
+ mp_raise_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;
+ }
+ mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_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;
+ }
+ mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
+
+STATIC mp_obj_t esp_flash_size(void) {
+ extern char flashchip;
+ // For SDK 1.5.2, either address has shifted and not mirrored in
+ // eagle.rom.addr.v6.ld, or extra initial member was added.
+ SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4);
+ #if 0
+ printf("deviceId: %x\n", flash->deviceId);
+ printf("chip_size: %u\n", flash->chip_size);
+ printf("block_size: %u\n", flash->block_size);
+ printf("sector_size: %u\n", flash->sector_size);
+ printf("page_size: %u\n", flash->page_size);
+ printf("status_mask: %u\n", flash->status_mask);
+ #endif
+ return mp_obj_new_int_from_uint(flash->chip_size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
+
+// If there's just 1 loadable segment at the start of flash,
+// we assume there's a yaota8266 bootloader.
+#define IS_OTA_FIRMWARE() ((*(uint32_t*)0x40200000 & 0xff00) == 0x100)
+
+extern byte _firmware_size[];
+
+STATIC mp_obj_t esp_flash_user_start(void) {
+ return MP_OBJ_NEW_SMALL_INT((uint32_t)_firmware_size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
+
+STATIC mp_obj_t esp_check_fw(void) {
+ MD5_CTX ctx;
+ char *fw_start = (char*)0x40200000;
+ if (IS_OTA_FIRMWARE()) {
+ // Skip yaota8266 bootloader
+ fw_start += 0x3c000;
+ }
+
+ uint32_t size = *(uint32_t*)(fw_start + 0x8ffc);
+ printf("size: %d\n", size);
+ if (size > 1024 * 1024) {
+ printf("Invalid size\n");
+ return mp_const_false;
+ }
+ MD5Init(&ctx);
+ MD5Update(&ctx, fw_start + 4, size - 4);
+ unsigned char digest[16];
+ MD5Final(digest, &ctx);
+ printf("md5: ");
+ for (int i = 0; i < 16; i++) {
+ printf("%02x", digest[i]);
+ }
+ printf("\n");
+ return mp_obj_new_bool(memcmp(digest, fw_start + size, sizeof(digest)) == 0);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw);
+
+
+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_);
+
+#if MICROPY_ESP8266_APA102
+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_);
+#endif
+
+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 mp_obj_t esp_malloc(mp_obj_t size_in) {
+ return MP_OBJ_NEW_SMALL_INT((mp_uint_t)os_malloc(mp_obj_get_int(size_in)));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_malloc_obj, esp_malloc);
+
+STATIC mp_obj_t esp_free(mp_obj_t addr_in) {
+ os_free((void*)mp_obj_get_int(addr_in));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_free_obj, esp_free);
+
+STATIC mp_obj_t esp_esf_free_bufs(mp_obj_t idx_in) {
+ return MP_OBJ_NEW_SMALL_INT(ets_esf_free_bufs(mp_obj_get_int(idx_in)));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_esf_free_bufs_obj, esp_esf_free_bufs);
+
+#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
+
+// We provide here a way of committing executable data to a region from
+// which it can be executed by the CPU. There are 2 such writable regions:
+// - iram1, which may have some space left at the end of it
+// - memory-mapped flash rom
+//
+// By default the iram1 region (the space at the end of it) is used. The
+// user can select iram1 or a section of flash by calling the
+// esp.set_native_code_location() function; see below. If flash is selected
+// then it is erased as needed.
+
+#include "gccollect.h"
+
+#define IRAM1_END (0x40108000)
+#define FLASH_START (0x40200000)
+#define FLASH_END (0x40300000)
+#define FLASH_SEC_SIZE (4096)
+
+#define ESP_NATIVE_CODE_IRAM1 (0)
+#define ESP_NATIVE_CODE_FLASH (1)
+
+extern uint32_t _lit4_end;
+STATIC uint32_t esp_native_code_location;
+STATIC uint32_t esp_native_code_start;
+STATIC uint32_t esp_native_code_end;
+STATIC uint32_t esp_native_code_cur;
+STATIC uint32_t esp_native_code_erased;
+
+void esp_native_code_init(void) {
+ esp_native_code_location = ESP_NATIVE_CODE_IRAM1;
+ esp_native_code_start = (uint32_t)&_lit4_end;
+ esp_native_code_end = IRAM1_END;
+ esp_native_code_cur = esp_native_code_start;
+ esp_native_code_erased = 0;
+}
+
+void esp_native_code_gc_collect(void) {
+ void *src;
+ if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) {
+ src = (void*)esp_native_code_start;
+ } else {
+ src = (void*)(FLASH_START + esp_native_code_start);
+ }
+ gc_collect_root(src, (esp_native_code_end - esp_native_code_start) / sizeof(uint32_t));
+}
+
+void *esp_native_code_commit(void *buf, size_t len) {
+ //printf("COMMIT(buf=%p, len=%u, start=%08x, cur=%08x, end=%08x, erased=%08x)\n", buf, len, esp_native_code_start, esp_native_code_cur, esp_native_code_end, esp_native_code_erased);
+
+ len = (len + 3) & ~3;
+ if (esp_native_code_cur + len > esp_native_code_end) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError,
+ "memory allocation failed, allocating %u bytes for native code", (uint)len));
+ }
+
+ void *dest;
+ if (esp_native_code_location == ESP_NATIVE_CODE_IRAM1) {
+ dest = (void*)esp_native_code_cur;
+ memcpy(dest, buf, len);
+ } else {
+ SpiFlashOpResult res;
+ while (esp_native_code_erased < esp_native_code_cur + len) {
+ res = spi_flash_erase_sector(esp_native_code_erased / FLASH_SEC_SIZE);
+ if (res != SPI_FLASH_RESULT_OK) {
+ break;
+ }
+ esp_native_code_erased += FLASH_SEC_SIZE;
+ }
+ if (res == SPI_FLASH_RESULT_OK) {
+ res = spi_flash_write(esp_native_code_cur, buf, len);
+ }
+ if (res != SPI_FLASH_RESULT_OK) {
+ mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
+ }
+ dest = (void*)(FLASH_START + esp_native_code_cur);
+ }
+
+ esp_native_code_cur += len;
+
+ return dest;
+}
+
+STATIC mp_obj_t esp_set_native_code_location(mp_obj_t start_in, mp_obj_t len_in) {
+ if (start_in == mp_const_none && len_in == mp_const_none) {
+ // use end of iram1 region
+ esp_native_code_init();
+ } else {
+ // use flash; input params are byte offsets from start of flash
+ esp_native_code_location = ESP_NATIVE_CODE_FLASH;
+ esp_native_code_start = mp_obj_get_int(start_in);
+ esp_native_code_end = esp_native_code_start + mp_obj_get_int(len_in);
+ esp_native_code_cur = esp_native_code_start;
+ esp_native_code_erased = esp_native_code_start;
+ // memory-mapped flash is limited in extents to 1MByte
+ if (esp_native_code_end > FLASH_END - FLASH_START) {
+ mp_raise_ValueError("flash location must be below 1MByte");
+ }
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_set_native_code_location_obj, esp_set_native_code_location);
+
+#endif
+
+STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_esp) },
+
+ { MP_ROM_QSTR(MP_QSTR_osdebug), MP_ROM_PTR(&esp_osdebug_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_type), MP_ROM_PTR(&esp_sleep_type_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&esp_deepsleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_id), MP_ROM_PTR(&esp_flash_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_read), MP_ROM_PTR(&esp_flash_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_write), MP_ROM_PTR(&esp_flash_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_erase), MP_ROM_PTR(&esp_flash_erase_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_size), MP_ROM_PTR(&esp_flash_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flash_user_start), MP_ROM_PTR(&esp_flash_user_start_obj) },
+ #if MICROPY_ESP8266_NEOPIXEL
+ { MP_ROM_QSTR(MP_QSTR_neopixel_write), MP_ROM_PTR(&esp_neopixel_write_obj) },
+ #endif
+ #if MICROPY_ESP8266_APA102
+ { MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_freemem), MP_ROM_PTR(&esp_freemem_obj) },
+ { MP_ROM_QSTR(MP_QSTR_meminfo), MP_ROM_PTR(&esp_meminfo_obj) },
+ { MP_ROM_QSTR(MP_QSTR_check_fw), MP_ROM_PTR(&esp_check_fw_obj) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_info_obj) }, // TODO delete/rename/move elsewhere
+ { MP_ROM_QSTR(MP_QSTR_malloc), MP_ROM_PTR(&esp_malloc_obj) },
+ { MP_ROM_QSTR(MP_QSTR_free), MP_ROM_PTR(&esp_free_obj) },
+ { MP_ROM_QSTR(MP_QSTR_esf_free_bufs), MP_ROM_PTR(&esp_esf_free_bufs_obj) },
+ #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
+ { MP_ROM_QSTR(MP_QSTR_set_native_code_location), MP_ROM_PTR(&esp_set_native_code_location_obj) },
+ #endif
+
+#if MODESP_INCLUDE_CONSTANTS
+ { MP_ROM_QSTR(MP_QSTR_SLEEP_NONE), MP_ROM_INT(NONE_SLEEP_T) },
+ { MP_ROM_QSTR(MP_QSTR_SLEEP_LIGHT), MP_ROM_INT(LIGHT_SLEEP_T) },
+ { MP_ROM_QSTR(MP_QSTR_SLEEP_MODEM), MP_ROM_INT(MODEM_SLEEP_T) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);
+
+const mp_obj_module_t esp_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&esp_module_globals,
+};
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c
new file mode 100644
index 000000000..99286848e
--- /dev/null
+++ b/ports/esp8266/modmachine.c
@@ -0,0 +1,279 @@
+/*
+ * 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 <stdio.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "extmod/machine_mem.h"
+#include "extmod/machine_signal.h"
+#include "extmod/machine_pulse.h"
+#include "extmod/machine_i2c.h"
+#include "modmachine.h"
+
+#include "xtirq.h"
+#include "os_type.h"
+#include "osapi.h"
+#include "etshal.h"
+#include "ets_alt_task.h"
+#include "user_interface.h"
+
+#if MICROPY_PY_MACHINE
+
+//#define MACHINE_WAKE_IDLE (0x01)
+//#define MACHINE_WAKE_SLEEP (0x02)
+#define MACHINE_WAKE_DEEPSLEEP (0x04)
+
+extern const mp_obj_type_t esp_wdt_type;
+
+STATIC mp_obj_t machine_freq(size_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) {
+ mp_raise_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_reset_cause(void) {
+ return MP_OBJ_NEW_SMALL_INT(system_get_rst_info()->reason);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
+
+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);
+
+STATIC mp_obj_t machine_idle(void) {
+ uint32_t t = mp_hal_ticks_cpu();
+ asm("waiti 0");
+ t = mp_hal_ticks_cpu() - t;
+ return MP_OBJ_NEW_SMALL_INT(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
+
+STATIC mp_obj_t machine_sleep(void) {
+ printf("Warning: not yet implemented\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
+
+STATIC mp_obj_t machine_deepsleep(void) {
+ // default to sleep forever
+ uint32_t sleep_us = 0;
+
+ // see if RTC.ALARM0 should wake the device
+ if (pyb_rtc_alarm0_wake & MACHINE_WAKE_DEEPSLEEP) {
+ uint64_t t = pyb_rtc_get_us_since_2000();
+ if (pyb_rtc_alarm0_expiry <= t) {
+ sleep_us = 1; // alarm already expired so wake immediately
+ } else {
+ uint64_t delta = pyb_rtc_alarm0_expiry - t;
+ if (delta <= 0xffffffff) {
+ // sleep for the desired time
+ sleep_us = delta;
+ } else {
+ // overflow, just set to maximum sleep time
+ sleep_us = 0xffffffff;
+ }
+ }
+ }
+
+ // prepare for RTC reset at wake up
+ rtc_prepare_deepsleep(sleep_us);
+ // put the device in a deep-sleep state
+ system_deep_sleep_set_option(0); // default power down mode; TODO check this
+ system_deep_sleep(sleep_us);
+
+ for (;;) {
+ // we must not return
+ ets_loop_iter();
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
+
+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, size_t n_args, size_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;
+ mp_sched_schedule(self->callback, self);
+}
+
+STATIC mp_obj_t esp_timer_init_helper(esp_timer_obj_t *self, size_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(size_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_rom_map_elem_t esp_timer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp_timer_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&esp_timer_init_obj) },
+// { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&esp_timer_callback_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) },
+ { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) },
+};
+STATIC MP_DEFINE_CONST_DICT(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_dict_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) },
+ { 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_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
+ { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_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_WDT), MP_ROM_PTR(&esp_wdt_type) },
+ { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
+ { MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
+ { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
+ { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
+ { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hspi_type) },
+
+ // wake abilities
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
+
+ // reset causes
+ { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },
+ { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
+ { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) },
+ { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) },
+ { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(REASON_SOFT_RESTART) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
+
+const mp_obj_module_t mp_module_machine = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&machine_module_globals,
+};
+
+#endif // MICROPY_PY_MACHINE
diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h
new file mode 100644
index 000000000..eae351f68
--- /dev/null
+++ b/ports/esp8266/modmachine.h
@@ -0,0 +1,41 @@
+#ifndef MICROPY_INCLUDED_ESP8266_MODMACHINE_H
+#define MICROPY_INCLUDED_ESP8266_MODMACHINE_H
+
+#include "py/obj.h"
+
+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 machine_hspi_type;
+
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj);
+
+typedef struct _pyb_pin_obj_t {
+ mp_obj_base_t base;
+ uint16_t phys_port;
+ uint16_t func;
+ uint32_t periph;
+} pyb_pin_obj_t;
+
+const pyb_pin_obj_t pyb_pin_obj[16 + 1];
+
+void pin_init0(void);
+void pin_intr_handler_iram(void *arg);
+void pin_intr_handler(uint32_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);
+
+extern uint32_t pyb_rtc_alarm0_wake;
+extern uint64_t pyb_rtc_alarm0_expiry;
+
+void pyb_rtc_set_us_since_2000(uint64_t nowus);
+uint64_t pyb_rtc_get_us_since_2000();
+void rtc_prepare_deepsleep(uint64_t sleep_us);
+
+#endif // MICROPY_INCLUDED_ESP8266_MODMACHINE_H
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
new file mode 100644
index 000000000..3acd244b8
--- /dev/null
+++ b/ports/esp8266/modnetwork.c
@@ -0,0 +1,488 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-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 "py/nlr.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "lib/netutils/netutils.h"
+#include "queue.h"
+#include "user_interface.h"
+#include "espconn.h"
+#include "spi_flash.h"
+#include "ets_alt_task.h"
+#include "lwip/dns.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);
+const mp_obj_type_t wlan_if_type;
+
+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_obj_t get_wlan(size_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(size_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(size_t n_args, const mp_obj_t *args) {
+ require_if(args[0], STATION_IF);
+ struct station_config config = {{0}};
+ size_t len;
+ const char *p;
+
+ if (n_args > 1) {
+ p = mp_obj_str_get_data(args[1], &len);
+ len = MIN(len, sizeof(config.ssid));
+ memcpy(config.ssid, p, len);
+ if (n_args > 2) {
+ p = mp_obj_str_get_data(args[2], &len);
+ len = MIN(len, sizeof(config.password));
+ memcpy(config.password, p, len);
+ }
+
+ error_check(wifi_station_set_config(&config), "Cannot set STA config");
+ }
+ error_check(wifi_station_connect(), "Cannot connect to AP");
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect);
+
+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_1(esp_disconnect_obj, esp_disconnect);
+
+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_1(esp_status_obj, esp_status);
+
+STATIC mp_obj_t *esp_scan_list = NULL;
+
+STATIC void esp_scan_cb(void *result, STATUS status) {
+ if (esp_scan_list == NULL) {
+ // called unexpectedly
+ return;
+ }
+ if (result && status == 0) {
+ // we need to catch any memory errors
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) {
+ mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
+ #if 1
+ // struct bss_info::ssid_len is not documented in SDK API Guide,
+ // but is present in SDK headers since 1.4.0
+ t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len);
+ #else
+ t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char*)bs->ssid));
+ #endif
+ 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
+ *esp_scan_list = MP_OBJ_NULL;
+ }
+ esp_scan_list = NULL;
+}
+
+STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
+ require_if(self_in, STATION_IF);
+ if ((wifi_get_opmode() & STATION_MODE) == 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
+ "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);
+ 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"));
+ }
+ 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(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_1(esp_isconnected_obj, esp_isconnected);
+
+STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ struct ip_info info;
+ ip_addr_t dns_addr;
+ wifi_get_ip_info(self->if_id, &info);
+ if (n_args == 1) {
+ // get
+ dns_addr = dns_getserver(0);
+ mp_obj_t tuple[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),
+ netutils_format_ipv4_addr((uint8_t*)&dns_addr, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else {
+ // set
+ mp_obj_t *items;
+ bool restart_dhcp_server = false;
+ mp_obj_get_array_fixed_n(args[1], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (void*)&info.ip, NETUTILS_BIG);
+ if (mp_obj_is_integer(items[1])) {
+ // allow numeric netmask, i.e.:
+ // 24 -> 255.255.255.0
+ // 16 -> 255.255.0.0
+ // etc...
+ uint32_t* m = (uint32_t*)&info.netmask;
+ *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
+ } else {
+ netutils_parse_ipv4_addr(items[1], (void*)&info.netmask, NETUTILS_BIG);
+ }
+ netutils_parse_ipv4_addr(items[2], (void*)&info.gw, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[3], (void*)&dns_addr, NETUTILS_BIG);
+ // To set a static IP we have to disable DHCP first
+ if (self->if_id == STATION_IF) {
+ wifi_station_dhcpc_stop();
+ } else {
+ restart_dhcp_server = wifi_softap_dhcps_status();
+ wifi_softap_dhcps_stop();
+ }
+ if (!wifi_set_ip_info(self->if_id, &info)) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError,
+ "wifi_set_ip_info() failed"));
+ }
+ dns_setserver(0, &dns_addr);
+ if (restart_dhcp_server) {
+ wifi_softap_dhcps_start();
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, 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) {
+ mp_raise_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");
+ }
+
+ int req_if = -1;
+
+ 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_mac): {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != 6) {
+ mp_raise_ValueError("invalid buffer length");
+ }
+ wifi_set_macaddr(self->if_id, bufinfo.buf);
+ break;
+ }
+ case QS(MP_QSTR_essid): {
+ req_if = SOFTAP_IF;
+ size_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;
+ }
+ case QS(MP_QSTR_hidden): {
+ req_if = SOFTAP_IF;
+ cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_authmode): {
+ req_if = SOFTAP_IF;
+ cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_password): {
+ req_if = SOFTAP_IF;
+ size_t len;
+ const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ len = MIN(len, sizeof(cfg.ap.password) - 1);
+ memcpy(cfg.ap.password, s, len);
+ cfg.ap.password[len] = 0;
+ break;
+ }
+ case QS(MP_QSTR_channel): {
+ req_if = SOFTAP_IF;
+ cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case QS(MP_QSTR_dhcp_hostname): {
+ req_if = STATION_IF;
+ if (self->if_id == STATION_IF) {
+ const char *s = mp_obj_str_get_str(kwargs->table[i].value);
+ wifi_station_set_hostname((char*)s);
+ }
+ break;
+ }
+ default:
+ goto unknown;
+ }
+ #undef QS
+ }
+ }
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+
+ 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) {
+ mp_raise_TypeError("can query only one param");
+ }
+
+ mp_obj_t val;
+
+ #define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+ switch ((uintptr_t)args[1]) {
+ case QS(MP_QSTR_mac): {
+ uint8_t mac[6];
+ wifi_get_macaddr(self->if_id, mac);
+ return mp_obj_new_bytes(mac, sizeof(mac));
+ }
+ case QS(MP_QSTR_essid):
+ req_if = SOFTAP_IF;
+ val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false);
+ break;
+ case QS(MP_QSTR_hidden):
+ req_if = SOFTAP_IF;
+ val = mp_obj_new_bool(cfg.ap.ssid_hidden);
+ break;
+ case QS(MP_QSTR_authmode):
+ req_if = SOFTAP_IF;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
+ break;
+ case QS(MP_QSTR_channel):
+ req_if = SOFTAP_IF;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
+ break;
+ case QS(MP_QSTR_dhcp_hostname): {
+ req_if = STATION_IF;
+ char* s = wifi_station_get_hostname();
+ val = mp_obj_new_str(s, strlen(s), false);
+ break;
+ }
+ default:
+ goto unknown;
+ }
+ #undef QS
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+
+ return val;
+
+unknown:
+ mp_raise_ValueError("unknown config param");
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
+
+STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+};
+
+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_dict_t*)&wlan_if_locals_dict,
+};
+
+STATIC mp_obj_t esp_phy_mode(size_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_rom_map_elem_t mp_module_network_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
+ { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
+
+#if MODNETWORK_INCLUDE_CONSTANTS
+ { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},
+ { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},
+
+ { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},
+ { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},
+ { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},
+ { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},
+ { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},
+ { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},
+
+ { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },
+ { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },
+ { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },
+
+ { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },
+ { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
+#endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
+
+const mp_obj_module_t network_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_network_globals,
+};
diff --git a/ports/esp8266/modpyb.c b/ports/esp8266/modpyb.c
new file mode 100644
index 000000000..0a23f6f9d
--- /dev/null
+++ b/ports/esp8266/modpyb.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#include "py/gc.h"
+#include "gccollect.h"
+#include "modmachine.h"
+
+// The pyb module no longer exists since all functionality now appears
+// elsewhere, in more standard places (eg time, machine modules). The
+// only remaining function is pyb.info() which has been moved to the
+// esp module, pending deletion/renaming/moving elsewhere.
+
+STATIC mp_obj_t pyb_info(size_t n_args, const mp_obj_t *args) {
+ // print info about memory
+ {
+ printf("_text_start=%p\n", &_text_start);
+ printf("_text_end=%p\n", &_text_end);
+ printf("_irom0_text_start=%p\n", &_irom0_text_start);
+ printf("_irom0_text_end=%p\n", &_irom0_text_end);
+ printf("_data_start=%p\n", &_data_start);
+ printf("_data_end=%p\n", &_data_end);
+ printf("_rodata_start=%p\n", &_rodata_start);
+ printf("_rodata_end=%p\n", &_rodata_end);
+ printf("_bss_start=%p\n", &_bss_start);
+ printf("_bss_end=%p\n", &_bss_end);
+ printf("_heap_start=%p\n", &_heap_start);
+ printf("_heap_end=%p\n", &_heap_end);
+ }
+
+ // qstr info
+ {
+ mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+ qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+ printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
+ }
+
+ // GC info
+ {
+ gc_info_t info;
+ gc_info(&info);
+ printf("GC:\n");
+ printf(" " UINT_FMT " total\n", info.total);
+ printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
+ printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
+ }
+
+ if (n_args == 1) {
+ // arg given means dump gc allocation table
+ gc_dump_alloc_table();
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
diff --git a/ports/esp8266/modules/_boot.py b/ports/esp8266/modules/_boot.py
new file mode 100644
index 000000000..81eb20dd6
--- /dev/null
+++ b/ports/esp8266/modules/_boot.py
@@ -0,0 +1,13 @@
+import gc
+gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)
+import uos
+from flashbdev import bdev
+
+try:
+ if bdev:
+ uos.mount(bdev, '/')
+except OSError:
+ import inisetup
+ inisetup.setup()
+
+gc.collect()
diff --git a/ports/esp8266/modules/apa102.py b/ports/esp8266/modules/apa102.py
new file mode 100644
index 000000000..41b7c0485
--- /dev/null
+++ b/ports/esp8266/modules/apa102.py
@@ -0,0 +1,17 @@
+# APA102 driver for MicroPython on ESP8266
+# MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch
+
+from esp import apa102_write
+from neopixel import NeoPixel
+
+
+class APA102(NeoPixel):
+ ORDER = (0, 1, 2, 3)
+
+ def __init__(self, clock_pin, data_pin, n, bpp=4):
+ super().__init__(data_pin, n, bpp)
+ self.clock_pin = clock_pin
+ self.clock_pin.init(clock_pin.OUT)
+
+ def write(self):
+ apa102_write(self.clock_pin, self.pin, self.buf)
diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py
new file mode 100644
index 000000000..9a69e7e07
--- /dev/null
+++ b/ports/esp8266/modules/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/ports/esp8266/modules/ds18x20.py b/ports/esp8266/modules/ds18x20.py
new file mode 120000
index 000000000..faae59d90
--- /dev/null
+++ b/ports/esp8266/modules/ds18x20.py
@@ -0,0 +1 @@
+../../drivers/onewire/ds18x20.py \ No newline at end of file
diff --git a/ports/esp8266/modules/flashbdev.py b/ports/esp8266/modules/flashbdev.py
new file mode 100644
index 000000000..40ba655c6
--- /dev/null
+++ b/ports/esp8266/modules/flashbdev.py
@@ -0,0 +1,35 @@
+import esp
+
+class FlashBdev:
+
+ SEC_SIZE = 4096
+ RESERVED_SECS = 1
+ START_SEC = esp.flash_user_start() // SEC_SIZE + RESERVED_SECS
+ NUM_BLK = 0x6b - RESERVED_SECS
+
+ def __init__(self, blocks=NUM_BLK):
+ self.blocks = blocks
+
+ def readblocks(self, n, buf):
+ #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
+ esp.flash_read((n + self.START_SEC) * self.SEC_SIZE, buf)
+
+ def writeblocks(self, n, buf):
+ #print("writeblocks(%s, %x(%d))" % (n, id(buf), len(buf)))
+ #assert len(buf) <= self.SEC_SIZE, len(buf)
+ esp.flash_erase(n + self.START_SEC)
+ esp.flash_write((n + self.START_SEC) * self.SEC_SIZE, buf)
+
+ def ioctl(self, op, arg):
+ #print("ioctl(%d, %r)" % (op, arg))
+ if op == 4: # BP_IOCTL_SEC_COUNT
+ return self.blocks
+ if op == 5: # BP_IOCTL_SEC_SIZE
+ return self.SEC_SIZE
+
+size = esp.flash_size()
+if size < 1024*1024:
+ bdev = None
+else:
+ # 20K at the flash end is reserved for SDK params storage
+ bdev = FlashBdev((size - 20480) // FlashBdev.SEC_SIZE - FlashBdev.START_SEC)
diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py
new file mode 100644
index 000000000..af78dfad5
--- /dev/null
+++ b/ports/esp8266/modules/inisetup.py
@@ -0,0 +1,52 @@
+import uos
+import network
+from flashbdev import bdev
+
+def wifi():
+ import ubinascii
+ ap_if = network.WLAN(network.AP_IF)
+ essid = b"MicroPython-%s" % ubinascii.hexlify(ap_if.config("mac")[-3:])
+ ap_if.config(essid=essid, authmode=network.AUTH_WPA_WPA2_PSK, password=b"micropythoN")
+
+def check_bootsec():
+ buf = bytearray(bdev.SEC_SIZE)
+ bdev.readblocks(0, buf)
+ empty = True
+ for b in buf:
+ if b != 0xff:
+ empty = False
+ break
+ if empty:
+ return True
+ fs_corrupted()
+
+def fs_corrupted():
+ import time
+ while 1:
+ print("""\
+The FAT filesystem starting at sector %d with size %d sectors appears to
+be corrupted. If you had important data there, you may want to make a flash
+snapshot to try to recover it. Otherwise, perform factory reprogramming
+of MicroPython firmware (completely erase flash, followed by firmware
+programming).
+""" % (bdev.START_SEC, bdev.blocks))
+ time.sleep(3)
+
+def setup():
+ check_bootsec()
+ print("Performing initial setup")
+ wifi()
+ uos.VfsFat.mkfs(bdev)
+ vfs = uos.VfsFat(bdev)
+ uos.mount(vfs, '/')
+ with open("boot.py", "w") as f:
+ f.write("""\
+# This file is executed on every boot (including wake-boot from deepsleep)
+#import esp
+#esp.osdebug(None)
+import gc
+#import webrepl
+#webrepl.start()
+gc.collect()
+""")
+ return vfs
diff --git a/ports/esp8266/modules/neopixel.py b/ports/esp8266/modules/neopixel.py
new file mode 100644
index 000000000..b13424d7d
--- /dev/null
+++ b/ports/esp8266/modules/neopixel.py
@@ -0,0 +1,32 @@
+# NeoPixel driver for MicroPython on ESP8266
+# MIT license; Copyright (c) 2016 Damien P. George
+
+from esp import neopixel_write
+
+
+class NeoPixel:
+ ORDER = (1, 0, 2, 3)
+
+ def __init__(self, pin, n, bpp=3):
+ self.pin = pin
+ self.n = n
+ self.bpp = bpp
+ self.buf = bytearray(n * bpp)
+ self.pin.init(pin.OUT)
+
+ def __setitem__(self, index, val):
+ offset = index * self.bpp
+ for i in range(self.bpp):
+ self.buf[offset + self.ORDER[i]] = val[i]
+
+ def __getitem__(self, index):
+ offset = index * self.bpp
+ return tuple(self.buf[offset + self.ORDER[i]]
+ for i in range(self.bpp))
+
+ def fill(self, color):
+ for i in range(self.n):
+ self[i] = color
+
+ def write(self):
+ neopixel_write(self.pin, self.buf, True)
diff --git a/ports/esp8266/modules/ntptime.py b/ports/esp8266/modules/ntptime.py
new file mode 100644
index 000000000..a97e08e60
--- /dev/null
+++ b/ports/esp8266/modules/ntptime.py
@@ -0,0 +1,36 @@
+try:
+ import usocket as socket
+except:
+ import socket
+try:
+ import ustruct as struct
+except:
+ import struct
+
+# (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(host, 123)[0][-1]
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.settimeout(1)
+ res = s.sendto(NTP_QUERY, addr)
+ msg = s.recv(48)
+ s.close()
+ val = struct.unpack("!I", msg[40:44])[0]
+ return val - NTP_DELTA
+
+# There's currently no timezone support in MicroPython, so
+# utime.localtime() will return UTC time (as if it was .gmtime())
+def settime():
+ t = time()
+ import machine
+ import utime
+ tm = utime.localtime(t)
+ tm = tm[0:3] + (0,) + tm[3:6] + (0,)
+ machine.RTC().datetime(tm)
+ print(utime.localtime())
diff --git a/ports/esp8266/modules/onewire.py b/ports/esp8266/modules/onewire.py
new file mode 120000
index 000000000..f6ec745e8
--- /dev/null
+++ b/ports/esp8266/modules/onewire.py
@@ -0,0 +1 @@
+../../drivers/onewire/onewire.py \ No newline at end of file
diff --git a/ports/esp8266/modules/port_diag.py b/ports/esp8266/modules/port_diag.py
new file mode 100644
index 000000000..ef8800355
--- /dev/null
+++ b/ports/esp8266/modules/port_diag.py
@@ -0,0 +1,33 @@
+import esp
+import uctypes
+import network
+import lwip
+
+
+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:")
+ SZ_MAP = {0: "512KB", 1: "256KB", 2: "1MB", 3: "2MB", 4: "4MB"}
+ FREQ_MAP = {0: "40MHZ", 1: "26MHZ", 2: "20MHz", 0xf: "80MHz"}
+ 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("Firmware checksum:")
+ print(esp.check_fw())
+
+ 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, comm in enumerate(("1,2 TX", "4 Mngmt TX(len: 0x41-0x100)", "5 Mngmt TX (len: 0-0x40)", "7", "8 RX")):
+ print("%d: %d (%s)" % (i, esp.esf_free_bufs(i), comm))
+ print("lwIP PCBs:")
+ lwip.print_pcbs()
+
+
+main()
diff --git a/ports/esp8266/modules/upip.py b/ports/esp8266/modules/upip.py
new file mode 120000
index 000000000..20d52a4ab
--- /dev/null
+++ b/ports/esp8266/modules/upip.py
@@ -0,0 +1 @@
+../../tools/upip.py \ No newline at end of file
diff --git a/ports/esp8266/modules/upip_utarfile.py b/ports/esp8266/modules/upip_utarfile.py
new file mode 120000
index 000000000..149886291
--- /dev/null
+++ b/ports/esp8266/modules/upip_utarfile.py
@@ -0,0 +1 @@
+../../tools/upip_utarfile.py \ No newline at end of file
diff --git a/ports/esp8266/modules/webrepl.py b/ports/esp8266/modules/webrepl.py
new file mode 100644
index 000000000..5a76e9b26
--- /dev/null
+++ b/ports/esp8266/modules/webrepl.py
@@ -0,0 +1,77 @@
+# This module should be imported from REPL, not run from command line.
+import socket
+import uos
+import network
+import websocket
+import websocket_helper
+import _webrepl
+
+listen_s = None
+client_s = None
+
+def setup_conn(port, accept_handler):
+ global listen_s
+ listen_s = socket.socket()
+ listen_s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+ ai = socket.getaddrinfo("0.0.0.0", port)
+ addr = ai[0][4]
+
+ listen_s.bind(addr)
+ listen_s.listen(1)
+ 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):
+ global client_s
+ cl, remote_addr = listen_sock.accept()
+ if uos.dupterm():
+ print("\nConcurrent WebREPL connection from", remote_addr, "rejected")
+ cl.close()
+ return
+ print("\nWebREPL connection from:", remote_addr)
+ client_s = cl
+ websocket_helper.server_handshake(cl)
+ ws = websocket.websocket(cl, True)
+ ws = _webrepl._webrepl(ws)
+ cl.setblocking(False)
+ # notify REPL on socket incoming data
+ cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
+ uos.dupterm(ws)
+
+
+def stop():
+ global listen_s, client_s
+ uos.dupterm(None)
+ if client_s:
+ client_s.close()
+ if listen_s:
+ listen_s.close()
+
+
+def start(port=8266, password=None):
+ stop()
+ if password is None:
+ try:
+ import webrepl_cfg
+ _webrepl.password(webrepl_cfg.PASS)
+ setup_conn(port, accept_conn)
+ print("Started webrepl in normal mode")
+ except:
+ print("WebREPL is not configured, run 'import webrepl_setup'")
+ else:
+ _webrepl.password(password)
+ setup_conn(port, accept_conn)
+ print("Started webrepl in manual override mode")
+
+
+def start_foreground(port=8266):
+ stop()
+ s = setup_conn(port, None)
+ accept_conn(s)
diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py
new file mode 100644
index 000000000..d91600e6e
--- /dev/null
+++ b/ports/esp8266/modules/webrepl_setup.py
@@ -0,0 +1,111 @@
+import sys
+#import uos as os
+import os
+import machine
+
+RC = "./boot.py"
+CONFIG = "./webrepl_cfg.py"
+
+def input_choice(prompt, choices):
+ while 1:
+ resp = input(prompt)
+ if resp in choices:
+ return resp
+
+def getpass(prompt):
+ return input(prompt)
+
+def input_pass():
+ while 1:
+ passwd1 = getpass("New password: ")
+ if len(passwd1) < 4:
+ print("Password too short")
+ continue
+ elif len(passwd1) > 9:
+ print("Password too long")
+ continue
+ passwd2 = getpass("Confirm password: ")
+ if passwd1 == passwd2:
+ return passwd1
+ print("Passwords do not match")
+
+
+def exists(fname):
+ try:
+ with open(fname):
+ pass
+ return True
+ except OSError:
+ return False
+
+def copy_stream(s_in, s_out):
+ buf = bytearray(64)
+ while 1:
+ sz = s_in.readinto(buf)
+ s_out.write(buf, sz)
+
+
+def get_daemon_status():
+ with open(RC) as f:
+ for l in f:
+ if "webrepl" in l:
+ if l.startswith("#"):
+ return False
+ return True
+ return None
+
+def add_daemon():
+ with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
+ new_f.write("import webrepl\nwebrepl.start()\n")
+ copy_stream(old_f, new_f)
+
+def change_daemon(action):
+ LINES = ("import webrepl", "webrepl.start()")
+ with open(RC) as old_f, open(RC + ".tmp", "w") as new_f:
+ for l in old_f:
+ for patt in LINES:
+ if patt in l:
+ if action and l.startswith("#"):
+ l = l[1:]
+ elif not action and not l.startswith("#"):
+ l = "#" + l
+ new_f.write(l)
+ # FatFs rename() is not POSIX compliant, will raise OSError if
+ # dest file exists.
+ os.remove(RC)
+ os.rename(RC + ".tmp", RC)
+
+
+def main():
+ status = get_daemon_status()
+
+ print("WebREPL daemon auto-start status:", "enabled" if status else "disabled")
+ print("\nWould you like to (E)nable or (D)isable it running on boot?")
+ print("(Empty line to quit)")
+ resp = input("> ").upper()
+
+ if resp == "E":
+ if exists(CONFIG):
+ resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", ""))
+ else:
+ print("To enable WebREPL, you must set password for it")
+ resp2 = "y"
+
+ if resp2 == "y":
+ passwd = input_pass()
+ with open(CONFIG, "w") as f:
+ f.write("PASS = %r\n" % passwd)
+
+
+ if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status):
+ print("No further action required")
+ sys.exit()
+
+ change_daemon(resp == "E")
+
+ print("Changes will be activated after reboot")
+ resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", ""))
+ if resp == "y":
+ machine.reset()
+
+main()
diff --git a/ports/esp8266/modules/websocket_helper.py b/ports/esp8266/modules/websocket_helper.py
new file mode 100644
index 000000000..9c06db502
--- /dev/null
+++ b/ports/esp8266/modules/websocket_helper.py
@@ -0,0 +1,74 @@
+import sys
+try:
+ import ubinascii as binascii
+except:
+ import binascii
+try:
+ import uhashlib as hashlib
+except:
+ import hashlib
+
+DEBUG = 0
+
+def server_handshake(sock):
+ clr = sock.makefile("rwb", 0)
+ l = clr.readline()
+ #sys.stdout.write(repr(l))
+
+ webkey = None
+
+ while 1:
+ l = clr.readline()
+ if not l:
+ raise OSError("EOF in headers")
+ if l == b"\r\n":
+ break
+ # sys.stdout.write(l)
+ h, v = [x.strip() for x in l.split(b":", 1)]
+ if DEBUG:
+ print((h, v))
+ if h == b'Sec-WebSocket-Key':
+ webkey = v
+
+ if not webkey:
+ raise OSError("Not a websocket request")
+
+ if DEBUG:
+ print("Sec-WebSocket-Key:", webkey, len(webkey))
+
+ d = hashlib.sha1(webkey)
+ d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
+ respkey = d.digest()
+ respkey = binascii.b2a_base64(respkey)[:-1]
+ if DEBUG:
+ print("respkey:", respkey)
+
+ sock.send(b"""\
+HTTP/1.1 101 Switching Protocols\r
+Upgrade: websocket\r
+Connection: Upgrade\r
+Sec-WebSocket-Accept: """)
+ sock.send(respkey)
+ sock.send("\r\n\r\n")
+
+
+# Very simplified client handshake, works for MicroPython's
+# websocket server implementation, but probably not for other
+# servers.
+def client_handshake(sock):
+ cl = sock.makefile("rwb", 0)
+ cl.write(b"""\
+GET / HTTP/1.1\r
+Host: echo.websocket.org\r
+Connection: Upgrade\r
+Upgrade: websocket\r
+Sec-WebSocket-Key: foo\r
+\r
+""")
+ l = cl.readline()
+# print(l)
+ while 1:
+ l = cl.readline()
+ if l == b"\r\n":
+ break
+# sys.stdout.write(l)
diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c
new file mode 100644
index 000000000..d0554096e
--- /dev/null
+++ b/ports/esp8266/moduos.c
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "extmod/misc.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "genhdr/mpversion.h"
+#include "esp_mphal.h"
+#include "user_interface.h"
+
+STATIC const qstr os_uname_info_fields[] = {
+ MP_QSTR_sysname, MP_QSTR_nodename,
+ MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
+};
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
+
+STATIC mp_obj_tuple_t os_uname_info_obj = {
+ .base = {&mp_type_attrtuple},
+ .len = 5,
+ .items = {
+ (mp_obj_t)&os_uname_info_sysname_obj,
+ (mp_obj_t)&os_uname_info_nodename_obj,
+ NULL,
+ (mp_obj_t)&os_uname_info_version_obj,
+ (mp_obj_t)&os_uname_info_machine_obj,
+ (void *)os_uname_info_fields,
+ }
+};
+
+STATIC mp_obj_t os_uname(void) {
+ // We must populate the "release" field each time in case it was GC'd since the last call.
+ const char *ver = system_get_sdk_version();
+ os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver), false);
+ return (mp_obj_t)&os_uname_info_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
+
+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 mp_obj_t os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ mp_hal_signal_dupterm_input();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_dupterm_notify_obj, os_dupterm_notify);
+
+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) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) },
+ #endif
+ #if MICROPY_VFS_FAT
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t uos_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&os_module_globals,
+};
diff --git a/ports/esp8266/modutime.c b/ports/esp8266/modutime.c
new file mode 100644
index 000000000..77dbcfa1f
--- /dev/null
+++ b/ports/esp8266/modutime.c
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Josef Gajdusek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/obj.h"
+#include "py/gc.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/smallint.h"
+#include "lib/timeutils/timeutils.h"
+#include "modmachine.h"
+#include "user_interface.h"
+#include "extmod/utime_mphal.h"
+
+/// \module time - time related functions
+///
+/// The `time` module provides functions for getting the current time and date,
+/// and for sleeping.
+
+/// \function localtime([secs])
+/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
+/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
+/// If secs is not provided or None, then the current time from the RTC is used.
+/// year includes the century (for example 2014)
+/// month is 1-12
+/// mday is 1-31
+/// hour is 0-23
+/// minute is 0-59
+/// second is 0-59
+/// weekday is 0-6 for Mon-Sun.
+/// yearday is 1-366
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+ timeutils_struct_time_t tm;
+ mp_int_t seconds;
+ if (n_args == 0 || args[0] == mp_const_none) {
+ seconds = pyb_rtc_get_us_since_2000() / 1000 / 1000;
+ } else {
+ seconds = mp_obj_get_int(args[0]);
+ }
+ timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
+ mp_obj_t tuple[8] = {
+ tuple[0] = mp_obj_new_int(tm.tm_year),
+ tuple[1] = mp_obj_new_int(tm.tm_mon),
+ tuple[2] = mp_obj_new_int(tm.tm_mday),
+ tuple[3] = mp_obj_new_int(tm.tm_hour),
+ tuple[4] = mp_obj_new_int(tm.tm_min),
+ tuple[5] = mp_obj_new_int(tm.tm_sec),
+ tuple[6] = mp_obj_new_int(tm.tm_wday),
+ tuple[7] = mp_obj_new_int(tm.tm_yday),
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
+
+/// \function mktime()
+/// This is inverse function of localtime. It's argument is a full 8-tuple
+/// which expresses a time as per localtime. It returns an integer which is
+/// the number of seconds since Jan 1, 2000.
+STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
+ size_t len;
+ mp_obj_t *elem;
+ mp_obj_get_array(tuple, &len, &elem);
+
+ // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
+ if (len < 8 || len > 9) {
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "mktime needs a tuple of length 8 or 9 (%d given)", len));
+ }
+
+ return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+ mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+ mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
+
+/// \function time()
+/// Returns the number of seconds, as an integer, since 1/1/2000.
+STATIC mp_obj_t time_time(void) {
+ // get date and time
+ return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
+
+STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
+
+ { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
+
+const mp_obj_module_t utime_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&time_module_globals,
+};
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
new file mode 100644
index 000000000..c45ed92c7
--- /dev/null
+++ b/ports/esp8266/mpconfigport.h
@@ -0,0 +1,198 @@
+#include <stdint.h>
+
+// options to control how MicroPython is built
+
+#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_PERSISTENT_CODE_LOAD (1)
+#define MICROPY_EMIT_XTENSA (1)
+#define MICROPY_EMIT_INLINE_XTENSA (1)
+#define MICROPY_MEM_STATS (0)
+#define MICROPY_DEBUG_PRINTERS (1)
+#define MICROPY_DEBUG_PRINTER_DEST mp_debug_print
+#define MICROPY_READER_VFS (MICROPY_VFS)
+#define MICROPY_ENABLE_GC (1)
+#define MICROPY_ENABLE_FINALISER (1)
+#define MICROPY_STACK_CHECK (1)
+#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
+#define MICROPY_KBD_EXCEPTION (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_USE_INTERNAL_ERRNO (1)
+#define MICROPY_ENABLE_SCHEDULER (1)
+#define MICROPY_PY_ALL_SPECIAL_METHODS (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)
+#define MICROPY_PY_BUILTINS_FROZENSET (1)
+#define MICROPY_PY_BUILTINS_SET (1)
+#define MICROPY_PY_BUILTINS_SLICE (1)
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
+#define MICROPY_PY_BUILTINS_PROPERTY (1)
+#define MICROPY_PY_BUILTINS_INPUT (1)
+#define MICROPY_PY_BUILTINS_HELP (1)
+#define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text
+#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
+#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_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_SYS_STDIO_BUFFER (1)
+#define MICROPY_PY_UERRNO (1)
+#define MICROPY_PY_UBINASCII (1)
+#define MICROPY_PY_UCTYPES (1)
+#define MICROPY_PY_UHASHLIB (1)
+#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS)
+#define MICROPY_PY_UHEAPQ (1)
+#define MICROPY_PY_UTIMEQ (1)
+#define MICROPY_PY_UJSON (1)
+#define MICROPY_PY_URANDOM (1)
+#define MICROPY_PY_URE (1)
+#define MICROPY_PY_USELECT (1)
+#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_UZLIB (1)
+#define MICROPY_PY_LWIP (1)
+#define MICROPY_PY_MACHINE (1)
+#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
+#define MICROPY_PY_MACHINE_PULSE (1)
+#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_SPI (1)
+#define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hspi_make_new
+#define MICROPY_PY_WEBSOCKET (1)
+#define MICROPY_PY_WEBREPL (1)
+#define MICROPY_PY_WEBREPL_DELAY (20)
+#define MICROPY_PY_FRAMEBUF (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_WARNINGS (1)
+#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
+#define MICROPY_STREAMS_NON_BLOCK (1)
+#define MICROPY_STREAMS_POSIX_API (1)
+#define MICROPY_MODULE_FROZEN_STR (1)
+#define MICROPY_MODULE_FROZEN_MPY (1)
+#define MICROPY_MODULE_FROZEN_LEXER mp_lexer_new_from_str32
+#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
+
+#define MICROPY_VFS (1)
+#define MICROPY_FATFS_ENABLE_LFN (1)
+#define MICROPY_FATFS_RPATH (2)
+#define MICROPY_FATFS_MAX_SS (4096)
+#define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+#define MICROPY_VFS_FAT (1)
+#define MICROPY_ESP8266_APA102 (1)
+#define MICROPY_ESP8266_NEOPIXEL (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
+
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p)))
+
+#define MP_SSIZE_MAX (0x7fffffff)
+
+#define UINT_FMT "%u"
+#define INT_FMT "%d"
+
+typedef int32_t mp_int_t; // must be pointer size
+typedef uint32_t mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+typedef uint32_t sys_prot_t; // for modlwip
+// ssize_t, off_t as required by POSIX-signatured functions in stream.h
+#include <sys/types.h>
+
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+void *esp_native_code_commit(void*, size_t);
+#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len)
+
+#define mp_type_fileio fatfs_type_fileio
+#define mp_type_textio fatfs_type_textio
+
+// use vfs's functions for import stat and builtin open
+#define mp_import_stat mp_vfs_import_stat
+#define mp_builtin_open mp_vfs_open
+#define mp_builtin_open_obj mp_vfs_open_obj
+
+// extra built in names to add to the global namespace
+#define MICROPY_PORT_BUILTINS \
+ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
+
+// extra built in modules to add to the list of known ones
+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 mp_module_onewire;
+
+#define MICROPY_PORT_BUILTIN_MODULES \
+ { MP_ROM_QSTR(MP_QSTR_esp), MP_ROM_PTR(&esp_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_usocket), MP_ROM_PTR(&mp_module_lwip) }, \
+ { MP_ROM_QSTR(MP_QSTR_network), MP_ROM_PTR(&network_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&utime_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_uos), MP_ROM_PTR(&uos_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
+ { MP_ROM_QSTR(MP_QSTR__onewire), MP_ROM_PTR(&mp_module_onewire) }, \
+
+#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&utime_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&uos_module) }, \
+ { MP_ROM_QSTR(MP_QSTR_json), MP_ROM_PTR(&mp_module_ujson) }, \
+ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_uerrno) }, \
+ { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_module_uselect) }, \
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_module_lwip) }, \
+
+#define MP_STATE_PORT MP_STATE_VM
+
+#define MICROPY_PORT_ROOT_POINTERS \
+ const char *readline_hist[8]; \
+ mp_obj_t pin_irq_handler[16]; \
+
+// We need to provide a declaration/definition of alloca()
+#include <alloca.h>
+
+// board specifics
+
+#define MICROPY_MPHALPORT_H "esp_mphal.h"
+#define MICROPY_HW_BOARD_NAME "ESP module"
+#define MICROPY_HW_MCU_NAME "ESP8266"
+#define MICROPY_PY_SYS_PLATFORM "esp8266"
+
+#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n
+
+#define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr))
diff --git a/ports/esp8266/mpconfigport_512k.h b/ports/esp8266/mpconfigport_512k.h
new file mode 100644
index 000000000..b84c13479
--- /dev/null
+++ b/ports/esp8266/mpconfigport_512k.h
@@ -0,0 +1,34 @@
+#include <mpconfigport.h>
+
+#undef MICROPY_EMIT_XTENSA
+#define MICROPY_EMIT_XTENSA (0)
+#undef MICROPY_EMIT_INLINE_XTENSA
+#define MICROPY_EMIT_INLINE_XTENSA (0)
+
+#undef MICROPY_ERROR_REPORTING
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
+
+#undef MICROPY_VFS
+#define MICROPY_VFS (0)
+#undef MICROPY_VFS_FAT
+#define MICROPY_VFS_FAT (0)
+
+#undef MICROPY_PERSISTENT_CODE_LOAD
+#define MICROPY_PERSISTENT_CODE_LOAD (0)
+
+#undef MICROPY_PY_IO_FILEIO
+#define MICROPY_PY_IO_FILEIO (0)
+
+#undef MICROPY_PY_SYS_STDIO_BUFFER
+#define MICROPY_PY_SYS_STDIO_BUFFER (0)
+#undef MICROPY_PY_BUILTINS_SLICE_ATTRS
+#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0)
+#undef MICROPY_PY_ALL_SPECIAL_METHODS
+#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
+
+#undef MICROPY_PY_FRAMEBUF
+#define MICROPY_PY_FRAMEBUF (0)
+
+#undef mp_import_stat
+#undef mp_builtin_open
+#undef mp_builtin_open_obj
diff --git a/ports/esp8266/qstrdefsport.h b/ports/esp8266/qstrdefsport.h
new file mode 100644
index 000000000..8f301a69c
--- /dev/null
+++ b/ports/esp8266/qstrdefsport.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// qstrs specific to this port, only needed if they aren't auto-generated
+
+// Entries for sys.path
+Q(/)
+Q(/lib)
diff --git a/ports/esp8266/strtoll.c b/ports/esp8266/strtoll.c
new file mode 100644
index 000000000..4e8a4d056
--- /dev/null
+++ b/ports/esp8266/strtoll.c
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+
+// assumes endptr != NULL
+// doesn't check for sign
+// doesn't check for base-prefix
+long long int strtoll(const char *nptr, char **endptr, int base) {
+ long long val = 0;
+
+ for (; *nptr; nptr++) {
+ int v = *nptr;
+ if ('0' <= v && v <= '9') {
+ v -= '0';
+ } else if ('A' <= v && v <= 'Z') {
+ v -= 'A' - 10;
+ } else if ('a' <= v && v <= 'z') {
+ v -= 'a' - 10;
+ } else {
+ break;
+ }
+ if (v >= base) {
+ break;
+ }
+ val = val * base + v;
+ }
+
+ *endptr = (char*)nptr;
+
+ return val;
+}
diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c
new file mode 100644
index 000000000..6c1f9e095
--- /dev/null
+++ b/ports/esp8266/uart.c
@@ -0,0 +1,296 @@
+/******************************************************************************
+ * Copyright 2013-2014 Espressif Systems (Wuxi)
+ *
+ * FileName: uart.c
+ *
+ * Description: Two UART mode configration and interrupt handler.
+ * Check your hardware connection while use this mode.
+ *
+ * Modification history:
+ * 2014/3/12, v1.0 create this file.
+*******************************************************************************/
+#include "ets_sys.h"
+#include "osapi.h"
+#include "uart.h"
+#include "osapi.h"
+#include "uart_register.h"
+#include "etshal.h"
+#include "c_types.h"
+#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.
+extern UartDevice UartDev;
+
+// the uart to which OS messages go; -1 to disable
+static int uart_os = UART_OS;
+
+#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);
+
+/******************************************************************************
+ * FunctionName : uart_config
+ * Description : Internal used function
+ * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
+ * UART1 just used for debug output
+ * Parameters : uart_no, use UART0 or UART1 defined ahead
+ * Returns : NONE
+*******************************************************************************/
+static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) {
+ if (uart_no == UART1) {
+ PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
+ } else {
+ 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_U0RXD_U, FUNC_U0RXD);
+ }
+
+ uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
+
+ WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
+ | UartDev.parity
+ | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
+ | (UartDev.data_bits << UART_BIT_NUM_S));
+
+ // clear rx and tx fifo,not ready
+ SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
+ CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
+
+ if (uart_no == UART0) {
+ // set rx fifo trigger
+ WRITE_PERI_REG(UART_CONF1(uart_no),
+ ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
+ ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
+ UART_RX_FLOW_EN |
+ (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
+ UART_RX_TOUT_EN);
+ SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
+ UART_FRM_ERR_INT_ENA);
+ } else {
+ WRITE_PERI_REG(UART_CONF1(uart_no),
+ ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
+ }
+
+ // clear all interrupt
+ WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
+ // enable rx_interrupt
+ SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
+}
+
+/******************************************************************************
+ * FunctionName : uart1_tx_one_char
+ * Description : Internal used function
+ * Use uart1 interface to transfer one char
+ * Parameters : uint8 TxChar - character to tx
+ * Returns : OK
+*******************************************************************************/
+void uart_tx_one_char(uint8 uart, uint8 TxChar) {
+ 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) < 126) {
+ break;
+ }
+ }
+ 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
+ * Do some special deal while tx char is '\r' or '\n'
+ * Parameters : char c - character to tx
+ * Returns : NONE
+*******************************************************************************/
+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');
+ } else if (c == '\r') {
+ } else {
+ 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
+ * UART0 interrupt handler, add self handle code inside
+ * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
+ * Returns : NONE
+*******************************************************************************/
+
+static void uart0_rx_intr_handler(void *para) {
+ /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
+ * uart1 and uart0 respectively
+ */
+
+ uint8 uart_no = UART_REPL;
+
+ if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
+ // frame error
+ WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
+ }
+
+ if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
+ // fifo full
+ goto read_chars;
+ } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
+ read_chars:
+ ETS_UART_INTR_DISABLE();
+
+ 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 == mp_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();
+ }
+}
+
+// Waits at most timeout microseconds for at least 1 char to become ready for reading.
+// Returns true if something available, false if not.
+bool uart_rx_wait(uint32_t timeout_us) {
+ uint32_t start = system_get_time();
+ for (;;) {
+ if (input_buf.iget != input_buf.iput) {
+ return true; // have at least 1 char ready for reading
+ }
+ if (system_get_time() - start >= timeout_us) {
+ return false; // timeout
+ }
+ ets_event_poll();
+ }
+}
+
+int uart_rx_any(uint8 uart) {
+ if (input_buf.iget != input_buf.iput) {
+ return true; // have at least 1 char ready for reading
+ }
+ return false;
+}
+
+int uart_tx_any_room(uint8 uart) {
+ uint32_t 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) >= 126) {
+ return false;
+ }
+ return true;
+}
+
+// Returns char from the input buffer, else -1 if buffer is empty.
+int uart_rx_char(void) {
+ return ringbuf_get(&input_buf);
+}
+
+int uart_rx_one_char(uint8 uart_no) {
+ if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
+ return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
+ }
+ return -1;
+}
+
+/******************************************************************************
+ * FunctionName : uart_init
+ * Description : user interface for init uart
+ * Parameters : UartBautRate uart0_br - uart0 bautrate
+ * UartBautRate uart1_br - uart1 bautrate
+ * Returns : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) {
+ // rom use 74880 baut_rate, here reinitialize
+ UartDev.baut_rate = uart0_br;
+ uart_config(UART0);
+ UartDev.baut_rate = uart1_br;
+ uart_config(UART1);
+ ETS_UART_INTR_ENABLE();
+
+ // install handler for "os" messages
+ os_install_putc1((void *)uart_os_write_char);
+}
+
+void ICACHE_FLASH_ATTR uart_reattach() {
+ uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880);
+}
+
+void ICACHE_FLASH_ATTR uart_setup(uint8 uart) {
+ ETS_UART_INTR_DISABLE();
+ uart_config(uart);
+ ETS_UART_INTR_ENABLE();
+}
+
+// Task-based UART interface
+
+#include "py/obj.h"
+#include "lib/utils/pyexec.h"
+
+#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 = 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;
+ }
+ }
+
+ if (ret & PYEXEC_FORCED_EXIT) {
+ soft_reset();
+ }
+}
+
+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
diff --git a/ports/esp8266/uart.h b/ports/esp8266/uart.h
new file mode 100644
index 000000000..684689a0e
--- /dev/null
+++ b/ports/esp8266/uart.h
@@ -0,0 +1,106 @@
+#ifndef MICROPY_INCLUDED_ESP8266_UART_H
+#define MICROPY_INCLUDED_ESP8266_UART_H
+
+#include <eagle_soc.h>
+
+#define UART0 (0)
+#define UART1 (1)
+
+typedef enum {
+ UART_FIVE_BITS = 0x0,
+ UART_SIX_BITS = 0x1,
+ UART_SEVEN_BITS = 0x2,
+ UART_EIGHT_BITS = 0x3
+} UartBitsNum4Char;
+
+typedef enum {
+ UART_ONE_STOP_BIT = 0x1,
+ UART_ONE_HALF_STOP_BIT = 0x2,
+ UART_TWO_STOP_BIT = 0x3
+} UartStopBitsNum;
+
+typedef enum {
+ UART_NONE_BITS = 0,
+ UART_ODD_BITS = BIT0,
+ UART_EVEN_BITS = 0
+} UartParityMode;
+
+typedef enum {
+ UART_STICK_PARITY_DIS = 0,
+ UART_STICK_PARITY_EN = BIT1
+} UartExistParity;
+
+typedef enum {
+ UART_BIT_RATE_9600 = 9600,
+ UART_BIT_RATE_19200 = 19200,
+ UART_BIT_RATE_38400 = 38400,
+ UART_BIT_RATE_57600 = 57600,
+ UART_BIT_RATE_74880 = 74880,
+ UART_BIT_RATE_115200 = 115200,
+ UART_BIT_RATE_230400 = 230400,
+ UART_BIT_RATE_256000 = 256000,
+ UART_BIT_RATE_460800 = 460800,
+ UART_BIT_RATE_921600 = 921600
+} UartBautRate;
+
+typedef enum {
+ UART_NONE_CTRL,
+ UART_HARDWARE_CTRL,
+ UART_XON_XOFF_CTRL
+} UartFlowCtrl;
+
+typedef enum {
+ UART_EMPTY,
+ UART_UNDER_WRITE,
+ UART_WRITE_OVER
+} RcvMsgBuffState;
+
+typedef struct {
+ uint32 RcvBuffSize;
+ uint8 *pRcvMsgBuff;
+ uint8 *pWritePos;
+ uint8 *pReadPos;
+ uint8 TrigLvl; //JLU: may need to pad
+ RcvMsgBuffState BuffState;
+} RcvMsgBuff;
+
+typedef struct {
+ uint32 TrxBuffSize;
+ uint8 *pTrxBuff;
+} TrxMsgBuff;
+
+typedef enum {
+ UART_BAUD_RATE_DET,
+ UART_WAIT_SYNC_FRM,
+ UART_SRCH_MSG_HEAD,
+ UART_RCV_MSG_BODY,
+ UART_RCV_ESC_CHAR,
+} RcvMsgState;
+
+typedef struct {
+ UartBautRate baut_rate;
+ UartBitsNum4Char data_bits;
+ UartExistParity exist_parity;
+ UartParityMode parity; // chip size in byte
+ UartStopBitsNum stop_bits;
+ UartFlowCtrl flow_ctrl;
+ RcvMsgBuff rcv_buff;
+ TrxMsgBuff trx_buff;
+ RcvMsgState rcv_state;
+ int received;
+ int buff_uart_no; //indicate which uart use tx/rx buffer
+} UartDevice;
+
+void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
+int uart0_rx(void);
+bool uart_rx_wait(uint32_t timeout_us);
+int uart_rx_char(void);
+void uart_tx_one_char(uint8 uart, uint8 TxChar);
+void uart_flush(uint8 uart);
+void uart_os_config(int uart);
+void uart_setup(uint8 uart);
+// check status of rx/tx
+int uart_rx_any(uint8 uart);
+int uart_tx_any_room(uint8 uart);
+
+#endif // MICROPY_INCLUDED_ESP8266_UART_H
diff --git a/ports/esp8266/uart_register.h b/ports/esp8266/uart_register.h
new file mode 100644
index 000000000..6398879ee
--- /dev/null
+++ b/ports/esp8266/uart_register.h
@@ -0,0 +1,128 @@
+//Generated at 2012-07-03 18:44:06
+/*
+ * Copyright (c) 2010 - 2011 Espressif System
+ *
+ */
+
+#ifndef UART_REGISTER_H_INCLUDED
+#define UART_REGISTER_H_INCLUDED
+#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
+//version value:32'h062000
+
+#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
+#define UART_RXFIFO_RD_BYTE 0x000000FF
+#define UART_RXFIFO_RD_BYTE_S 0
+
+#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4)
+#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
+#define UART_BRK_DET_INT_RAW (BIT(7))
+#define UART_CTS_CHG_INT_RAW (BIT(6))
+#define UART_DSR_CHG_INT_RAW (BIT(5))
+#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
+#define UART_FRM_ERR_INT_RAW (BIT(3))
+#define UART_PARITY_ERR_INT_RAW (BIT(2))
+#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
+#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
+
+#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8)
+#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
+#define UART_BRK_DET_INT_ST (BIT(7))
+#define UART_CTS_CHG_INT_ST (BIT(6))
+#define UART_DSR_CHG_INT_ST (BIT(5))
+#define UART_RXFIFO_OVF_INT_ST (BIT(4))
+#define UART_FRM_ERR_INT_ST (BIT(3))
+#define UART_PARITY_ERR_INT_ST (BIT(2))
+#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
+#define UART_RXFIFO_FULL_INT_ST (BIT(0))
+
+#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC)
+#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
+#define UART_BRK_DET_INT_ENA (BIT(7))
+#define UART_CTS_CHG_INT_ENA (BIT(6))
+#define UART_DSR_CHG_INT_ENA (BIT(5))
+#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
+#define UART_FRM_ERR_INT_ENA (BIT(3))
+#define UART_PARITY_ERR_INT_ENA (BIT(2))
+#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
+#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
+
+#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10)
+#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
+#define UART_BRK_DET_INT_CLR (BIT(7))
+#define UART_CTS_CHG_INT_CLR (BIT(6))
+#define UART_DSR_CHG_INT_CLR (BIT(5))
+#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
+#define UART_FRM_ERR_INT_CLR (BIT(3))
+#define UART_PARITY_ERR_INT_CLR (BIT(2))
+#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
+#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
+
+#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14)
+#define UART_CLKDIV_CNT 0x000FFFFF
+#define UART_CLKDIV_S 0
+
+#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18)
+#define UART_GLITCH_FILT 0x000000FF
+#define UART_GLITCH_FILT_S 8
+#define UART_AUTOBAUD_EN (BIT(0))
+
+#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
+#define UART_TXD (BIT(31))
+#define UART_RTSN (BIT(30))
+#define UART_DTRN (BIT(29))
+#define UART_TXFIFO_CNT 0x000000FF
+#define UART_TXFIFO_CNT_S 16
+#define UART_RXD (BIT(15))
+#define UART_CTSN (BIT(14))
+#define UART_DSRN (BIT(13))
+#define UART_RXFIFO_CNT 0x000000FF
+#define UART_RXFIFO_CNT_S 0
+
+#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20)
+#define UART_TXFIFO_RST (BIT(18))
+#define UART_RXFIFO_RST (BIT(17))
+#define UART_IRDA_EN (BIT(16))
+#define UART_TX_FLOW_EN (BIT(15))
+#define UART_LOOPBACK (BIT(14))
+#define UART_IRDA_RX_INV (BIT(13))
+#define UART_IRDA_TX_INV (BIT(12))
+#define UART_IRDA_WCTL (BIT(11))
+#define UART_IRDA_TX_EN (BIT(10))
+#define UART_IRDA_DPLX (BIT(9))
+#define UART_TXD_BRK (BIT(8))
+#define UART_SW_DTR (BIT(7))
+#define UART_SW_RTS (BIT(6))
+#define UART_STOP_BIT_NUM 0x00000003
+#define UART_STOP_BIT_NUM_S 4
+#define UART_BIT_NUM 0x00000003
+#define UART_BIT_NUM_S 2
+#define UART_PARITY_EN (BIT(1))
+#define UART_PARITY (BIT(0))
+
+#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24)
+#define UART_RX_TOUT_EN (BIT(31))
+#define UART_RX_TOUT_THRHD 0x0000007F
+#define UART_RX_TOUT_THRHD_S 24
+#define UART_RX_FLOW_EN (BIT(23))
+#define UART_RX_FLOW_THRHD 0x0000007F
+#define UART_RX_FLOW_THRHD_S 16
+#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
+#define UART_TXFIFO_EMPTY_THRHD_S 8
+#define UART_RXFIFO_FULL_THRHD 0x0000007F
+#define UART_RXFIFO_FULL_THRHD_S 0
+
+#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28)
+#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
+#define UART_LOWPULSE_MIN_CNT_S 0
+
+#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C)
+#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
+#define UART_HIGHPULSE_MIN_CNT_S 0
+
+#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30)
+#define UART_PULSE_NUM_CNT 0x0003FF
+#define UART_PULSE_NUM_CNT_S 0
+
+#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78)
+#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C)
+#endif // UART_REGISTER_H_INCLUDED
diff --git a/ports/esp8266/user_config.h b/ports/esp8266/user_config.h
new file mode 100644
index 000000000..8b1a39374
--- /dev/null
+++ b/ports/esp8266/user_config.h
@@ -0,0 +1 @@
+// empty
diff --git a/ports/esp8266/xtirq.h b/ports/esp8266/xtirq.h
new file mode 100644
index 000000000..595052fc7
--- /dev/null
+++ b/ports/esp8266/xtirq.h
@@ -0,0 +1,59 @@
+/*
+ * 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