From 5b36f32996ff58da81d3c65e31f5349d498e09e4 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov <rojer@cesanta.com> Date: Tue, 24 Nov 2015 00:11:51 +0000 Subject: [PATCH] Add ESP8266 RTOS example PUBLISHED_FROM=892d01b09f5801d3d19e6db1ce22b7916d2f83d5 --- examples/ESP8266_RTOS/Makefile | 118 +++++++++++++++++ examples/ESP8266_RTOS/README.md | 26 ++++ examples/ESP8266_RTOS/gen_misc.sh | 173 +++++++++++++++++++++++++ examples/ESP8266_RTOS/readme.txt | 56 ++++++++ examples/ESP8266_RTOS/user/Makefile | 47 +++++++ examples/ESP8266_RTOS/user/esp_libc.c | 54 ++++++++ examples/ESP8266_RTOS/user/mongoose.c | 1 + examples/ESP8266_RTOS/user/mongoose.h | 1 + examples/ESP8266_RTOS/user/user_main.c | 108 +++++++++++++++ 9 files changed, 584 insertions(+) create mode 100644 examples/ESP8266_RTOS/Makefile create mode 100644 examples/ESP8266_RTOS/README.md create mode 100644 examples/ESP8266_RTOS/gen_misc.sh create mode 100644 examples/ESP8266_RTOS/readme.txt create mode 100644 examples/ESP8266_RTOS/user/Makefile create mode 100644 examples/ESP8266_RTOS/user/esp_libc.c create mode 120000 examples/ESP8266_RTOS/user/mongoose.c create mode 120000 examples/ESP8266_RTOS/user/mongoose.h create mode 100644 examples/ESP8266_RTOS/user/user_main.c diff --git a/examples/ESP8266_RTOS/Makefile b/examples/ESP8266_RTOS/Makefile new file mode 100644 index 000000000..0317ff878 --- /dev/null +++ b/examples/ESP8266_RTOS/Makefile @@ -0,0 +1,118 @@ +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of object file images to be generated () +# GEN_BINS - list of binaries to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +TARGET = eagle +#FLAVOR = release +FLAVOR = debug + +EXTRA_CCFLAGS += -Wall -Werror + +ifndef PDIR # { +GEN_IMAGES= eagle.app.v6.out +GEN_BINS= eagle.app.v6.bin +SPECIAL_MKTARGETS=$(APP_MKTARGETS) +SUBDIRS=user + +endif # } PDIR + +LDDIR = $(SDK_PATH)/ld + +CCFLAGS += -Os + +TARGET_LDFLAGS = \ + -nostdlib \ + -Wl,-EL \ + --longcalls \ + --text-section-literals + +ifeq ($(FLAVOR),debug) + TARGET_LDFLAGS += -g -O2 +endif + +ifeq ($(FLAVOR),release) + TARGET_LDFLAGS += -g -O0 +endif + +COMPONENTS_eagle.app.v6 = \ + user/libuser.a + +LINKFLAGS_eagle.app.v6 = \ + -L$(SDK_PATH)/lib \ + -Wl,--gc-sections \ + -nostdlib \ + -T$(LD_FILE) \ + -Wl,--no-check-sections \ + -u call_user_start \ + -Wl,-static \ + -Wl,--start-group \ + -lcirom \ + -lgcc \ + -lhal \ + -lphy \ + -lpp \ + -lnet80211 \ + -lwpa \ + -lcrypto \ + -lmain \ + -lfreertos \ + -llwip \ + $(DEP_LIBS_eagle.app.v6) \ + -Wl,--end-group + +DEPENDS_eagle.app.v6 = \ + $(LD_FILE) \ + $(LDDIR)/eagle.rom.addr.v6.ld + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# + +#UNIVERSAL_TARGET_DEFINES = \ + +# Other potential configuration flags include: +# -DTXRX_TXBUF_DEBUG +# -DTXRX_RXBUF_DEBUG +# -DWLAN_CONFIG_CCX +CONFIGURATION_DEFINES = -DICACHE_FLASH + +DEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + +DDEFINES += \ + $(UNIVERSAL_TARGET_DEFINES) \ + $(CONFIGURATION_DEFINES) + + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +sinclude $(SDK_PATH)/Makefile + +.PHONY: FORCE +FORCE: + diff --git a/examples/ESP8266_RTOS/README.md b/examples/ESP8266_RTOS/README.md new file mode 100644 index 000000000..f2a3c559c --- /dev/null +++ b/examples/ESP8266_RTOS/README.md @@ -0,0 +1,26 @@ +This is a Mongoose "Hello, world" that can be compiled under ESP8266 RTOS SDK. + +It sets up an AP (SSID `Mongoose`) and serves a "hello world" page on http://192.168.4.1/ + +Most of the the boilerplate comes from [project_template](https://github.com/espressif/ESP8266_RTOS_SDK/tree/master/examples/project_template) (@ [3ca6af5](https://github.com/espressif/ESP8266_RTOS_SDK/tree/3ca6af5da68678d809b34c7cd98bee71e0235039/examples/project_template)) with minimal changes. + +To build with no changes to the SDK, you will need a module with 1MB (8Mb) flash or more. + +Compile (for NodeMCU 1.0): + +``` +$ export SDK_PATH=/path/to/ESP8266_RTOS_SDK +$ export BIN_PATH=./bin +$ make clean; make BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=dio SPI_SIZE_MAP=6 +``` + +Flash (using [esptool](https://github.com/themadinventor/esptool)): + +``` +$ esptool.py --port /dev/ttyUSB0 --baud 230400 \ + write_flash --flash_mode=dio --flash_size=32m \ + 0x00000 ${SDK_PATH}/bin/boot_v1.4\(b1\).bin \ + 0x01000 ${BIN_PATH}/upgrade/user1.4096.new.6.bin +``` + +Note: the output can be made to fit in 512KB (4Mb) by moving `irom0_0_seg` in [eagle.app.v6.ld](https://github.com/espressif/ESP8266_RTOS_SDK/blob/master/ld/eagle.app.v6.ld) and increasing its size. diff --git a/examples/ESP8266_RTOS/gen_misc.sh b/examples/ESP8266_RTOS/gen_misc.sh new file mode 100644 index 000000000..7dcf6645c --- /dev/null +++ b/examples/ESP8266_RTOS/gen_misc.sh @@ -0,0 +1,173 @@ +#!/bin/bash + +:<<! +******NOTICE****** +MUST set SDK_PATH & BIN_PATH firstly!!! +example: +export SDK_PATH=~/ESP8266_RTOS_SDK +export BIN_PATH=~/esp8266_bin +! + +echo "gen_misc.sh version 20150911" +echo "" + +if [ $SDK_PATH ]; then + echo "SDK_PATH:" + echo "$SDK_PATH" + echo "" +else + echo "ERROR: Please export SDK_PATH in gen_misc.sh firstly, exit!!!" + exit +fi + +if [ $BIN_PATH ]; then + echo "BIN_PATH:" + echo "$BIN_PATH" + echo "" +else + echo "ERROR: Please export BIN_PATH in gen_misc.sh firstly, exit!!!" + exit +fi + +echo "Please check SDK_PATH & BIN_PATH, enter (Y/y) to continue:" +read input + +if [[ $input != Y ]] && [[ $input != y ]]; then + exit +fi + +echo "" + +echo "Please follow below steps(1-5) to generate specific bin(s):" +echo "STEP 1: use boot_v1.2+ by default" +boot=new + +echo "boot mode: $boot" +echo "" + +echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)" +echo "enter (0/1/2, default 0):" +read input + +if [ -z "$input" ]; then + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +elif [ $input == 1 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=1 + echo "generate bin: user1.bin" + fi +elif [ $input == 2 ]; then + if [ $boot == none ]; then + app=0 + echo "choose no boot before" + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" + else + app=2 + echo "generate bin: user2.bin" + fi +else + if [ $boot != none ]; then + boot=none + echo "ignore boot" + fi + app=0 + echo "generate bin: eagle.flash.bin+eagle.irom0text.bin" +fi + +echo "" + +echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)" +echo "enter (0/1/2/3, default 2):" +read input + +if [ -z "$input" ]; then + spi_speed=40 +elif [ $input == 0 ]; then + spi_speed=20 +elif [ $input == 1 ]; then + spi_speed=26.7 +elif [ $input == 3 ]; then + spi_speed=80 +else + spi_speed=40 +fi + +echo "spi speed: $spi_speed MHz" +echo "" + +echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)" +echo "enter (0/1/2/3, default 0):" +read input + +if [ -z "$input" ]; then + spi_mode=QIO +elif [ $input == 1 ]; then + spi_mode=QOUT +elif [ $input == 2 ]; then + spi_mode=DIO +elif [ $input == 3 ]; then + spi_mode=DOUT +else + spi_mode=QIO +fi + +echo "spi mode: $spi_mode" +echo "" + +echo "STEP 5: choose spi size and map" +echo " 0= 512KB( 256KB+ 256KB)" +echo " 2=1024KB( 512KB+ 512KB)" +echo " 3=2048KB( 512KB+ 512KB)" +echo " 4=4096KB( 512KB+ 512KB)" +echo " 5=2048KB(1024KB+1024KB)" +echo " 6=4096KB(1024KB+1024KB)" +echo "enter (0/2/3/4/5/6, default 0):" +read input + +if [ -z "$input" ]; then + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +elif [ $input == 2 ]; then + spi_size_map=2 + echo "spi size: 1024KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 3 ]; then + spi_size_map=3 + echo "spi size: 2048KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 4 ]; then + spi_size_map=4 + echo "spi size: 4096KB" + echo "spi ota map: 512KB + 512KB" +elif [ $input == 5 ]; then + spi_size_map=5 + echo "spi size: 2048KB" + echo "spi ota map: 1024KB + 1024KB" +elif [ $input == 6 ]; then + spi_size_map=6 + echo "spi size: 4096KB" + echo "spi ota map: 1024KB + 1024KB" +else + spi_size_map=0 + echo "spi size: 512KB" + echo "spi ota map: 256KB + 256KB" +fi + +echo "" + +echo "start..." +echo "" + +make clean + +make BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map diff --git a/examples/ESP8266_RTOS/readme.txt b/examples/ESP8266_RTOS/readme.txt new file mode 100644 index 000000000..3c7e7e718 --- /dev/null +++ b/examples/ESP8266_RTOS/readme.txt @@ -0,0 +1,56 @@ +This is a simple project template. + +sample_lib is an example for multi-level folder Makefile, notice the folder structure and each Makefile, you can get the clue. + + +HOWTO: +1. Copy this folder to anywhere. +Example: + Copy to ~/workspace/project_template + You can rename this folder as you like. + +2. Export SDK_PATH and BIN_PATH. +Example: + Your SDK path is ~/esp_iot_rtos_sdk, and want generate bin at ~/esp8266_bin. + Do follow steps: + 1>. export SDK_PATH=~/esp_iot_rtos_sdk + 2>. export BIN_PATH=~/esp8266_bin + SDK and project are seperate, you can update SDK without change your project. + +3. Enter project_template folder, run ./gen_misc.sh, and follow the tips and steps. + + +Compile Options: +(1) COMPILE + Possible value: xcc + Default value: + If not set, use gcc by default. + +(2) BOOT + Possible value: none/old/new + none: no need boot + old: use boot_v1.1 + new: use boot_v1.2 + Default value: new + +(3) APP + Possible value: 0/1/2 + 0: original mode, generate eagle.app.v6.flash.bin and eagle.app.v6.irom0text.bin + 1: generate user1 + 2: generate user2 + Default value: 0 + +(3) SPI_SPEED + Possible value: 20/26.7/40/80 + Default value: 40 + +(4) SPI_MODE + Possible value: QIO/QOUT/DIO/DOUT + Default value: QIO + +(4) SPI_SIZE_MAP + Possible value: 0/2/3/4/5/6 + Default value: 0 + +For example: + make COMPILE=gcc BOOT=new APP=1 SPI_SPEED=40 SPI_MODE=QIO SPI_SIZE_MAP=0 diff --git a/examples/ESP8266_RTOS/user/Makefile b/examples/ESP8266_RTOS/user/Makefile new file mode 100644 index 000000000..e005b7096 --- /dev/null +++ b/examples/ESP8266_RTOS/user/Makefile @@ -0,0 +1,47 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = libuser.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +DEFINES += -DMG_DISABLE_DAV -DMG_DISABLE_SYNC_RESOLVER -DMG_DISABLE_CGI \ + -DMG_DISABLE_SOCKETPAIR -DMG_DISABLE_DIRECTORY_LISTING \ + -DMG_MAX_HTTP_HEADERS=20 -DMG_MAX_HTTP_REQUEST_SIZE=1024 \ + -DMG_MAX_PATH=40 -DMG_MAX_HTTP_SEND_IOBUF=1024 \ + -DMG_ESP8266 -DRTOS_SDK -DMG_LWIP + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/examples/ESP8266_RTOS/user/esp_libc.c b/examples/ESP8266_RTOS/user/esp_libc.c new file mode 100644 index 000000000..a48893f0b --- /dev/null +++ b/examples/ESP8266_RTOS/user/esp_libc.c @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2015 Cesanta Software Limited +* All rights reserved +*/ + +#include <ctype.h> +#include <sys/time.h> +#include <stdint.h> + +#include <math.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "esp_common.h" + +/* Makes fprintf(stdout) and stderr work. */ +_ssize_t _write_r(struct _reent *r, int fd, void *buf, size_t len) { + if (fd == 1 || fd == 2) { + size_t i; + for (i = 0; i < len; i++) { + os_putc(((char *) buf)[i]); + } + return len; + } + return -1; +} + +/* + * You'll need to implement _open_r and friends if you want file operations. See + * https://github.com/cesanta/smart.js/blob/master/platforms/esp8266/user/esp_fs.c + * for SPIFFS-based implementation. + */ + +void abort(void) __attribute__((no_instrument_function)); +void abort(void) { + /* cause an unaligned access exception, that will drop you into gdb */ + *(int *) 1 = 1; + while (1) + ; /* avoid gcc warning because stdlib abort() has noreturn attribute */ +} + +void _exit(int status) { + printf("_exit(%d)\n", status); + abort(); +} + +int _gettimeofday_r(struct _reent *r, struct timeval *tp, void *tzp) { + uint32_t time = system_get_time(); + tp->tv_sec = time / 1000000; + tp->tv_usec = time % 1000000; + return 0; +} diff --git a/examples/ESP8266_RTOS/user/mongoose.c b/examples/ESP8266_RTOS/user/mongoose.c new file mode 120000 index 000000000..5e522bbcd --- /dev/null +++ b/examples/ESP8266_RTOS/user/mongoose.c @@ -0,0 +1 @@ +../../../mongoose.c \ No newline at end of file diff --git a/examples/ESP8266_RTOS/user/mongoose.h b/examples/ESP8266_RTOS/user/mongoose.h new file mode 120000 index 000000000..ee4ac8232 --- /dev/null +++ b/examples/ESP8266_RTOS/user/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file diff --git a/examples/ESP8266_RTOS/user/user_main.c b/examples/ESP8266_RTOS/user/user_main.c new file mode 100644 index 000000000..e52e4784b --- /dev/null +++ b/examples/ESP8266_RTOS/user/user_main.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ + +#include "esp_common.h" + +#include "mongoose.h" + +#define AP_SSID "Mongoose" +#define AP_PASS "Mongoose" +#define AP_CHAN 9 +#define MG_LISTEN_ADDR "80" + +#define MG_TASK_STACK_SIZE 2048 +#define MG_TASK_PRIORITY 1 + +void uart_div_modify(int uart_no, unsigned int freq); + +void ev_handler(struct mg_connection *nc, int ev, void *p) { + static const char *reply_fmt = + "HTTP/1.0 200 OK\r\n" + "Connection: close\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Hello %s\n"; + LOG(LL_DEBUG, ("conn %p ev %d", nc, ev)); + + switch (ev) { + case MG_EV_ACCEPT: { + char addr[32]; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), + MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); + LOG(LL_INFO, ("Connection %p from %s", nc, addr)); + break; + } + case MG_EV_HTTP_REQUEST: { + char addr[32]; + struct http_message *hm = (struct http_message *) p; + mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), + MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); + LOG(LL_INFO, + ("HTTP request from %s: %.*s %.*s", addr, (int) hm->method.len, + hm->method.p, (int) hm->uri.len, hm->uri.p)); + mg_printf(nc, reply_fmt, addr); + nc->flags |= MG_F_SEND_AND_CLOSE; + break; + } + case MG_EV_CLOSE: { + LOG(LL_INFO, ("Connection %p closed", nc)); + break; + } + } +} + +void setup_ap() { + struct softap_config cfg; + + wifi_set_opmode_current(SOFTAP_MODE); + memset(&cfg, 0, sizeof(cfg)); + strcpy((char *) cfg.ssid, AP_SSID); + strcpy((char *) cfg.password, AP_PASS); + cfg.ssid_len = strlen((const char *) cfg.ssid); + cfg.authmode = + strlen((const char *) cfg.password) ? AUTH_WPA2_PSK : AUTH_OPEN; + cfg.channel = AP_CHAN; + cfg.ssid_hidden = 0; + cfg.max_connection = 10; + cfg.beacon_interval = 100; /* ms */ + + LOG(LL_INFO, ("Setting up AP '%s' on channel %d", cfg.ssid, cfg.channel)); + wifi_softap_set_config_current(&cfg); +} + +static void mg_task(void *arg) { + struct mg_mgr mgr; + struct mg_connection *nc; + + cs_log_set_level(LL_INFO); + + LOG(LL_INFO, ("SDK version: %s", system_get_sdk_version())); + setup_ap(); + + mg_mgr_init(&mgr, NULL); + + nc = mg_bind(&mgr, MG_LISTEN_ADDR, ev_handler); + if (nc == NULL) { + LOG(LL_ERROR, ("Error setting up listener!")); + return; + } + mg_set_protocol_http_websocket(nc); + + while (1) { + mg_mgr_poll(&mgr, 1000); + } +} + +xTaskHandle s_mg_task_handle; + +void user_init(void) { + uart_div_modify(0, UART_CLK_FREQ / 115200); + + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + xTaskCreate(mg_task, (const signed char *) "mongoose", MG_TASK_STACK_SIZE, + NULL, MG_TASK_PRIORITY, &s_mg_task_handle); +} -- GitLab