Browse Source

init commit

curiousmuch 6 years ago
commit
542f63e5b4
65 changed files with 13901 additions and 0 deletions
  1. 249 0
      Makefile
  2. 44 0
      driver/Makefile
  3. 66 0
      driver/gpio16.c
  4. 155 0
      driver/hw_timer.c
  5. 330 0
      driver/i2c_master.c
  6. 176 0
      driver/key.c
  7. 457 0
      driver/sdio_slv.c
  8. 487 0
      driver/spi.c
  9. 502 0
      driver/spi_interface.c
  10. 422 0
      driver/spi_overlap.c
  11. 796 0
      driver/uart.c
  12. 42 0
      gdbstub/Makefile
  13. 785 0
      gdbstub/gdbstub.c
  14. 1565 0
      hal/lps25hb.c
  15. 364 0
      hal/lsm6ds3.c
  16. 175 0
      hal/max17043.c
  17. 164 0
      hal/ws2812.c
  18. 33 0
      include/driver/gpio16.h
  19. 93 0
      include/driver/i2c_master.h
  20. 51 0
      include/driver/key.h
  21. 40 0
      include/driver/sdio_slv.h
  22. 300 0
      include/driver/slc_register.h
  23. 74 0
      include/driver/spi.h
  24. 353 0
      include/driver/spi_interface.h
  25. 85 0
      include/driver/spi_overlap.h
  26. 222 0
      include/driver/spi_register.h
  27. 229 0
      include/driver/uart.h
  28. 159 0
      include/driver/uart_register.h
  29. 17 0
      include/esp_common.h
  30. 63 0
      include/gdbstub/gdbstub-cfg.h
  31. 25 0
      include/gdbstub/gdbstub-entry.h
  32. 14 0
      include/gdbstub/gdbstub.h
  33. 1309 0
      include/hal/lps25hb.h
  34. 269 0
      include/hal/lsm6ds3.h
  35. 58 0
      include/hal/max17043.h
  36. 35 0
      include/hal/ws2812.h
  37. 10 0
      include/interface/uart_interface.h
  38. 90 0
      include/log/esp_log.h
  39. 60 0
      include/user_config.h
  40. 57 0
      include/util/config.h
  41. 48 0
      include/util/ideasX.h
  42. 62 0
      include/util/wifi.h
  43. 61 0
      interface/uart_interface.c
  44. 42 0
      log/Makefile
  45. 31 0
      log/log.c
  46. 44 0
      mqtt/Makefile
  47. 19 0
      mqtt/include/debug.h
  48. 148 0
      mqtt/include/mqtt.h
  49. 141 0
      mqtt/include/mqtt_msg.h
  50. 32 0
      mqtt/include/proto.h
  51. 44 0
      mqtt/include/queue.h
  52. 19 0
      mqtt/include/ringbuf.h
  53. 17 0
      mqtt/include/typedef.h
  54. 9 0
      mqtt/include/utils.h
  55. 995 0
      mqtt/mqtt.c
  56. 487 0
      mqtt/mqtt_msg.c
  57. 129 0
      mqtt/proto.c
  58. 75 0
      mqtt/queue.c
  59. 67 0
      mqtt/ringbuf.c
  60. 149 0
      mqtt/utils.c
  61. 44 0
      user/Makefile
  62. 76 0
      user/rfinit.c
  63. 112 0
      user/user_main.c
  64. 140 0
      util/config.c
  65. 485 0
      util/wifi.c

+ 249 - 0
Makefile

@@ -0,0 +1,249 @@
+# none sdkota espboot rboot
+OTA ?= none
+OTA_APP_ADDR = 0x2000
+OTA_BOOTLOADER_PATH = ../esp-bootloader/firmware/espboot.bin
+
+THISDIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+# Base directory for the compiler. Needs a / at the end; if not set it'll use the tools that are in
+# the PATH.
+XTENSA_TOOLS_ROOT ?=
+
+# base directory of the ESP8266 SDK package, absolute
+SDK_BASE	?= /home/curiousmuch/ideasX-repositories/esp8266/esp-open-sdk/sdk
+
+#Esptool.py path and port
+ESPTOOL		?= /home/curiousmuch/ideasX-repositories/esp8266/esp-open-sdk/esptool/esptool.py
+ESPPORT		?= /dev/ttyUSB0
+#ESPPORT		?= /dev/tty.wchusbserial1410
+#ESPDELAY indicates seconds to wait between flashing the two binary images
+ESPDELAY	?= 3
+#ESPBAUD		?= 115200
+ESPBAUD		?= 460800
+
+# 40m 26m 20m 80m
+ESP_FREQ = 40m
+# qio qout dio dout
+ESP_MODE = dio
+#4m 2m 8m 16m 32m
+ESP_SIZE = 32m
+
+
+VERBOSE = yes
+FLAVOR = debug
+# name for the target project
+TARGET		?= ideasX_
+# name for the target when compiling as library
+TARGET_LIB ?= ideasX.a
+
+# which modules (subdirectories) of the project to include in compiling
+USER_MODULES		= user driver gdbstub log hal
+USER_INC				= include
+USER_LIB				=
+
+# which modules (subdirectories) of the project to include when compiling as library
+LIB_MODULES			= mqtt
+
+SDK_LIBDIR = lib
+SDK_LIBS = c gcc phy pp net80211 wpa main lwip crypto ssl json driver
+SDK_INC = include include/json
+
+
+
+# Output directors to store intermediate compiled files
+# relative to the project directory
+BUILD_BASE				= build
+FIRMWARE_BASE		= firmware
+
+# Opensdk patches stdint.h when compiled with an internal SDK. If you run into compile problems pertaining to
+# redefinition of int types, try setting this to 'yes'.
+USE_OPENSDK ?= yes
+
+DATETIME := $(shell date "+%Y-%b-%d_%H:%M:%S_%Z")
+
+# select which tools to use as compiler, librarian and linker
+CC		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
+AR		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar
+LD		:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
+OBJCOPY	:= $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
+
+
+
+####
+#### no user configurable options below here
+####
+SRC_DIR				:= $(USER_MODULES)
+SRC_DIR_LIB		:= $(LIB_MODULES)
+BUILD_DIR			:= $(addprefix $(BUILD_BASE)/,$(USER_MODULES))
+
+INCDIR	:= $(addprefix -I,$(SRC_DIR))
+EXTRA_INCDIR	:= $(addprefix -I,$(USER_INC))
+MODULE_INCDIR	:= $(addsuffix /include,$(INCDIR))
+
+SDK_LIBDIR	:= $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR))
+SDK_LIBS 		:= $(addprefix -l,$(SDK_LIBS))
+
+SDK_INCDIR	:= $(addprefix -I$(SDK_BASE)/,$(SDK_INC))
+
+SRC		:= $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c))
+SRC_LIB	:= $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.c))
+ASMSRC		= $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.S))
+ASMSRC_LIB = $(foreach sdir,$(SRC_DIR_LIB),$(wildcard $(sdir)/*.S))
+
+OBJ		= $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC))
+OBJ_LIB	= $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC_LIB))
+OBJ		+= $(patsubst %.S,$(BUILD_BASE)/%.o,$(ASMSRC))
+OBJ_LIB	+= $(patsubst %.c,$(BUILD_BASE)/%.o,$(ASMSRC_LIB))
+
+APP_AR		:= $(addprefix $(BUILD_BASE)/,$(TARGET).a)
+TARGET_OUT	:= $(addprefix $(BUILD_BASE)/,$(TARGET).out)
+
+
+
+# compiler flags using during compilation of source files
+CFLAGS		= -g			\
+						-Wpointer-arith		\
+						-Wundef			\
+						-Wl,-EL			\
+						-Wno-implicit-function-declaration \
+						-fno-inline-functions	\
+						-nostdlib       \
+						-mlongcalls	\
+						-mtext-section-literals \
+						-ffunction-sections \
+						-fdata-sections	\
+						-fno-builtin-printf\
+						-DICACHE_FLASH \
+						-DBUID_TIME=\"$(DATETIME)\"
+
+# linker flags used to generate the main object file
+LDFLAGS		= -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
+
+ifeq ($(FLAVOR),debug)
+    LDFLAGS += -g -O2
+    CFLAGS += -DMQTT_DEBUG_ON -DDEBUG_ON
+endif
+
+ifeq ($(FLAVOR),release)
+    LDFLAGS += -g -O0
+endif
+
+V ?= $(VERBOSE)
+ifeq ("$(V)","yes")
+Q :=
+vecho := @true
+else
+Q := @
+vecho := @echo
+endif
+
+ifeq ("$(USE_OPENSDK)","yes")
+CFLAGS		+= -DUSE_OPENSDK
+else
+CFLAGS		+= -D_STDINT_Hlocal
+endif
+
+ifneq ("$(wildcard $(THISDIR)/include/user_config.local.h)","")
+CFLAGS += -DLOCAL_CONFIG_AVAILABLE
+endif
+
+
+ESPTOOL_OPTS=--port $(ESPPORT) --baud $(ESPBAUD)
+
+#32m
+ESP_INIT_DATA_DEFAULT_ADDR = 0xfc000
+
+ifeq ("$(ESP_SIZE)","16m")
+	ESP_INIT_DATA_DEFAULT_ADDR = 0x1fc000
+else ifeq ("$(ESP_SIZE)","32m")
+	ESP_INIT_DATA_DEFAULT_ADDR = 0x3fc000
+endif
+
+ifeq ("$(OTA)","espboot")
+	OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET)-0x2000.bin)
+	ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
+									0x00000 $(OTA_BOOTLOADER_PATH) \
+									$(OTA_APP_ADDR) $(OUTPUT) \
+									$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
+
+	ESPTOOL_FLASHDEF=--version=2
+	LD_SCRIPT	= -Tld/with-espboot-flash-at-0x2000-size-1M.ld
+else
+	OUTPUT := $(addprefix $(FIRMWARE_BASE)/,$(TARGET))
+	ESPTOOL_WRITE = write_flash --flash_freq $(ESP_FREQ) --flash_mode $(ESP_MODE) --flash_size $(ESP_SIZE) \
+									0x00000 $(OUTPUT)0x00000.bin \
+									0x10000 $(OUTPUT)0x10000.bin \
+									$(ESP_INIT_DATA_DEFAULT_ADDR) $(SDK_BASE)/bin/esp_init_data_default.bin
+
+	ESPTOOL_FLASHDEF=
+	#LD_SCRIPT   = -T$(SDK_BASE)/ld/eagle.app.v6.new.2048.ld
+	LD_SCRIPT	= -T$(SDK_BASE)/ld/eagle.app.v6.ld
+endif
+OUTPUT_LIB := $(addprefix $(FIRMWARE_BASE)/,$(TARGET_LIB))
+
+
+vpath %.c $(SRC_DIR)
+
+define compile-objects
+$1/%.o: %.c
+	$(vecho) "CC $$<"
+	$(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS)  -c $$< -o $$@
+endef
+
+
+
+.PHONY: all lib checkdirs clean
+
+all: touch checkdirs $(OUTPUT)
+
+lib: checkdirs $(OUTPUT_LIB)
+
+touch:
+	$(vecho) "-------------------------------------------\n"
+	$(vecho) "BUID TIME $(DATETIME)"
+	$(vecho) "-------------------------------------------\n"
+	$(Q) touch user/user_main.c
+
+checkdirs: $(BUILD_DIR) $(FIRMWARE_BASE)
+
+$(OUTPUT): $(TARGET_OUT)
+	$(vecho) "FW $@"
+	$(Q) $(ESPTOOL) elf2image $(ESPTOOL_FLASHDEF) $< -o $(OUTPUT)
+
+$(OUTPUT_LIB): $(OBJ_LIB)
+	$(vecho) "AR $@"
+	$(Q) $(AR) cru $@ $^
+
+$(BUILD_DIR):
+	$(Q) mkdir -p $@
+
+$(FIRMWARE_BASE):
+	$(Q) mkdir -p $@
+
+$(TARGET_OUT): $(APP_AR)
+	$(vecho) "LD $@"
+	$(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(SDK_LIBS) $(APP_AR) -Wl,--end-group -o $@
+
+$(APP_AR): $(OBJ)
+	$(vecho) "AR $@"
+	$(Q) $(AR) cru $@ $^
+
+flash:
+	$(ESPTOOL) $(ESPTOOL_OPTS) $(ESPTOOL_WRITE)
+
+wipe:
+	$(ESPTOOL) $(ESPTOOL_OPTS) erase_flash
+
+fast: all flash openport
+
+openport:
+	$(vecho) "After flash, terminal will enter serial port screen"
+	$(vecho) "Please exit with command:"
+	$(vecho) "\033[0;31m" "Ctrl + A + k" "\033[0m"
+
+	#@read -p "Press any key to continue... " -n1 -s
+	@screen $(ESPPORT) 115200
+
+clean:
+	$(Q) rm -rf $(BUILD_DIR)
+	$(Q) rm -rf $(FIRMWARE_BASE)
+$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir))))

+ 44 - 0
driver/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# 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 = libdriver.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 += 
+
+#############################################################
+# 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
+INCLUDES += -I ./
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 66 - 0
driver/gpio16.c

@@ -0,0 +1,66 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "osapi.h"
+#include "driver/gpio16.h"
+
+void ICACHE_FLASH_ATTR
+gpio16_output_conf(void)
+{
+    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
+                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); 	// mux configuration for XPD_DCDC to output rtc_gpio0
+
+    WRITE_PERI_REG(RTC_GPIO_CONF,
+                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);	//mux configuration for out enable
+
+    WRITE_PERI_REG(RTC_GPIO_ENABLE,
+                   (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1);	//out enable
+}
+
+void ICACHE_FLASH_ATTR
+gpio16_output_set(uint8 value)
+{
+    WRITE_PERI_REG(RTC_GPIO_OUT,
+                   (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1));
+}
+
+void ICACHE_FLASH_ATTR
+gpio16_input_conf(void)
+{
+    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
+                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); 	// mux configuration for XPD_DCDC and rtc_gpio0 connection
+
+    WRITE_PERI_REG(RTC_GPIO_CONF,
+                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);	//mux configuration for out enable
+
+    WRITE_PERI_REG(RTC_GPIO_ENABLE,
+                   READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe);	//out disable
+}
+
+uint8 ICACHE_FLASH_ATTR
+gpio16_input_get(void)
+{
+    return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1);
+}

+ 155 - 0
driver/hw_timer.c

@@ -0,0 +1,155 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "os_type.h"
+#include "osapi.h"
+
+#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)
+
+#define FRC1_ENABLE_TIMER  BIT7
+#define FRC1_AUTO_LOAD  BIT6
+
+//TIMER PREDIVED MODE
+typedef enum {
+    DIVDED_BY_1 = 0,		//timer clock
+    DIVDED_BY_16 = 4,	//divided by 16
+    DIVDED_BY_256 = 8,	//divided by 256
+} TIMER_PREDIVED_MODE;
+
+typedef enum {			//timer interrupt mode
+    TM_LEVEL_INT = 1,	// level interrupt
+    TM_EDGE_INT   = 0,	//edge interrupt
+} TIMER_INT_MODE;
+
+typedef enum {
+    FRC1_SOURCE = 0,
+    NMI_SOURCE = 1,
+} FRC1_TIMER_SOURCE_TYPE;
+
+/******************************************************************************
+* FunctionName : hw_timer_arm
+* Description  : set a trigger timer delay for this timer.
+* Parameters   : uint32 val :
+in autoload mode
+                        50 ~ 0x7fffff;  for FRC1 source.
+                        100 ~ 0x7fffff;  for NMI source.
+in non autoload mode:
+                        10 ~ 0x7fffff;
+* Returns      : NONE
+*******************************************************************************/
+void  hw_timer_arm(u32 val)
+{
+    RTC_REG_WRITE(FRC1_LOAD_ADDRESS, US_TO_RTC_TIMER_TICKS(val));
+}
+
+static void (* user_hw_timer_cb)(void) = NULL;
+/******************************************************************************
+* FunctionName : hw_timer_set_func
+* Description  : set the func, when trigger timer is up.
+* Parameters   : void (* user_hw_timer_cb_set)(void):
+                        timer callback function,
+* Returns      : NONE
+*******************************************************************************/
+void  hw_timer_set_func(void (* user_hw_timer_cb_set)(void))
+{
+    user_hw_timer_cb = user_hw_timer_cb_set;
+}
+
+static void  hw_timer_isr_cb(void)
+{
+    if (user_hw_timer_cb != NULL) {
+        (*(user_hw_timer_cb))();
+    }
+}
+
+/******************************************************************************
+* FunctionName : hw_timer_init
+* Description  : initilize the hardware isr timer
+* Parameters   :
+FRC1_TIMER_SOURCE_TYPE source_type:
+                        FRC1_SOURCE,    timer use frc1 isr as isr source.
+                        NMI_SOURCE,     timer use nmi isr as isr source.
+u8 req:
+                        0,  not autoload,
+                        1,  autoload mode,
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR hw_timer_init(FRC1_TIMER_SOURCE_TYPE source_type, u8 req)
+{
+    if (req == 1) {
+        RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
+                      FRC1_AUTO_LOAD | DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
+    } else {
+        RTC_REG_WRITE(FRC1_CTRL_ADDRESS,
+                      DIVDED_BY_16 | FRC1_ENABLE_TIMER | TM_EDGE_INT);
+    }
+
+    if (source_type == NMI_SOURCE) {
+        ETS_FRC_TIMER1_NMI_INTR_ATTACH(hw_timer_isr_cb);
+    } else {
+        ETS_FRC_TIMER1_INTR_ATTACH(hw_timer_isr_cb, NULL);
+    }
+
+    TM1_EDGE_INT_ENABLE();
+    ETS_FRC1_INTR_ENABLE();
+}
+
+//-------------------------------Test Code Below--------------------------------------
+#if 0
+void   hw_test_timer_cb(void)
+{
+    static uint16 j = 0;
+    j++;
+
+    if ((WDEV_NOW() - tick_now2) >= 1000000) {
+        static u32 idx = 1;
+        tick_now2 = WDEV_NOW();
+        os_printf("b%u:%d\n", idx++, j);
+        j = 0;
+    }
+
+    //hw_timer_arm(50);
+}
+
+void ICACHE_FLASH_ATTR user_init(void)
+{
+    hw_timer_init(FRC1_SOURCE, 1);
+    hw_timer_set_func(hw_test_timer_cb);
+    hw_timer_arm(100);
+}
+#endif
+/*
+NOTE:
+1 if use nmi source, for autoload timer , the timer setting val can't be less than 100.
+2 if use nmi source, this timer has highest priority, can interrupt other isr.
+3 if use frc1 source, this timer can't interrupt other isr.
+
+*/
+

+ 330 - 0
driver/i2c_master.c

@@ -0,0 +1,330 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "osapi.h"
+#include "gpio.h"
+
+#include "driver/i2c_master.h"
+
+LOCAL uint8 m_nLastSDA;
+LOCAL uint8 m_nLastSCL;
+
+/******************************************************************************
+ * FunctionName : i2c_master_setDC
+ * Description  : Internal used function -
+ *                    set i2c SDA and SCL bit value for half clk cycle
+ * Parameters   : uint8 SDA
+ *                uint8 SCL
+ * Returns      : NONE
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+i2c_master_setDC(uint8 SDA, uint8 SCL)
+{
+    SDA	&= 0x01;
+    SCL	&= 0x01;
+    m_nLastSDA = SDA;
+    m_nLastSCL = SCL;
+
+    if ((0 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_LOW();
+    } else if ((0 == SDA) && (1 == SCL)) {
+        I2C_MASTER_SDA_LOW_SCL_HIGH();
+    } else if ((1 == SDA) && (0 == SCL)) {
+        I2C_MASTER_SDA_HIGH_SCL_LOW();
+    } else {
+        I2C_MASTER_SDA_HIGH_SCL_HIGH();
+    }
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getDC
+ * Description  : Internal used function -
+ *                    get i2c SDA bit value
+ * Parameters   : NONE
+ * Returns      : uint8 - SDA bit value
+*******************************************************************************/
+LOCAL uint8 ICACHE_FLASH_ATTR
+i2c_master_getDC(void)
+{
+    uint8 sda_out;
+    sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
+    return sda_out;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_init
+ * Description  : initilize I2C bus to enable i2c operations
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_init(void)
+{
+    uint8 i;
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+
+    // when SCL = 0, toggle SDA to clear up
+    i2c_master_setDC(0, 0) ;
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0) ;
+    i2c_master_wait(5);
+
+    // set data_cnt to max value
+    for (i = 0; i < 28; i++) {
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5);	// sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5);	// sda 1, scl 1
+    }
+
+    // reset all
+    i2c_master_stop();
+    return;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_gpio_init
+ * Description  : config SDA and SCL gpio to open-drain output mode,
+ *                mux and gpio num defined in i2c_master.h
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_gpio_init(void)
+{
+    ETS_GPIO_INTR_DISABLE() ;
+//    ETS_INTR_LOCK();
+
+    PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
+    PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);
+
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO));
+    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
+    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO));
+
+    I2C_MASTER_SDA_HIGH_SCL_HIGH();
+
+    ETS_GPIO_INTR_ENABLE() ;
+//    ETS_INTR_UNLOCK();
+
+    i2c_master_init();
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_start
+ * Description  : set i2c to send state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_start(void)
+{
+    i2c_master_setDC(1, m_nLastSCL);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);	// sda 1, scl 1
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5);	// sda 0, scl 1
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_stop
+ * Description  : set i2c to stop sending state
+ * Parameters   : NONE
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_stop(void)
+{
+    i2c_master_wait(5);
+
+    i2c_master_setDC(0, m_nLastSCL);
+    i2c_master_wait(5);	// sda 0
+    i2c_master_setDC(0, 1);
+    i2c_master_wait(5);	// sda 0, scl 1
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);	// sda 1, scl 1
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_setAck
+ * Description  : set ack to i2c bus as level value
+ * Parameters   : uint8 level - 0 or 1
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_setAck(uint8 level)
+{
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5);	// sda level, scl 0
+    i2c_master_setDC(level, 1);
+    i2c_master_wait(8);	// sda level, scl 1
+    i2c_master_setDC(level, 0);
+    i2c_master_wait(5);	// sda level, scl 0
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_getAck
+ * Description  : confirm if peer send ack
+ * Parameters   : NONE
+ * Returns      : uint8 - ack value, 0 or 1
+*******************************************************************************/
+uint8 ICACHE_FLASH_ATTR
+i2c_master_getAck(void)
+{
+    uint8 retVal;
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 1);
+    i2c_master_wait(5);
+
+    retVal = i2c_master_getDC();
+    i2c_master_wait(5);
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);
+
+    return retVal;
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_checkAck
+* Description  : get dev response
+* Parameters   : NONE
+* Returns      : true : get ack ; false : get nack
+*******************************************************************************/
+bool ICACHE_FLASH_ATTR
+i2c_master_checkAck(void)
+{
+    if(i2c_master_getAck()){
+        return FALSE;
+    }else{
+        return TRUE;
+    }
+}
+
+/******************************************************************************
+* FunctionName : i2c_master_send_ack
+* Description  : response ack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_ack(void)
+{
+    i2c_master_setAck(0x0);
+}
+/******************************************************************************
+* FunctionName : i2c_master_send_nack
+* Description  : response nack
+* Parameters   : NONE
+* Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_send_nack(void)
+{
+    i2c_master_setAck(0x1);
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_readByte
+ * Description  : read Byte from i2c bus
+ * Parameters   : NONE
+ * Returns      : uint8 - readed value
+*******************************************************************************/
+uint8 ICACHE_FLASH_ATTR
+i2c_master_readByte(void)
+{
+    uint8 retVal = 0;
+    uint8 k, i;
+
+    i2c_master_wait(5);
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);	// sda 1, scl 0
+
+    for (i = 0; i < 8; i++) {
+        i2c_master_wait(5);
+        i2c_master_setDC(1, 0);
+        i2c_master_wait(5);	// sda 1, scl 0
+        i2c_master_setDC(1, 1);
+        i2c_master_wait(5);	// sda 1, scl 1
+
+        k = i2c_master_getDC();
+        i2c_master_wait(5);
+
+        if (i == 7) {
+            i2c_master_wait(3);   ////
+        }
+
+        k <<= (7 - i);
+        retVal |= k;
+    }
+
+    i2c_master_setDC(1, 0);
+    i2c_master_wait(5);	// sda 1, scl 0
+
+    return retVal;
+}
+
+/******************************************************************************
+ * FunctionName : i2c_master_writeByte
+ * Description  : write wrdata value(one byte) into i2c
+ * Parameters   : uint8 wrdata - write value
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+i2c_master_writeByte(uint8 wrdata)
+{
+    uint8 dat;
+    sint8 i;
+
+    i2c_master_wait(5);
+
+    i2c_master_setDC(m_nLastSDA, 0);
+    i2c_master_wait(5);
+
+    for (i = 7; i >= 0; i--) {
+        dat = wrdata >> i;
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+        i2c_master_setDC(dat, 1);
+        i2c_master_wait(5);
+
+        if (i == 0) {
+            i2c_master_wait(3);   ////
+        }
+
+        i2c_master_setDC(dat, 0);
+        i2c_master_wait(5);
+    }
+}

+ 176 - 0
driver/key.c

@@ -0,0 +1,176 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "os_type.h"
+#include "osapi.h"
+#include "mem.h"
+#include "gpio.h"
+#include "user_interface.h"
+
+#include "driver/key.h"
+
+LOCAL void key_intr_handler(struct keys_param *keys);
+
+/******************************************************************************
+ * FunctionName : key_init_single
+ * Description  : init single key's gpio and register function
+ * Parameters   : uint8 gpio_id - which gpio to use
+ *                uint32 gpio_name - gpio mux name
+ *                uint32 gpio_func - gpio function
+ *                key_function long_press - long press function, needed to install
+ *                key_function short_press - short press function, needed to install
+ * Returns      : single_key_param - single key parameter, needed by key init
+*******************************************************************************/
+struct single_key_param *ICACHE_FLASH_ATTR
+key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press)
+{
+    struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param));
+
+    single_key->gpio_id = gpio_id;
+    single_key->gpio_name = gpio_name;
+    single_key->gpio_func = gpio_func;
+    single_key->long_press = long_press;
+    single_key->short_press = short_press;
+
+    return single_key;
+}
+
+/******************************************************************************
+ * FunctionName : key_init
+ * Description  : init keys
+ * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
+ * Returns      : none
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+key_init(struct keys_param *keys)
+{
+    uint8 i;
+
+    ETS_GPIO_INTR_ATTACH(key_intr_handler, keys);
+
+    ETS_GPIO_INTR_DISABLE();
+
+    for (i = 0; i < keys->key_num; i++) {
+        keys->single_key[i]->key_level = 1;
+
+        PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func);
+
+        gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id));
+
+        gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)
+                          | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)
+                          | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
+
+        //clear gpio14 status
+        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id));
+
+        //enable interrupt
+        gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);
+    }
+
+    ETS_GPIO_INTR_ENABLE();
+}
+
+/******************************************************************************
+ * FunctionName : key_5s_cb
+ * Description  : long press 5s timer callback
+ * Parameters   : single_key_param *single_key - single key parameter
+ * Returns      : none
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+key_5s_cb(struct single_key_param *single_key)
+{
+    os_timer_disarm(&single_key->key_5s);
+
+    // low, then restart
+    if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
+        if (single_key->long_press) {
+            single_key->long_press();
+        }
+    }
+}
+
+/******************************************************************************
+ * FunctionName : key_50ms_cb
+ * Description  : 50ms timer callback to check it's a real key push
+ * Parameters   : single_key_param *single_key - single key parameter
+ * Returns      : none
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+key_50ms_cb(struct single_key_param *single_key)
+{
+    os_timer_disarm(&single_key->key_50ms);
+
+    // high, then key is up
+    if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {
+        os_timer_disarm(&single_key->key_5s);
+        single_key->key_level = 1;
+        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE);
+
+        if (single_key->short_press) {
+            single_key->short_press();
+        }
+    } else {
+        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE);
+    }
+}
+
+/******************************************************************************
+ * FunctionName : key_intr_handler
+ * Description  : key interrupt handler
+ * Parameters   : key_param *keys - keys parameter, which inited by key_init_single
+ * Returns      : none
+*******************************************************************************/
+LOCAL void
+key_intr_handler(struct keys_param *keys)
+{
+    uint8 i;
+    uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
+
+    for (i = 0; i < keys->key_num; i++) {
+        if (gpio_status & BIT(keys->single_key[i]->gpio_id)) {
+            //disable interrupt
+            gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE);
+
+            //clear interrupt status
+            GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id));
+
+            if (keys->single_key[i]->key_level == 1) {
+                // 5s, restart & enter softap mode
+                os_timer_disarm(&keys->single_key[i]->key_5s);
+                os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);
+                os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);
+                keys->single_key[i]->key_level = 0;
+                gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);
+            } else {
+                // 50ms, check if this is a real key up
+                os_timer_disarm(&keys->single_key[i]->key_50ms);
+                os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);
+                os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);
+            }
+        }
+    }
+}
+

+ 457 - 0
driver/sdio_slv.c

@@ -0,0 +1,457 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "driver/slc_register.h"
+#include "driver/sdio_slv.h"
+#include "ets_sys.h"
+#include "osapi.h"
+#include "os_type.h"
+//#include "gpio.h"
+#include "user_interface.h"
+#include "mem.h"
+
+#define SDIO_TOKEN_SIZE		0//4
+#define RX_BUFFER_SIZE      512
+#define RX_BUFFER_NUM       4
+
+#define TX_BUFFER_SIZE		512
+#define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA)
+#define TRIG_TOHOST_INT()	SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\
+							//CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0)
+struct sdio_queue
+{
+	uint32	blocksize:12;
+	uint32	datalen:12;
+	uint32	unused:5;
+	uint32	sub_sof:1;
+	uint32 	eof:1;
+	uint32	owner:1;
+
+	uint32	buf_ptr;
+	uint32	next_link_ptr;
+};
+
+struct sdio_slave_status_element
+{
+	uint32 wr_busy:1;
+	uint32 rd_empty :1;
+	uint32 comm_cnt :3;
+	uint32 intr_no :3;
+	uint32 rx_length:16;
+	uint32 res:8;
+};
+
+union sdio_slave_status
+{
+	struct sdio_slave_status_element elm_value;
+	uint32 word_value;
+};
+
+//uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024];
+uint8 tx_buffer[TX_BUFFER_SIZE];
+
+uint32 data_len = 0;
+
+struct sdio_list {
+	uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE];
+	uint8* tail;
+	struct sdio_list* next;
+};
+
+static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL;
+struct sdio_list* pHead_ToSend;
+struct sdio_list* pTail_ToSend;
+struct sdio_list* pHead_Sended;
+struct sdio_list* pTail_Sended;
+
+
+
+os_event_t * sdioQueue;
+struct sdio_queue rx_que,tx_que;
+
+static bool has_read = 0;
+
+static void sdio_slave_isr(void *para);
+static void tx_buff_handle_done(void);
+static void rx_buff_read_done(void);
+static void tx_buff_write_done(void);
+
+static void sdio_try_to_load(void);
+static void sdio_read_done_process(void);
+
+void sdio_slave_init(void)
+{
+    uint32 regval = 0;
+    union sdio_slave_status sdio_sta;
+    ETS_SDIO_INTR_DISABLE();
+    ////reset orginal link
+    SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
+    CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
+
+    os_printf("RX&TX link reset!\n");
+
+    //set sdio mode
+    SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
+    //clear to host interrupt io signal for preventing from random initial signal.
+    WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff);
+    //enable 2 events to trigger the to host intr io
+    SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA);
+    ////initialize rx queue information
+
+    has_read = TRUE;
+	pHead_ToSend = NULL;
+
+	int loop = RX_BUFFER_NUM;
+	struct sdio_list* p = NULL;
+	while(loop--) {
+		if(pHead_Sended == NULL) {
+			pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
+			p = pHead_Sended;
+		} else {
+			p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
+			p = p->next;
+		}
+		//os_printf("p:0x%08x\r\n",p);
+		p->tail = p->buffer + SDIO_TOKEN_SIZE;
+		p->next = NULL;
+	}
+	pTail_Sended = p;
+	
+    rx_que.blocksize = RX_BUFFER_SIZE;
+    rx_que.datalen=0;
+    rx_que.eof=1;
+    rx_que.owner=1;
+    rx_que.sub_sof=0;
+    rx_que.unused=0;
+    rx_que.buf_ptr=(uint32)pHead_Sended->buffer;
+    rx_que.next_link_ptr=0;
+
+
+    ////initialize tx queue information
+    tx_que.blocksize=TX_BUFFER_SIZE;
+    tx_que.datalen=0;
+    tx_que.eof=0;
+    tx_que.owner=1;
+    tx_que.sub_sof=0;
+    tx_que.unused=0;
+    tx_que.buf_ptr=(uint32)tx_buffer;
+    tx_que.next_link_ptr=0;
+
+    ///////link tx&rx queue information address to sdio hardware
+    CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
+    regval= ((uint32)&rx_que);
+    SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK);
+    CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK);
+    regval= ((uint32)&tx_que);
+    SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK);
+
+#if (SDIO_TOKEN_SIZE == 0)
+    SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE);
+#endif
+
+    /////config sdio_status reg
+    sdio_sta.elm_value.comm_cnt=7;
+    sdio_sta.elm_value.intr_no=INIT_STAGE;
+    sdio_sta.elm_value.wr_busy=0;
+    sdio_sta.elm_value.rd_empty=1;
+    sdio_sta.elm_value.rx_length=0;
+    sdio_sta.elm_value.res=0;
+    SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);
+
+
+    /////attach isr func to sdio interrupt
+    ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL);
+    /////enable sdio operation intr
+    WRITE_PERI_REG(SLC_INT_ENA,  SLC_INTEREST_EVENT);
+    /////clear sdio initial random active intr signal
+    WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
+    /////enable sdio intr in cpu
+    ETS_SDIO_INTR_ENABLE();
+}
+
+static void sdio_slave_isr(void *para)
+{
+    uint32 slc_intr_status,postval;
+    static uint8 state =0;
+    uint16 rx_len,i;
+    uint32* pword;
+    union sdio_slave_status sdio_sta;
+
+    slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
+
+    if (slc_intr_status == 0)
+    {
+        /* No interested interrupts pending */
+        return;
+    }
+    //clear all intrs
+    WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
+    //os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
+    //process every intr
+
+    //TO HOST DONE
+    if (slc_intr_status & SLC_RX_EOF_INT_ENA)
+    {
+        //following code must be called after a data pack has been read
+        rx_buff_read_done();
+        //TRIG_TOHOST_INT();
+        //system_os_post(2, 1, 0);
+		sdio_read_done_process();
+    }
+
+    //FROM HOST DONE
+    if (slc_intr_status & SLC_TX_EOF_INT_ENA)
+    {
+        //call the following function after host cpu data transmission finished
+        tx_buff_write_done();
+
+        //system_os_post(USER_TASK_PRIO_1,SDIO_DATA_ERROR,0);
+        //os_printf("%d,%s\r\n",tx_que.datalen,tx_que.buf_ptr);
+        //at_fake_uart_rx((uint8*)tx_que.buf_ptr,tx_que.datalen);
+		if(sdio_recv_data_callback_ptr) {
+			sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen);
+		}
+        tx_buff_handle_done();
+        TRIG_TOHOST_INT();
+		//system_os_post(2, 3, 0);
+    }
+
+    //TO HOST underflow
+    if(slc_intr_status & SLC_RX_UDF_INT_ENA)
+    {
+    }
+
+    //FROM HOST overflow
+    if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA)
+    {
+    }
+
+    slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
+    if(slc_intr_status)
+    {
+        WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
+        os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
+    }
+
+}
+
+static void rx_buff_read_done(void)
+{
+    union sdio_slave_status sdio_sta;
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.comm_cnt++;
+    sdio_sta.elm_value.rd_empty=1;
+    sdio_sta.elm_value.rx_length=0;
+    sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //os_printf("rx_buff_read_done\r\n");
+}
+
+static void tx_buff_write_done(void)
+{
+    union sdio_slave_status sdio_sta;
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.comm_cnt++;
+    sdio_sta.elm_value.wr_busy=1;
+	sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE);
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+}
+
+static void tx_buff_handle_done(void)
+{
+    union sdio_slave_status sdio_sta;
+
+    /////config tx queue information
+    tx_que.blocksize=TX_BUFFER_SIZE;
+    tx_que.datalen=0;
+    tx_que.eof=0;
+    tx_que.owner=1;
+
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.wr_busy=0;
+    sdio_sta.elm_value.intr_no |= TX_AVAILIBLE;
+
+    SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);       //tx buffer is ready for being written
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //*******************************************************************//
+
+}
+static int32 rx_buff_load_done(uint16 rx_len)
+{
+    union sdio_slave_status sdio_sta;
+
+	if(rx_len == 0) {
+		return 0;
+	}
+    if(rx_len > rx_que.blocksize)
+    {
+        rx_len = rx_que.blocksize;
+    }
+
+    //os_memcpy(rx_que.buf_ptr,data,rx_len);
+    /////config rx queue information
+    rx_que.blocksize=RX_BUFFER_SIZE;
+    rx_que.datalen=rx_len + SDIO_TOKEN_SIZE;
+    rx_que.eof=1;
+    rx_que.owner=1;
+
+    //ETS_SDIO_INTR_DISABLE();
+    //available_buffer_amount--;
+
+    /////modify sdio status reg
+    sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
+    sdio_sta.elm_value.rd_empty=0;
+    sdio_sta.elm_value.intr_no |= RX_AVAILIBLE;
+    sdio_sta.elm_value.rx_length=rx_len;
+
+    SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);       //rx buffer is ready for being read
+    WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);  //update sdio status register
+    //ETS_SDIO_INTR_ENABLE();
+    //os_printf("rx_buff_load_done(%d,0x%08x):%s\r\n",rx_len,rx_que.buf_ptr,rx_que.buf_ptr);
+    //os_printf("rx_buff_load_done:%d\r\n",rx_len);
+    return rx_len;
+}
+
+int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len)
+{
+    int32 data_len = 0;
+
+	if (pHead_Sended == NULL) {
+		os_printf("no buf\r\n");
+		return 0;
+	}
+    int32 left_len = 0;
+    
+    while(len)
+    {
+		left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(pHead_Sended->tail - pHead_Sended->buffer);
+        if(len < left_len)
+        {
+            os_memcpy(pHead_Sended->tail,data,len);
+			pHead_Sended->tail += len;
+			len = 0;
+			data_len += len;
+            //os_printf(">555:0x%08x,0x%08x\r\n",pHead_Sended->buffer,pHead_Sended->tail);
+        }
+        else
+        {
+            os_memcpy(pHead_Sended->tail,data,left_len);
+			pHead_Sended->tail += left_len;
+			len -= left_len;
+			data += left_len;
+			data_len += left_len;
+			if(pHead_ToSend == NULL) {
+				pTail_ToSend = pHead_Sended;
+				pHead_ToSend = pTail_ToSend;
+			} else {
+				pTail_ToSend->next = pHead_Sended;
+				pTail_ToSend = pTail_ToSend->next;
+			}
+			pHead_Sended = pHead_Sended->next;
+			
+			pTail_ToSend->next = NULL;
+            if(pHead_Sended == NULL)
+            {
+                os_printf("buf full\r\n");
+                break;
+            }
+            //os_printf(">666\r\n");
+        }
+    }
+
+	//os_printf(">>pHead_ToSend:0x%08x\r\n",pHead_ToSend);
+	
+	if(pHead_ToSend == NULL) {
+		pTail_ToSend = pHead_Sended;
+		pHead_ToSend = pTail_ToSend;
+
+		pHead_Sended = pHead_Sended->next;
+		pTail_ToSend->next = NULL;
+		//system_os_post(2, 2, 0);
+		sdio_try_to_load();
+	}
+    return data_len;
+}
+
+static void sdio_try_to_load(void)
+{
+	if((has_read == TRUE) && (pHead_ToSend != NULL))
+        {
+            rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
+            rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+			//pHead_ToSend = pHead_ToSend->next;
+            has_read = FALSE;
+            //os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS));
+            TRIG_TOHOST_INT();
+        }
+}
+
+static void sdio_read_done_process(void)
+{
+	has_read = TRUE;
+		
+	pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE;
+	if(pHead_Sended) {
+       	pTail_Sended->next = pHead_ToSend;
+		pTail_Sended = pTail_Sended->next;
+	}else {
+		pTail_Sended = pHead_ToSend;
+		pHead_Sended = pTail_Sended;
+	}
+	pHead_ToSend = pHead_ToSend->next;
+	pTail_Sended->next = NULL;
+	//os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail);
+	if(pHead_ToSend) {
+		rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
+           rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+		has_read = FALSE;
+		//os_printf("intr trig\r\n");
+		//TRIG_TOHOST_INT();
+	} else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) {
+		pHead_ToSend = pHead_Sended;
+		pTail_ToSend = pHead_ToSend;
+		pHead_Sended = pHead_Sended->next;
+		pTail_ToSend->next = NULL;
+			
+		rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;			
+        rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
+		has_read = FALSE;
+		//os_printf("intr trig\r\n");
+		//TRIG_TOHOST_INT();
+	}
+
+	TRIG_TOHOST_INT();
+}
+
+bool sdio_register_recv_cb(sdio_recv_data_callback_t cb)
+{
+	sdio_recv_data_callback_ptr = cb;
+	
+	return TRUE;
+}
+

+ 487 - 0
driver/spi.c

@@ -0,0 +1,487 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "driver/spi.h"
+#include "driver/spi_overlap.h"
+
+#define CACHE_FLASH_CTRL_REG 0x3ff0000C
+#define CACHE_FLUSH_START_BIT BIT0
+#define CACHE_EMPTY_FLAG_BIT BIT1
+/******************************************************************************
+ * FunctionName : cache_flush
+ * Description  : clear all the cpu cache data for stability test.
+*******************************************************************************/
+void cache_flush(void)
+{
+   while(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT) {
+      CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+      SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+   }
+   while(!(READ_PERI_REG(CACHE_FLASH_CTRL_REG)&CACHE_EMPTY_FLAG_BIT));
+   	
+   CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG, CACHE_FLUSH_START_BIT);
+}
+/******************************************************************************
+ * FunctionName : spi_master_init
+ * Description  : SPI master initial function for common byte units transmission
+ * Parameters   : uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_master_init(uint8 spi_no)
+{
+	uint32 regvalue; 
+
+	if(spi_no>1) 		return; //handle invalid input number
+	
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
+
+	WRITE_PERI_REG(SPI_CLOCK(spi_no), 
+					((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
+					((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
+					((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+}
+/******************************************************************************
+ * FunctionName : spi_lcd_9bit_write
+ * Description  : SPI 9bits transmission function for driving LCD TM035PDZV36
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 high_bit - first high bit of the data, 0 is for "0",the other value 1-255 is for "1"
+ *				uint8 low_8bit- the rest 8bits of the data.
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)
+{
+	uint32 regvalue;
+	uint8 bytetemp;
+	if(spi_no>1) 		return; //handle invalid input number
+	
+	if(high_bit)		bytetemp=(low_8bit>>1)|0x80;
+	else				bytetemp=(low_8bit>>1)&0x7f;
+	
+	regvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp);		//configure transmission variable,9bit transmission length and first 8 command bit 
+	if(low_8bit&0x01) 	regvalue|=BIT15;        //write the 9th bit
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);		//waiting for spi module available
+	WRITE_PERI_REG(SPI_USER2(spi_no), regvalue);				//write  command and command length into spi reg
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);		//transmission start
+//	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);	
+}
+/******************************************************************************
+ * FunctionName : spi_mast_byte_write
+ * Description  : SPI master 1 byte transmission function
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data- transmitted data
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_mast_byte_write(uint8 spi_no,uint8 data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_MISO);
+
+	//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)data));
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);	
+ }  
+
+/******************************************************************************
+ * FunctionName : spi_byte_write_espslave
+ * Description  : SPI master 1 byte transmission function for esp8266 slave,
+ * 			transmit 1byte data to esp8266 slave buffer needs 16bit transmission ,
+ * 			first byte is command 0x04 to write slave buffer, second byte is data
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data- transmitted data
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_byte_write_espslave(uint8 spi_no,uint8 data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY);
+
+	//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	//0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|4);
+	WRITE_PERI_REG(SPI_W0(spi_no), (uint32)(data));
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+ }
+/******************************************************************************
+ * FunctionName : spi_byte_read_espslave
+ * Description  : SPI master 1 byte read function for esp8266 slave,
+ * 			read 1byte data from esp8266 slave buffer needs 16bit transmission ,
+ * 			first byte is command 0x06 to read slave buffer, second byte is recieved data
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8* data- recieved data address
+*******************************************************************************/
+  void ICACHE_FLASH_ATTR
+      spi_byte_read_espslave(uint8 spi_no,uint8 *data)
+ {
+	uint32 regvalue;
+
+	if(spi_no>1) 		return; //handle invalid input number
+
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+
+	SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
+	CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY);
+		//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+	// bit15-0 is cmd value.
+	//0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value
+	WRITE_PERI_REG(SPI_USER2(spi_no), 
+					((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|6);
+	SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
+	
+	while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
+	*data=(uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);
+ }
+
+/******************************************************************************
+ * FunctionName : spi_slave_init
+ * Description  : SPI slave mode initial funtion, including mode setting,
+ * 			IO setting, transmission interrupt opening, interrupt function registration
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+ *				uint8 data_len - read&write data pack length,using byte as unit,the range is 1-32
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_slave_init(uint8 spi_no,uint8 data_len)
+{
+    uint32 regvalue; 
+    uint32 data_bit_len;
+    if(spi_no>1)
+        return; //handle invalid input number
+    if(data_len<=1) data_bit_len=7;
+    else if(data_len>=32) data_bit_len=0xff;
+    else	data_bit_len=(data_len<<3)-1;
+
+    //clear bit9,bit8 of reg PERIPHS_IO_MUX
+    //bit9 should be cleared when HSPI clock doesn't equal CPU clock
+    //bit8 should be cleared when SPI clock doesn't equal CPU clock
+    ////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST
+    if(spi_no==SPI){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode	
+    }else if(spi_no==HSPI){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode	
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode	
+    }
+
+    //regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no));
+    //slave mode,slave use buffers which are register "SPI_FLASH_C0~C15", enable trans done isr
+    //set bit 30 bit 29 bit9,bit9 is trans done isr mask
+    SET_PERI_REG_MASK(	SPI_SLAVE(spi_no), 
+    						SPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN|
+                                         	SPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN|
+                                         	SPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN|
+                                         	SPI_TRANS_DONE_EN);
+    //disable general trans intr 
+    //CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN);
+
+    CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode
+    SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15 
+
+
+//////**************RUN WHEN SLAVE RECIEVE*******************///////
+   //tow lines below is to configure spi timing.
+    SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<<SPI_MOSI_DELAY_NUM_S) ;//delay num
+    os_printf("SPI_CTRL2 is %08x\n",READ_PERI_REG(SPI_CTRL2(spi_no)));
+    WRITE_PERI_REG(SPI_CLOCK(spi_no), 0);
+
+
+    
+/////***************************************************//////	
+
+    //set 8 bit slave command length, because slave must have at least one bit addr, 
+    //8 bit slave+8bit addr, so master device first 2 bytes can be regarded as a command 
+    //and the  following bytes are datas, 
+    //32 bytes input wil be stored in SPI_FLASH_C0-C7
+    //32 bytes output data should be set to SPI_FLASH_C8-C15
+    WRITE_PERI_REG(SPI_USER2(spi_no), (0x7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S); //0x70000000
+
+    //set 8 bit slave recieve buffer length, the buffer is SPI_FLASH_C0-C7
+    //set 8 bit slave status register, which is the low 8 bit of register "SPI_FLASH_STATUS"
+    SET_PERI_REG_MASK(SPI_SLAVE1(spi_no),  ((data_bit_len&SPI_SLV_BUF_BITLEN)<< SPI_SLV_BUF_BITLEN_S)|
+                                                                                        ((0x7&SPI_SLV_STATUS_BITLEN)<<SPI_SLV_STATUS_BITLEN_S)|
+                                                                                       ((0x7&SPI_SLV_WR_ADDR_BITLEN)<<SPI_SLV_WR_ADDR_BITLEN_S)|
+                                                                                       ((0x7&SPI_SLV_RD_ADDR_BITLEN)<<SPI_SLV_RD_ADDR_BITLEN_S));
+    
+    SET_PERI_REG_MASK(SPI_PIN(spi_no),BIT19);//BIT19   
+
+    //maybe enable slave transmission liston 
+    SET_PERI_REG_MASK(SPI_CMD(spi_no),SPI_USR);
+    //register level2 isr function, which contains spi, hspi and i2s events
+    ETS_SPI_INTR_ATTACH(spi_slave_isr_handler,NULL);
+    //enable level2 isr, which contains spi, hspi and i2s events
+    ETS_SPI_INTR_ENABLE(); 
+}
+
+
+
+
+
+/* =============================================================================================
+ * code below is for spi slave r/w testcase with 2 r/w state lines connected to the spi master mcu
+ * replace with your own process functions
+ * find "add system_os_post here" in spi_slave_isr_handler.
+ * =============================================================================================
+ */
+
+
+
+
+
+
+
+#ifdef SPI_SLAVE_DEBUG
+ /******************************************************************************
+ * FunctionName : hspi_master_readwrite_repeat
+ * Description  : SPI master test  function for reading and writing esp8266 slave buffer,
+ 			the function uses HSPI module 
+*******************************************************************************/
+os_timer_t timer2;
+
+void hspi_master_readwrite_repeat(void)
+{
+	static uint8 data=0;
+	uint8 temp;
+
+	os_timer_disarm(&timer2);
+	spi_byte_read_espslave(HSPI,&temp);
+
+	temp++;
+	spi_byte_write_espslave(HSPI,temp);
+       os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);
+       os_timer_arm(&timer2, 500, 0);
+}
+#endif
+
+
+/******************************************************************************
+ * FunctionName : spi_slave_isr_handler
+ * Description  : SPI interrupt function, SPI HSPI and I2S interrupt can trig this function
+ 			   some basic operation like clear isr flag has been done, 
+ 			   and it is availible	for adding user coder in the funtion
+ * Parameters  : void *para- function parameter address, which has been registered in function spi_slave_init
+*******************************************************************************/
+#include "gpio.h"
+#include "user_interface.h"
+#include "mem.h"
+static uint8 spi_data[32] = {0};
+static uint8 idx = 0;
+static uint8 spi_flg = 0;
+#define SPI_MISO
+#define SPI_QUEUE_LEN 8
+os_event_t * spiQueue;
+#define MOSI  0
+#define MISO  1
+#define STATUS_R_IN_WR 2
+#define STATUS_W  3
+#define TR_DONE_ALONE  4
+#define WR_RD 5
+#define DATA_ERROR 6
+#define STATUS_R_IN_RD 7
+//init the two intr line of slave
+//gpio0: wr_ready ,and  
+//gpio2: rd_ready , controlled by slave
+void ICACHE_FLASH_ATTR
+    gpio_init()
+{
+
+    	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
+	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
+	//PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
+    	GPIO_OUTPUT_SET(0, 1);
+    	GPIO_OUTPUT_SET(2, 0);
+	//GPIO_OUTPUT_SET(4, 1);
+}
+
+
+
+void spi_slave_isr_handler(void *para)
+{
+	uint32 regvalue,calvalue;
+    	static uint8 state =0;
+	uint32 recv_data,send_data;
+
+	if(READ_PERI_REG(0x3ff00020)&BIT4){		
+        //following 3 lines is to clear isr signal
+        	CLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);
+    	}else if(READ_PERI_REG(0x3ff00020)&BIT7){ //bit7 is for hspi isr,
+        	regvalue=READ_PERI_REG(SPI_SLAVE(HSPI));
+         	CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE_EN|
+								SPI_SLV_WR_STA_DONE_EN|
+								SPI_SLV_RD_STA_DONE_EN|
+								SPI_SLV_WR_BUF_DONE_EN|
+								SPI_SLV_RD_BUF_DONE_EN);
+        	SET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);
+        	CLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE|
+								SPI_SLV_WR_STA_DONE|
+								SPI_SLV_RD_STA_DONE|
+								SPI_SLV_WR_BUF_DONE|
+								SPI_SLV_RD_BUF_DONE); 
+		SET_PERI_REG_MASK(SPI_SLAVE(HSPI),  
+								SPI_TRANS_DONE_EN|
+								SPI_SLV_WR_STA_DONE_EN|
+								SPI_SLV_RD_STA_DONE_EN|
+								SPI_SLV_WR_BUF_DONE_EN|
+								SPI_SLV_RD_BUF_DONE_EN);
+
+		if(regvalue&SPI_SLV_WR_BUF_DONE){ 
+            		GPIO_OUTPUT_SET(0, 0);
+            		idx=0;
+            		while(idx<8){
+            			recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
+            			spi_data[idx<<2] = recv_data&0xff;
+            			spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
+            			spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
+            			spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
+            			idx++;
+			}
+			//add system_os_post here
+            		GPIO_OUTPUT_SET(0, 1);
+		}
+        	if(regvalue&SPI_SLV_RD_BUF_DONE){
+			//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.
+           		GPIO_OUTPUT_SET(2, 0);
+			//add system_os_post here
+			//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);
+
+        	}
+    
+    }else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr,
+
+    }
+}
+
+
+#ifdef SPI_SLAVE_DEBUG
+
+void ICACHE_FLASH_ATTR
+    set_miso_data()
+{
+    if(GPIO_INPUT_GET(2)==0){
+        WRITE_PERI_REG(SPI_W8(HSPI),0x05040302);
+        WRITE_PERI_REG(SPI_W9(HSPI),0x09080706);
+        WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a);
+        WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e);
+
+        WRITE_PERI_REG(SPI_W12(HSPI),0x15141312);
+        WRITE_PERI_REG(SPI_W13(HSPI),0x19181716);
+        WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a);
+        WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e);
+        GPIO_OUTPUT_SET(2, 1);
+    }
+}
+
+
+
+void ICACHE_FLASH_ATTR
+    disp_spi_data()
+{
+    uint8 i = 0;
+    for(i=0;i<32;i++){
+        os_printf("data %d : 0x%02x\n\r",i,spi_data[i]);
+    }
+    //os_printf("d31:0x%02x\n\r",spi_data[31]);
+}
+
+
+void ICACHE_FLASH_ATTR
+    spi_task(os_event_t *e)
+{
+    uint8 data;
+    switch(e->sig){
+       case MOSI:
+            	disp_spi_data();
+            	break;
+	case STATUS_R_IN_WR :
+		os_printf("SR ERR in WRPR,Reg:%08x \n",e->par);
+		break;
+	case STATUS_W:
+		os_printf("SW ERR,Reg:%08x\n",e->par);
+		break;	
+	case TR_DONE_ALONE:
+		os_printf("TD ALO ERR,Reg:%08x\n",e->par);
+		break;	
+	case WR_RD:
+		os_printf("WR&RD ERR,Reg:%08x\n",e->par);
+		break;	
+	case DATA_ERROR:
+		os_printf("Data ERR,Reg:%08x\n",e->par);
+		break;
+	case STATUS_R_IN_RD :
+		os_printf("SR ERR in RDPR,Reg:%08x\n",e->par);
+		break;	
+        default:
+            break;
+    }
+}
+
+void ICACHE_FLASH_ATTR
+    spi_task_init(void)
+{
+    spiQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*SPI_QUEUE_LEN);
+    system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN);
+}
+
+os_timer_t spi_timer_test;
+
+void ICACHE_FLASH_ATTR
+    spi_test_init()
+{
+    os_printf("spi init\n\r");
+    spi_slave_init(HSPI);
+    os_printf("gpio init\n\r");
+    gpio_init();
+    os_printf("spi task init \n\r");
+    spi_task_init();
+#ifdef SPI_MISO
+    os_printf("spi miso init\n\r");
+    set_miso_data();
+#endif
+    
+    //os_timer_disarm(&spi_timer_test);
+    //os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl
+    //os_timer_arm(&spi_timer_test,50,1);
+}
+
+#endif
+
+

+ 502 - 0
driver/spi_interface.c

@@ -0,0 +1,502 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+
+/**
+ * @file spi_interface.c
+ * @brief Defines and Macros for the SPI.
+ */
+
+#include "driver/spi_interface.h"
+#include "osapi.h"
+#include "ets_sys.h"
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @brief Based on pAttr initialize SPI module.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIInit(SpiNum spiNum, SpiAttr* pAttr)
+{
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pAttr)) {
+        return;
+    }
+    // SPI_CPOL & SPI_CPHA
+    switch (pAttr->subMode) {
+    case SpiSubMode_1:
+        CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SpiSubMode_2:
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        SET_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
+        break;
+    case SpiSubMode_3:
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE);
+        break;
+    case SpiSubMode_0:
+    default:
+        CLEAR_PERI_REG_MASK(SPI_PIN(spiNum), SPI_IDLE_EDGE);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum),  SPI_CK_OUT_EDGE);
+        // To do nothing
+        break;
+    }
+
+    // SPI bit order
+    if (SpiBitOrder_MSBFirst == pAttr->bitOrder) {
+        CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER);
+        CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER);
+    } else if (SpiBitOrder_LSBFirst == pAttr->bitOrder) {
+        SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_WR_BIT_ORDER);
+        SET_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_RD_BIT_ORDER);
+    } else {
+        // To do nothing
+    }
+
+    // Disable flash operation mode
+    // As earlier as better, if not SPI_CTRL2 can not to be set delay cycles.
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_FLASH_MODE);
+
+    // SPI mode type
+    if (SpiMode_Master == pAttr->mode) {
+        // SPI mode type
+        CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE);
+        // SPI Send buffer
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
+        // SPI Speed
+        if (1 < (pAttr->speed)) {
+            uint8 i, k;
+            i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
+            k = pAttr->speed / i;
+            CLEAR_PERI_REG_MASK(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK);
+            WRITE_PERI_REG(SPI_CLOCK(spiNum),
+                           (((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
+                           (((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
+                           ((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
+                           (((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
+        } else {
+            WRITE_PERI_REG(SPI_CLOCK(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
+        }
+        // By default format:CMD+ADDR+DATA
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI );
+
+        //delay num
+        SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S));
+    } else if (SpiMode_Slave == pAttr->mode) {
+        // BIT19 must do
+        SET_PERI_REG_MASK(SPI_PIN(spiNum), BIT19);
+
+        // SPI mode type
+        SET_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_SLAVE_MODE);
+        // SPI Send buffer
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
+
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+
+        // If do not set delay cycles, slave not working,master cann't get the data.
+        SET_PERI_REG_MASK(SPI_CTRL2(spiNum), ((0x1 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
+        // SPI Speed
+        WRITE_PERI_REG(SPI_CLOCK(spiNum), 0);
+
+        // By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes).
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          7, SPI_USR_COMMAND_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_WR_ADDR_BITLEN,
+                          7, SPI_SLV_WR_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_RD_ADDR_BITLEN,
+                          7, SPI_SLV_RD_ADDR_BITLEN_S);
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_BUF_BITLEN,
+                          (32 * 8 - 1), SPI_SLV_BUF_BITLEN_S);
+        // For 8266 work on slave mode.
+        SET_PERI_REG_BITS(SPI_SLAVE1(spiNum), SPI_SLV_STATUS_BITLEN,
+                          7, SPI_SLV_STATUS_BITLEN_S);
+    } else {
+        // To do nothing
+    }
+
+    //clear Daul or Quad lines transmission mode
+    CLEAR_PERI_REG_MASK(SPI_CTRL(spiNum), SPI_QIO_MODE | SPI_DIO_MODE | SPI_DOUT_MODE | SPI_QOUT_MODE);
+    // Clear the data buffer.
+    uint8 i;
+    uint32 regAddr = REG_SPI_BASE(spiNum) + 0x40;
+    for (i = 0; i < 16; ++i) {
+        WRITE_PERI_REG(regAddr, 0);
+        regAddr += 4;
+    }
+    
+}
+
+/**
+ * @brief Set address value by master mode.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterCfgAddr(SpiNum spiNum, uint32_t addr)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // Set address
+    WRITE_PERI_REG(SPI_ADDR(spiNum), addr);
+}
+
+/**
+ * @brief Set command value by master mode.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterCfgCmd(SpiNum spiNum, uint32_t cmd)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
+    // bit15-0 is cmd value.
+    SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
+}
+
+/**
+ * @brief Send data to slave.
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterSendData(SpiNum spiNum, SpiData* pInData)
+{
+    char idx = 0;
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pInData)
+        || (64 < pInData->dataLen)) {
+        return -1;
+    }
+    uint32_t *value = pInData->data;
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pInData->cmdLen != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pInData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        // Load command
+        SPIMasterCfgCmd(spiNum, pInData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pInData->addrLen == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pInData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pInData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        // Load address
+        SPIMasterCfgAddr(spiNum, *pInData->addr);
+    }
+    // Set data by user.
+    if (pInData->dataLen != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        // Load send buffer
+        do {
+            WRITE_PERI_REG((SPI_W0(spiNum) + (idx << 2)), *value++);
+        } while (++idx < ((pInData->dataLen / 4) + ((pInData->dataLen % 4) ? 1 : 0)));
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN, ((pInData->dataLen << 3) - 1), SPI_USR_MOSI_BITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN,
+                          0, SPI_USR_MOSI_BITLEN_S);
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+    // Wait for transmit done
+    while (!(READ_PERI_REG(SPI_SLAVE(spiNum))&SPI_TRANS_DONE));
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SPI_TRANS_DONE);
+    return 0;
+}
+
+/**
+ * @brief Receive data from slave.
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterRecvData(SpiNum spiNum, SpiData* pOutData)
+{
+    char idx = 0;
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pOutData)) {
+        return -1;
+    }
+
+    uint32_t *value = pOutData->data;
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Set command by user.
+    if (pOutData->cmdLen != 0) {
+        // Max command length 16 bits.
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          ((pOutData->cmdLen << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
+        // Enable command
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        // Load command
+        SPIMasterCfgCmd(spiNum, pOutData->cmd);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_COMMAND);
+        SET_PERI_REG_BITS(SPI_USER2(spiNum), SPI_USR_COMMAND_BITLEN,
+                          0, SPI_USR_COMMAND_BITLEN_S);
+    }
+    // Set Address by user.
+    if (pOutData->addrLen == 0) {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          0, SPI_USR_ADDR_BITLEN_S);
+    } else {
+        if (NULL == pOutData->addr) {
+            return -1;
+        }
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_ADDR_BITLEN,
+                          ((pOutData->addrLen << 3) - 1), SPI_USR_ADDR_BITLEN_S);
+        // Enable address
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_ADDR);
+        // Load address
+        SPIMasterCfgAddr(spiNum, *pOutData->addr);
+    }
+    // Set data by user.
+    if (pOutData->dataLen != 0) {
+        if (NULL == value) {
+            return -1;
+        }
+        // Clear MOSI enable
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        // Enable MOSI
+        SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        // Set data send buffer length.Max data length 64 bytes.
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN, ((pOutData->dataLen << 3) - 1), SPI_USR_MISO_BITLEN_S);
+    } else {
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+        CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+        SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN,
+                          0, SPI_USR_MISO_BITLEN_S);
+    }
+    // Start send data
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Read data out
+    do {
+        *value++ = READ_PERI_REG(SPI_W0(spiNum) + (idx << 2));
+    } while (++idx < ((pOutData->dataLen / 4) + ((pOutData->dataLen % 4) ? 1 : 0)));
+    
+
+    return 0;
+}
+
+/**
+ * @brief Load data to send buffer by slave mode.
+ *
+ */
+int ICACHE_FLASH_ATTR SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t inLen)
+{
+    if (NULL == pInData) {
+        return -1;
+    }
+	uint32_t *value = pInData;
+    char i;
+    for (i = 0; i < inLen; ++i) {
+        WRITE_PERI_REG((SPI_W8(spiNum) + (i << 2)), *value++);
+    }
+    // Enable slave transmission liston
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+    return 0;
+}
+
+/**
+ * @brief Configurate slave prepare for receive data.
+ *
+ */
+int ICACHE_FLASH_ATTR SPISlaveRecvData(SpiNum spiNum)
+{
+    if ((spiNum > SpiNum_HSPI)) {
+        return -1;
+    }
+    // Enable slave transmission liston
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    return 0;
+}
+
+/**
+ * @brief Send data to slave(ESP8266 register of RD_STATUS or WR_STATUS).
+ *
+ */
+void ICACHE_FLASH_ATTR SPIMasterSendStatus(SpiNum spiNum, uint8_t data)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Enable MOSI
+    SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI);
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x04 is eps8266 slave write cmd value
+    WRITE_PERI_REG(SPI_USER2(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_WRITE_STATUS_TO_SLAVE_CMD);
+    // Set data send buffer length.
+    SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MOSI_BITLEN,
+                      ((sizeof(data) << 3) - 1), SPI_USR_MOSI_BITLEN_S);
+
+    WRITE_PERI_REG(SPI_W0(spiNum), (uint32)(data));
+    // Start SPI
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+}
+
+/**
+ * @brief Receive status register from slave(ESP8266).
+ *
+ */
+int ICACHE_FLASH_ATTR SPIMasterRecvStatus(SpiNum spiNum)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return -1;
+    }
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+    // Enable MISO
+    SET_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MISO);
+    CLEAR_PERI_REG_MASK(SPI_USER(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
+
+    // 8bits cmd, 0x06 is eps8266 slave read status cmd value
+    WRITE_PERI_REG(SPI_USER2(spiNum),
+                   ((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
+                   | MASTER_READ_STATUS_FROM_SLAVE_CMD);
+    // Set revcive buffer length.
+    SET_PERI_REG_BITS(SPI_USER1(spiNum), SPI_USR_MISO_BITLEN,
+                      7, SPI_USR_MISO_BITLEN_S);
+
+    // start spi module.
+    SET_PERI_REG_MASK(SPI_CMD(spiNum), SPI_USR);
+
+    while (READ_PERI_REG(SPI_CMD(spiNum))&SPI_USR);
+
+    uint8_t data = (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff);
+
+    return (uint8)(READ_PERI_REG(SPI_W0(spiNum)) & 0xff);
+}
+
+/**
+ * @brief Select SPI CS pin.
+ *
+ */
+void ICACHE_FLASH_ATTR SPICsPinSelect(SpiNum spiNum, SpiPinCS pinCs)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    // clear select
+    SET_PERI_REG_BITS(SPI_PIN(spiNum), 3, 0, 0);
+    SET_PERI_REG_MASK(SPI_PIN(spiNum), pinCs);
+}
+
+
+void SPIIntCfg(SpiNum spiNum, SpiIntInfo *pIntInfo)
+{
+    if ((spiNum > SpiNum_HSPI)
+        || (NULL == pIntInfo)) {
+        return;
+    }
+    // Clear the interrupt source and disable all of the interrupt.
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), 0x3FF);
+    SPIIntEnable(spiNum, pIntInfo->src);
+    os_printf("src=%x\r\n,isrFunc=%x", (pIntInfo->src << 5), pIntInfo->isrFunc);
+    //
+    ETS_SPI_INTR_ATTACH(pIntInfo->isrFunc, NULL);
+    // Enable isr
+    ETS_SPI_INTR_ENABLE();    
+}
+
+
+/**
+ * @brief Enable SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntEnable(SpiNum spiNum, SpiIntSrc intSrc)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    SET_PERI_REG_MASK(SPI_SLAVE(spiNum), (intSrc << 5));
+}
+
+/**
+ * @brief Disable SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntDisable(SpiNum spiNum, SpiIntSrc intSrc)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), intSrc);
+}
+
+/**
+ * @brief Clear all of SPI interrupt source.
+ *
+ */
+void ICACHE_FLASH_ATTR SPIIntClear(SpiNum spiNum)
+{
+    if (spiNum > SpiNum_HSPI) {
+        return;
+    }
+    CLEAR_PERI_REG_MASK(SPI_SLAVE(spiNum), SpiIntSrc_TransDone
+                        | SpiIntSrc_WrStaDone
+                        | SpiIntSrc_RdStaDone
+                        | SpiIntSrc_WrBufDone
+                        | SpiIntSrc_RdBufDone);
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 422 - 0
driver/spi_overlap.c

@@ -0,0 +1,422 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "driver/spi_overlap.h"
+#include "driver/spi.h"
+#include "gpio.h"
+
+#define SPI_FLASH_READ_MODE_MASK 0x196000
+#define WAIT_HSPI_IDLE() 	while(READ_PERI_REG(SPI_EXT2(HSPI))||(READ_PERI_REG(SPI_CMD(HSPI))&0xfffc0000));
+#define CONF_HSPI_CLK_DIV(div)	WRITE_PERI_REG(SPI_CLOCK(HSPI), (((div<<1)+1)<<12)+(div<<6)+(div<<1)+1)
+#define HSPI_FALLING_EDGE_SAMPLE()		SET_PERI_REG_MASK(SPI_USER(HSPI),  SPI_CK_OUT_EDGE)
+#define HSPI_RISING_EDGE_SAMPLE()			CLEAR_PERI_REG_MASK(SPI_USER(HSPI),  SPI_CK_OUT_EDGE)
+#define ACTIVE_HSPI_CS0	 	CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS |SPI_CS2_DIS)
+#define ACTIVE_HSPI_CS1		CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS1_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS2_DIS)
+#define ACTIVE_HSPI_CS2		CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS2_DIS);\
+						SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_CS0_DIS |SPI_CS1_DIS)
+#define ENABLE_HSPI_DEV_CS()		PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2)
+#define DISABLE_HSPI_DEV_CS()		GPIO_OUTPUT_SET(15, 1);\
+									PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15)
+struct hspi_device_register hspi_dev_reg;
+/******************************************************************************
+ * FunctionName : hspi_overlap_init
+ * Description  : enable hspi and spi module overlap mode
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+hspi_overlap_init(void)
+{
+	//hspi overlap to spi, two spi masters on cspi
+	SET_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap);
+
+	//set higher priority for spi than hspi
+	SET_PERI_REG_MASK(SPI_EXT3(SPI),0x1);
+	SET_PERI_REG_MASK(SPI_EXT3(HSPI),0x3);
+	SET_PERI_REG_MASK(SPI_USER(HSPI), BIT(5));
+}
+/******************************************************************************
+ * FunctionName : hspi_overlap_deinit
+ * Description  : recover hspi and spi module from overlap mode
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+hspi_overlap_deinit(void)
+{
+	//hspi overlap to spi, two spi masters on cspi
+	CLEAR_PERI_REG_MASK(HOST_INF_SEL, reg_cspi_overlap);
+
+	//set higher priority for spi than hspi
+	CLEAR_PERI_REG_MASK(SPI_EXT3(SPI),0x1);
+	CLEAR_PERI_REG_MASK(SPI_EXT3(HSPI),0x3);
+	CLEAR_PERI_REG_MASK(SPI_USER(HSPI), BIT(5));
+}
+
+/******************************************************************************
+ * FunctionName : spi_reg_backup
+ * Description  : backup SPI normal operation register value and disable CPU cache to modify some flash registers.
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+    spi_reg_backup(uint8 spi_no,uint32* backup_mem)
+{
+	if(spi_no>1) 		return; //handle invalid input number
+
+	backup_mem[PERIPHS_IO_MUX_BACKUP]	=READ_PERI_REG(PERIPHS_IO_MUX);
+	backup_mem[SPI_USER_BACKUP]	=READ_PERI_REG(SPI_USER(spi_no)); 	
+	backup_mem[SPI_CTRL_BACKUP]	=READ_PERI_REG(SPI_CTRL(spi_no)); 	
+	backup_mem[SPI_CLOCK_BACKUP]	=READ_PERI_REG(SPI_CLOCK(spi_no));
+	backup_mem[SPI_USER1_BACKUP]	=READ_PERI_REG(SPI_USER1(spi_no));
+	backup_mem[SPI_USER2_BACKUP]	=READ_PERI_REG(SPI_USER2(spi_no));	
+	backup_mem[SPI_CMD_BACKUP]	=READ_PERI_REG(SPI_CMD(spi_no));
+	backup_mem[SPI_PIN_BACKUP]	=READ_PERI_REG(SPI_PIN(spi_no));
+	backup_mem[SPI_SLAVE_BACKUP]	=READ_PERI_REG(SPI_SLAVE(spi_no));
+}
+/******************************************************************************
+ * FunctionName : spi_reg_recover
+ * Description  : recover SPI normal operation register value and enable CPU cache.
+ * Parameters   : 	uint8 spi_no - SPI module number, Only "SPI" and "HSPI" are valid
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+   spi_reg_recover(uint8 spi_no,uint32* backup_mem)
+{
+	if(spi_no>1) 		return; //handle invalid input number
+
+//	WRITE_PERI_REG(PERIPHS_IO_MUX, backup_mem[PERIPHS_IO_MUX_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER(spi_no), backup_mem[SPI_USER_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CTRL(spi_no), backup_mem[SPI_CTRL_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CLOCK(spi_no), backup_mem[SPI_CLOCK_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER1(spi_no), backup_mem[SPI_USER1_BACKUP]); 	
+	WRITE_PERI_REG(SPI_USER2(spi_no), backup_mem[SPI_USER2_BACKUP]); 	
+	WRITE_PERI_REG(SPI_CMD(spi_no), backup_mem[SPI_CMD_BACKUP]); 	
+	WRITE_PERI_REG(SPI_PIN(spi_no), backup_mem[SPI_PIN_BACKUP]); 
+//	WRITE_PERI_REG(SPI_SLAVE(spi_no), backup_mem[SPI_SLAVE_BACKUP]); 
+}
+
+void ICACHE_FLASH_ATTR  
+    hspi_master_dev_init(uint8 dev_no,uint8 clk_polar,uint8 clk_div)
+{
+	uint32 regtemp;
+	if((dev_no>3)||(clk_polar>1)||(clk_div>0x1f))
+	{
+		os_printf("hspi_master_dev_init parameter is out of range!\n\r");
+		return;
+	}
+	
+	WAIT_HSPI_IDLE();
+	if(!hspi_dev_reg.hspi_reg_backup_flag){
+		if(READ_PERI_REG(PERIPHS_IO_MUX)&BIT8){
+			hspi_dev_reg.spi_io_80m=1;
+			SET_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK);
+		}else{
+			hspi_dev_reg.spi_io_80m=0;
+			CLEAR_PERI_REG_MASK(SPI_CLOCK(HSPI),SPI_CLK_EQU_SYSCLK);
+		}
+		
+		regtemp=READ_PERI_REG(SPI_CTRL(SPI))&SPI_FLASH_READ_MODE_MASK;
+		CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_FLASH_READ_MODE_MASK);
+		SET_PERI_REG_MASK(SPI_CTRL(HSPI), regtemp);
+		spi_reg_backup(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+		spi_master_init(HSPI);
+		spi_reg_backup(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+
+		hspi_dev_reg.hspi_reg_backup_flag=1;
+		
+	//	spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+		hspi_dev_reg.selected_dev_num=HSPI_IDLE;
+	}
+
+	hspi_dev_reg.hspi_dev_conf[dev_no].active=1;
+	hspi_dev_reg.hspi_dev_conf[dev_no].clk_div=clk_div;
+	hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar=clk_polar;
+	
+	switch(dev_no){
+		case HSPI_CS_DEV :
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
+			CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX, BIT9);
+			break;
+
+		case SPI_CS1_DEV :	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_SPI_CS1);
+			if(hspi_dev_reg.spi_io_80m){	
+				os_printf("SPI CS1 device must work at 80Mhz");
+			}
+			break;
+			
+		case SPI_CS2_DEV :	
+			PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_SPI_CS2);
+			if(hspi_dev_reg.spi_io_80m){	
+				os_printf("SPI CS2 device must work at 80Mhz");
+			}
+			break;
+			
+		default: break;
+	}
+}
+
+void ICACHE_FLASH_ATTR
+    hspi_dev_sel(uint8 dev_no)
+{
+	uint32 regval;
+	
+	if(dev_no>3){
+		os_printf("hspi_dev_sel parameter is out of range!\n\r");
+		return;
+	}
+
+	if(!hspi_dev_reg.hspi_dev_conf[dev_no].active){
+		os_printf("device%d has not been initialized!\n\r",dev_no);
+		return;
+	}
+	
+	switch(hspi_dev_reg.selected_dev_num){
+		case HSPI_CS_DEV:
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+				
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+				
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0	;
+			}
+			break;
+
+		case SPI_CS1_DEV:
+			if(dev_no==SPI_CS2_DEV){
+				WAIT_HSPI_IDLE();
+				if(!hspi_dev_reg.spi_io_80m)	{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+				ACTIVE_HSPI_CS2;			
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0;
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+
+		case SPI_CS2_DEV:
+			if(dev_no==SPI_CS1_DEV){
+				WAIT_HSPI_IDLE();
+				if(!hspi_dev_reg.spi_io_80m)	{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS1;
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0;
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+			
+		case SPI_CS0_FLASH:
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}			
+			}
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+
+		default: 
+			if((dev_no==SPI_CS1_DEV)||(dev_no==SPI_CS2_DEV)){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				else							{CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);}
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				if(dev_no==SPI_CS1_DEV)		{ACTIVE_HSPI_CS1;}
+				else							{ACTIVE_HSPI_CS2;}
+			}
+			else if(dev_no==SPI_CS0_FLASH){
+				WAIT_HSPI_IDLE();
+				DISABLE_HSPI_DEV_CS();
+				hspi_overlap_init();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_flash_reg_backup);
+
+				if(hspi_dev_reg.spi_io_80m)	{SET_PERI_REG_MASK(SPI_CLOCK(HSPI), SPI_CLK_EQU_SYSCLK);}
+				
+				HSPI_RISING_EDGE_SAMPLE();
+				ACTIVE_HSPI_CS0	;
+			}			
+			else if(dev_no==HSPI_CS_DEV){
+				WAIT_HSPI_IDLE();
+				ENABLE_HSPI_DEV_CS();
+				hspi_overlap_deinit();
+				spi_reg_recover(HSPI, hspi_dev_reg.hspi_dev_reg_backup);
+				CONF_HSPI_CLK_DIV(hspi_dev_reg.hspi_dev_conf[dev_no].clk_div);
+
+				if(hspi_dev_reg.hspi_dev_conf[dev_no].clk_polar)	{HSPI_FALLING_EDGE_SAMPLE();}
+				else												{HSPI_RISING_EDGE_SAMPLE();}
+
+				ACTIVE_HSPI_CS0;
+			}
+			break;
+	}
+	hspi_dev_reg.selected_dev_num=dev_no;
+}
+
+/******************************************************************************
+ * FunctionName : spi_read_data
+ * Description  : use hspi to read flash data for stability test
+ * Parameters   : 	SpiFlashChip * spi-- flash parameter structure pointer
+ * 				uint32 flash_addr--flash start address
+ *				uint32 * addr_dest--start address for preped destination memory space
+ *				uint32 byte_length--length of the data which needs to be read from flash
+*******************************************************************************/
+SpiFlashOpResult ICACHE_FLASH_ATTR
+hspi_overlap_read_flash_data(SpiFlashChip * spi, uint32 flash_addr, uint32 * addr_dest, uint32 byte_length)
+{
+    uint32  temp_addr,reg_tmp;
+    sint32  temp_length;
+    uint8   i;
+    uint8   remain_word_num;	
+	
+   hspi_dev_sel(SPI_CS0_FLASH);
+
+      //address range check 	
+   if ((flash_addr+byte_length) > (spi->chip_size))
+   {
+        return SPI_FLASH_RESULT_ERR;
+   }
+   
+    temp_addr = flash_addr;
+    temp_length = byte_length;
+	
+    while(temp_length > 0)
+    {
+       if(temp_length >= SPI_BUFF_BYTE_NUM)
+       {
+	//   reg_tmp=((temp_addr&0xff)<<16)|(temp_addr&0xff00)|((temp_addr&0xff0000)>>16)|(SPI_BUFF_BYTE_NUM << SPI_FLASH_BYTES_LEN);
+	   reg_tmp= temp_addr |(SPI_BUFF_BYTE_NUM<< SPI_FLASH_BYTES_LEN) ;
+	   WRITE_PERI_REG(SPI_ADDR(HSPI), reg_tmp);
+          WRITE_PERI_REG(SPI_CMD(HSPI), SPI_FLASH_READ);
+          while(READ_PERI_REG(SPI_CMD(HSPI)) != 0);
+
+          for(i=0; i<(SPI_BUFF_BYTE_NUM>>2);i++)
+          {    
+              *addr_dest++ = READ_PERI_REG(SPI_W0(HSPI)+i*4);
+          }
+          temp_length = temp_length - SPI_BUFF_BYTE_NUM;
+          temp_addr = temp_addr + SPI_BUFF_BYTE_NUM;
+       }
+       else
+       {
+            WRITE_PERI_REG(SPI_ADDR(HSPI), temp_addr |(temp_length << SPI_FLASH_BYTES_LEN ));
+            WRITE_PERI_REG(SPI_CMD(HSPI), SPI_FLASH_READ);
+            while(READ_PERI_REG(SPI_CMD(HSPI)) != 0);
+
+            remain_word_num = (0== (temp_length&0x3))? (temp_length>>2) : (temp_length>>2)+1;
+	     for (i=0; i<remain_word_num; i++)		
+	     {
+               *addr_dest++ = READ_PERI_REG(SPI_W0(HSPI)+i*4);
+	     }	 
+            temp_length = 0;
+        }
+    }
+
+    return SPI_FLASH_RESULT_OK;
+}
+
+void ICACHE_FLASH_ATTR
+hspi_overlap_flash_init(void)
+{
+	 hspi_master_dev_init(SPI_CS0_FLASH,0,0);
+
+	 spi_flash_set_read_func(hspi_overlap_read_flash_data);
+}

+ 796 - 0
driver/uart.c

@@ -0,0 +1,796 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "ets_sys.h"
+#include "osapi.h"
+#include "driver/uart.h"
+#include "osapi.h"
+#include "driver/uart_register.h"
+#include "mem.h"
+#include "os_type.h"
+
+// UartDev is defined and initialized in rom code.
+extern UartDevice    UartDev;
+
+LOCAL struct UartBuffer* pTxBuffer = NULL;
+LOCAL struct UartBuffer* pRxBuffer = NULL;
+
+/*uart demo with a system task, to output what uart receives*/
+/*this is a example to process uart data from task,please change the priority to fit your application task if exists*/
+/*it might conflict with your task, if so,please arrange the priority of different task,  or combine it to a different event in the same task. */
+#define uart_recvTaskPrio        0
+#define uart_recvTaskQueueLen    10
+os_event_t    uart_recvTaskQueue[uart_recvTaskQueueLen];
+
+#define DBG  
+#define DBG1 uart1_sendStr_no_wait
+#define DBG2 os_printf
+
+
+LOCAL void uart0_rx_intr_handler(void *para);
+
+/******************************************************************************
+ * 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
+*******************************************************************************/
+LOCAL 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{
+        /* rcv_buff size if 0x100 */
+        ETS_UART_INTR_ATTACH(uart0_rx_intr_handler,  &(UartDev.rcv_buff));
+        PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
+	#if UART_HW_RTS
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);   //HW FLOW CONTROL RTS PIN
+        #endif
+	#if UART_HW_CTS
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);   //HW FLOW CONTROL CTS PIN
+        #endif
+    }
+    uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE
+    
+    WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M)  <<  UART_PARITY_EN_S) //SET BIT AND PARITY MODE
+                                                                        | ((UartDev.parity & UART_PARITY_M)  <<UART_PARITY_S )
+                                                                        | ((UartDev.stop_bits & UART_STOP_BIT_NUM) << UART_STOP_BIT_NUM_S)
+                                                                        | ((UartDev.data_bits & UART_BIT_NUM) << 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);    //RESET FIFO
+    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),
+        ((100 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
+        #if UART_HW_RTS
+        ((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
+        UART_RX_FLOW_EN |   //enbale rx flow control
+        #endif
+        (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
+        UART_RX_TOUT_EN|
+        ((0x10 & UART_TXFIFO_EMPTY_THRHD)<<UART_TXFIFO_EMPTY_THRHD_S));//wjl 
+        #if UART_HW_CTS
+        SET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN);  //add this sentense to add a tx flow control via MTCK( CTS )
+        #endif
+        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));//TrigLvl default val == 1
+    }
+    //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|UART_RXFIFO_OVF_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
+*******************************************************************************/
+ STATUS 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);
+    return OK;
+}
+
+/******************************************************************************
+ * 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
+*******************************************************************************/
+LOCAL void ICACHE_FLASH_ATTR
+uart1_write_char(char c)
+{
+    if (c == '\n'){
+        uart_tx_one_char(UART1, '\r');
+        uart_tx_one_char(UART1, '\n');
+    }else if (c == '\r'){
+    
+    }else{
+        uart_tx_one_char(UART1, c);
+    }
+}
+
+//os_printf output to fifo or to the tx buffer
+LOCAL void ICACHE_FLASH_ATTR
+uart0_write_char_no_wait(char c)
+{
+#if UART_BUFF_EN    //send to uart0 fifo but do not wait 
+    uint8 chr;
+    if (c == '\n'){
+        chr = '\r';
+        tx_buff_enq(&chr, 1);
+        chr = '\n';
+        tx_buff_enq(&chr, 1);
+    }else if (c == '\r'){
+    
+    }else{
+        tx_buff_enq(&c,1);
+    }
+#else //send to uart tx buffer
+    if (c == '\n'){
+        uart_tx_one_char_no_wait(UART0, '\r');
+        uart_tx_one_char_no_wait(UART0, '\n');
+    }else if (c == '\r'){
+    
+    }
+    else{
+        uart_tx_one_char_no_wait(UART0, c);
+    }
+#endif
+}
+
+/******************************************************************************
+ * FunctionName : uart0_tx_buffer
+ * Description  : use uart0 to transfer buffer
+ * Parameters   : uint8 *buf - point to send buffer
+ *                uint16 len - buffer len
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+uart0_tx_buffer(uint8 *buf, uint16 len)
+{
+    uint16 i;
+    for (i = 0; i < len; i++)
+    {
+        uart_tx_one_char(UART0, buf[i]);
+    }
+}
+
+/******************************************************************************
+ * FunctionName : uart0_sendStr
+ * Description  : use uart0 to transfer buffer
+ * Parameters   : uint8 *buf - point to send buffer
+ *                uint16 len - buffer len
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+uart0_sendStr(const char *str)
+{
+    while(*str){
+        uart_tx_one_char(UART0, *str++);
+    }
+}
+void at_port_print(const char *str) __attribute__((alias("uart0_sendStr")));
+/******************************************************************************
+ * 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
+*******************************************************************************/
+LOCAL 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 RcvChar;
+    uint8 uart_no = UART0;//UartDev.buff_uart_no;
+    uint8 fifo_len = 0;
+    uint8 buf_idx = 0;
+    uint8 temp,cnt;
+    //RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
+    
+    	/*ATTENTION:*/
+	/*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/
+	/*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
+	/*IF NOT , POST AN EVENT AND PROCESS IN SYSTEM TASK */
+    if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)){
+        DBG1("FRM_ERR\r\n");
+        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
+    }else if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)){
+        DBG("f");
+        uart_rx_intr_disable(UART0);
+        WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
+        system_os_post(uart_recvTaskPrio, 0, 0);
+    }else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)){
+        DBG("t");
+        uart_rx_intr_disable(UART0);
+        WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
+        system_os_post(uart_recvTaskPrio, 0, 0);
+    }else if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)){
+        DBG("e");
+	/* to output uart data from uart buffer directly in empty interrupt handler*/
+	/*instead of processing in system event, in order not to wait for current task/function to quit */
+	/*ATTENTION:*/
+	/*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/
+	/*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
+	CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
+	#if UART_BUFF_EN
+		tx_start_uart_buffer(UART0);
+	#endif
+        //system_os_post(uart_recvTaskPrio, 1, 0);
+        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
+        
+    }else if(UART_RXFIFO_OVF_INT_ST  == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)){
+        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
+        DBG1("RX OVF!!\r\n");
+    }
+
+}
+
+/******************************************************************************
+ * FunctionName : uart_init
+ * Description  : user interface for init uart
+ * Parameters   : UartBautRate uart0_br - uart0 bautrate
+ *                UartBautRate uart1_br - uart1 bautrate
+ * Returns      : NONE
+*******************************************************************************/
+#if UART_SELFTEST&UART_BUFF_EN
+os_timer_t buff_timer_t;
+void ICACHE_FLASH_ATTR
+uart_test_rx()
+{
+    uint8 uart_buf[128]={0};
+    uint16 len = 0;
+    len = rx_buff_deq(uart_buf, 128 );
+    tx_buff_enq(uart_buf,len);
+}
+#endif
+
+LOCAL void ICACHE_FLASH_ATTR ///////
+uart_recvTask(os_event_t *events)
+{
+    if(events->sig == 0){
+    #if  UART_BUFF_EN  
+        Uart_rx_buff_enq();
+    #else
+        uint8 fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+        uint8 d_tmp = 0;
+        uint8 idx=0;
+        for(idx=0;idx<fifo_len;idx++) {
+            d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
+            uart_tx_one_char(UART0, d_tmp);
+        }
+        WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+        uart_rx_intr_enable(UART0);
+    #endif
+    }else if(events->sig == 1){
+    #if UART_BUFF_EN
+	 //already move uart buffer output to uart empty interrupt
+        //tx_start_uart_buffer(UART0);
+    #else 
+    
+    #endif
+    }
+}
+
+void ICACHE_FLASH_ATTR
+uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
+{
+    /*this is a example to process uart data from task,please change the priority to fit your application task if exists*/
+    system_os_task(uart_recvTask, uart_recvTaskPrio, uart_recvTaskQueue, uart_recvTaskQueueLen);  //demo with a task to process the uart data
+    
+    UartDev.baut_rate = uart0_br;
+    uart_config(UART0);
+    UartDev.baut_rate = uart1_br;
+    uart_config(UART1);
+    ETS_UART_INTR_ENABLE();
+    
+    #if UART_BUFF_EN
+    pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
+    pRxBuffer = Uart_Buf_Init(UART_RX_BUFFER_SIZE);
+    #endif
+
+
+    /*option 1: use default print, output from uart0 , will wait some time if fifo is full */
+    //do nothing...
+
+    /*option 2: output from uart1,uart1 output will not wait , just for output debug info */
+    /*os_printf output uart data via uart1(GPIO2)*/
+    //os_install_putc1((void *)uart1_write_char);    //use this one to output debug information via uart1 //
+
+    /*option 3: output from uart0 will skip current byte if fifo is full now... */
+    /*see uart0_write_char_no_wait:you can output via a buffer or output directly */
+    /*os_printf output uart data via uart0 or uart buffer*/
+    //os_install_putc1((void *)uart0_write_char_no_wait);  //use this to print via uart0
+    
+    #if UART_SELFTEST&UART_BUFF_EN
+    os_timer_disarm(&buff_timer_t);
+    os_timer_setfn(&buff_timer_t, uart_test_rx , NULL);   //a demo to process the data in uart rx buffer
+    os_timer_arm(&buff_timer_t,10,1);
+    #endif
+}
+
+void ICACHE_FLASH_ATTR
+uart_reattach()
+{
+    uart_init(BIT_RATE_115200, BIT_RATE_115200);
+}
+
+/******************************************************************************
+ * FunctionName : uart_tx_one_char_no_wait
+ * Description  : uart tx a single char without waiting for fifo 
+ * Parameters   : uint8 uart - uart port
+ *                uint8 TxChar - char to tx
+ * Returns      : STATUS
+*******************************************************************************/
+STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
+{
+    uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
+    if (fifo_cnt < 126) {
+        WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
+    }
+    return OK;
+}
+
+STATUS uart0_tx_one_char_no_wait(uint8 TxChar)
+{
+    uint8 fifo_cnt = (( READ_PERI_REG(UART_STATUS(UART0))>>UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);
+    if (fifo_cnt < 126) {
+        WRITE_PERI_REG(UART_FIFO(UART0) , TxChar);
+    }
+    return OK;
+}
+
+
+/******************************************************************************
+ * FunctionName : uart1_sendStr_no_wait
+ * Description  : uart tx a string without waiting for every char, used for print debug info which can be lost
+ * Parameters   : const char *str - string to be sent
+ * Returns      : NONE
+*******************************************************************************/
+void uart1_sendStr_no_wait(const char *str)
+{
+    while(*str){
+        uart_tx_one_char_no_wait(UART1, *str++);
+    }
+}
+
+
+#if UART_BUFF_EN
+/******************************************************************************
+ * FunctionName : Uart_Buf_Init
+ * Description  : tx buffer enqueue: fill a first linked buffer 
+ * Parameters   : char *pdata - data point  to be enqueue
+ * Returns      : NONE
+*******************************************************************************/
+struct UartBuffer* ICACHE_FLASH_ATTR
+Uart_Buf_Init(uint32 buf_size)
+{
+    uint32 heap_size = system_get_free_heap_size();
+    if(heap_size <=buf_size){
+        DBG1("no buf for uart\n\r");
+        return NULL;
+    }else{
+        DBG("test heap size: %d\n\r",heap_size);
+        struct UartBuffer* pBuff = (struct UartBuffer* )os_malloc(sizeof(struct UartBuffer));
+        pBuff->UartBuffSize = buf_size;
+        pBuff->pUartBuff = (uint8*)os_malloc(pBuff->UartBuffSize);
+        pBuff->pInPos = pBuff->pUartBuff;
+        pBuff->pOutPos = pBuff->pUartBuff;
+        pBuff->Space = pBuff->UartBuffSize;
+        pBuff->BuffState = OK;
+        pBuff->nextBuff = NULL;
+        pBuff->TcpControl = RUN;
+        return pBuff;
+    }
+}
+
+
+//copy uart buffer
+LOCAL void Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len)
+{
+    if(data_len == 0) return ;
+    
+    uint16 tail_len = pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos ;
+    if(tail_len >= data_len){  //do not need to loop back  the queue
+        os_memcpy(pCur->pInPos , pdata , data_len );
+        pCur->pInPos += ( data_len );
+        pCur->pInPos = (pCur->pUartBuff +  (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
+        pCur->Space -=data_len;
+    }else{
+        os_memcpy(pCur->pInPos, pdata, tail_len);
+        pCur->pInPos += ( tail_len );
+        pCur->pInPos = (pCur->pUartBuff +  (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
+        pCur->Space -=tail_len;
+        os_memcpy(pCur->pInPos, pdata+tail_len , data_len-tail_len);
+        pCur->pInPos += ( data_len-tail_len );
+        pCur->pInPos = (pCur->pUartBuff +  (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize );
+        pCur->Space -=( data_len-tail_len);
+    }
+    
+}
+
+/******************************************************************************
+ * FunctionName : uart_buf_free
+ * Description  : deinit of the tx buffer
+ * Parameters   : struct UartBuffer* pTxBuff - tx buffer struct pointer
+ * Returns      : NONE
+*******************************************************************************/
+void ICACHE_FLASH_ATTR
+uart_buf_free(struct UartBuffer* pBuff)
+{
+    os_free(pBuff->pUartBuff);
+    os_free(pBuff);
+}
+
+
+//rx buffer dequeue
+uint16 ICACHE_FLASH_ATTR
+rx_buff_deq(char* pdata, uint16 data_len )
+{
+    uint16 buf_len =  (pRxBuffer->UartBuffSize- pRxBuffer->Space);
+    uint16 tail_len = pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize - pRxBuffer->pOutPos ;
+    uint16 len_tmp = 0;
+    len_tmp = ((data_len > buf_len)?buf_len:data_len);
+    if(pRxBuffer->pOutPos <= pRxBuffer->pInPos){
+        os_memcpy(pdata, pRxBuffer->pOutPos,len_tmp);
+        pRxBuffer->pOutPos+= len_tmp;
+        pRxBuffer->Space += len_tmp;
+    }else{
+        if(len_tmp>tail_len){
+            os_memcpy(pdata, pRxBuffer->pOutPos, tail_len);
+            pRxBuffer->pOutPos += tail_len;
+            pRxBuffer->pOutPos = (pRxBuffer->pUartBuff +  (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
+            pRxBuffer->Space += tail_len;
+            
+            os_memcpy(pdata+tail_len , pRxBuffer->pOutPos, len_tmp-tail_len);
+            pRxBuffer->pOutPos+= ( len_tmp-tail_len );
+            pRxBuffer->pOutPos= (pRxBuffer->pUartBuff +  (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
+            pRxBuffer->Space +=( len_tmp-tail_len);                
+        }else{
+            //os_printf("case 3 in rx deq\n\r");
+            os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
+            pRxBuffer->pOutPos += len_tmp;
+            pRxBuffer->pOutPos = (pRxBuffer->pUartBuff +  (pRxBuffer->pOutPos- pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize );
+            pRxBuffer->Space += len_tmp;
+        }
+    }
+    if(pRxBuffer->Space >= UART_FIFO_LEN){
+        uart_rx_intr_enable(UART0);
+    }
+    return len_tmp; 
+}
+
+
+//move data from uart fifo to rx buffer
+void Uart_rx_buff_enq()
+{
+    uint8 fifo_len,buf_idx;
+    uint8 fifo_data;
+    #if 1
+    fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+    if(fifo_len >= pRxBuffer->Space){
+        os_printf("buf full!!!\n\r");            
+    }else{
+        buf_idx=0;
+        while(buf_idx < fifo_len){
+            buf_idx++;
+            fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
+            *(pRxBuffer->pInPos++) = fifo_data;
+            if(pRxBuffer->pInPos == (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize)){
+                pRxBuffer->pInPos = pRxBuffer->pUartBuff;
+            }            
+        }
+        pRxBuffer->Space -= fifo_len ;
+        if(pRxBuffer->Space >= UART_FIFO_LEN){
+            //os_printf("after rx enq buf enough\n\r");
+            uart_rx_intr_enable(UART0);
+        }
+    }
+    #endif
+}
+
+
+//fill the uart tx buffer
+void ICACHE_FLASH_ATTR
+tx_buff_enq(char* pdata, uint16 data_len )
+{
+    CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
+
+    if(pTxBuffer == NULL){
+        DBG1("\n\rnull, create buffer struct\n\r");
+        pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
+        if(pTxBuffer!= NULL){
+            Uart_Buf_Cpy(pTxBuffer ,  pdata,  data_len );
+        }else{
+            DBG1("uart tx MALLOC no buf \n\r");
+        }
+    }else{
+        if(data_len <= pTxBuffer->Space){
+        Uart_Buf_Cpy(pTxBuffer ,  pdata,  data_len);
+        }else{
+            DBG1("UART TX BUF FULL!!!!\n\r");
+        }
+    }
+    #if 0
+    if(pTxBuffer->Space <= URAT_TX_LOWER_SIZE){
+	    set_tcp_block();        
+    }
+    #endif
+    SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD)<<UART_TXFIFO_EMPTY_THRHD_S);
+    SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
+}
+
+
+
+//--------------------------------
+LOCAL void tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len,  uint8 uart_no)
+{
+    uint8 i;
+    for(i = 0; i<data_len;i++){
+        WRITE_PERI_REG(UART_FIFO(uart_no) , *(pTxBuff->pOutPos++));
+        if(pTxBuff->pOutPos == (pTxBuff->pUartBuff + pTxBuff->UartBuffSize)){
+            pTxBuff->pOutPos = pTxBuff->pUartBuff;
+        }
+    }
+    pTxBuff->pOutPos = (pTxBuff->pUartBuff +  (pTxBuff->pOutPos - pTxBuff->pUartBuff) % pTxBuff->UartBuffSize );
+    pTxBuff->Space += data_len;
+}
+
+
+/******************************************************************************
+ * FunctionName : tx_start_uart_buffer
+ * Description  : get data from the tx buffer and fill the uart tx fifo, co-work with the uart fifo empty interrupt
+ * Parameters   : uint8 uart_no - uart port num
+ * Returns      : NONE
+*******************************************************************************/
+void tx_start_uart_buffer(uint8 uart_no)
+{
+    uint8 tx_fifo_len = (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT;
+    uint8 fifo_remain = UART_FIFO_LEN - tx_fifo_len ;
+    uint8 len_tmp;
+    uint16 tail_ptx_len,head_ptx_len,data_len;
+    //struct UartBuffer* pTxBuff = *get_buff_prt();
+    
+    if(pTxBuffer){      
+        data_len = (pTxBuffer->UartBuffSize - pTxBuffer->Space);
+        if(data_len > fifo_remain){
+            len_tmp = fifo_remain;
+            tx_fifo_insert( pTxBuffer,len_tmp,uart_no);
+            SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
+        }else{
+            len_tmp = data_len;
+            tx_fifo_insert( pTxBuffer,len_tmp,uart_no);
+        }
+    }else{
+        DBG1("pTxBuff null \n\r");
+    }
+}
+
+#endif
+
+
+void uart_rx_intr_disable(uint8 uart_no)
+{
+#if 1
+    CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+#else
+    ETS_UART_INTR_DISABLE();
+#endif
+}
+
+void uart_rx_intr_enable(uint8 uart_no)
+{
+#if 1
+    SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+#else
+    ETS_UART_INTR_ENABLE();
+#endif
+}
+
+
+//========================================================
+LOCAL void
+uart0_write_char(char c)
+{
+    if (c == '\n') {
+        uart_tx_one_char(UART0, '\r');
+        uart_tx_one_char(UART0, '\n');
+    } else if (c == '\r') {
+    } else {
+        uart_tx_one_char(UART0, c);
+    }
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len) 
+{
+    SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_BIT_NUM,len,UART_BIT_NUM_S);
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num) 
+{
+    SET_PERI_REG_BITS(UART_CONF0(uart_no),UART_STOP_BIT_NUM,bit_num,UART_STOP_BIT_NUM_S);
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask) 
+{
+    CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK);
+    SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask);
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetParity(uint8 uart_no, UartParityMode Parity_mode) 
+{
+    CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY |UART_PARITY_EN);
+    if(Parity_mode==NONE_BITS){
+    }else{
+        SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode|UART_PARITY_EN);
+    }
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetBaudrate(uint8 uart_no,uint32 baud_rate)
+{
+    uart_div_modify(uart_no, UART_CLK_FREQ /baud_rate);
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh)
+{
+    if(flow_ctrl&USART_HardwareFlowControl_RTS){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
+        SET_PERI_REG_BITS(UART_CONF1(uart_no),UART_RX_FLOW_THRHD,rx_thresh,UART_RX_FLOW_THRHD_S);
+        SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
+    }else{
+        CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
+    }
+    if(flow_ctrl&USART_HardwareFlowControl_CTS){
+        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
+        SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
+    }else{
+        CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
+    }
+}
+
+void ICACHE_FLASH_ATTR
+UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us) //do not use if tx flow control enabled
+{
+    uint32 t_s = system_get_time();
+    while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)){
+		
+        if(( system_get_time() - t_s )> time_out_us){
+            break;
+        }
+	WRITE_PERI_REG(0X60000914, 0X73);//WTD
+
+    }
+}
+
+
+bool ICACHE_FLASH_ATTR
+UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us)
+{
+    uint32 t_start = system_get_time();
+    uint8 tx_fifo_len;
+    uint32 tx_buff_len;
+    while(1){
+        tx_fifo_len =( (READ_PERI_REG(UART_STATUS(uart_no))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT);
+        if(pTxBuffer){
+            tx_buff_len = ((pTxBuffer->UartBuffSize)-(pTxBuffer->Space));
+        }else{
+            tx_buff_len = 0;
+        }
+		
+        if( tx_fifo_len==0 && tx_buff_len==0){
+            return TRUE;
+        }
+        if( system_get_time() - t_start > time_out_us){
+            return FALSE;
+        }
+	WRITE_PERI_REG(0X60000914, 0X73);//WTD
+    }    
+}
+
+
+void ICACHE_FLASH_ATTR
+UART_ResetFifo(uint8 uart_no)
+{
+    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);
+}
+
+void ICACHE_FLASH_ATTR
+UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask)
+{
+    WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask);
+}
+
+void ICACHE_FLASH_ATTR
+UART_SetIntrEna(uint8 uart_no,uint32 ena_mask)
+{
+    SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask);
+}
+
+
+void ICACHE_FLASH_ATTR
+UART_SetPrintPort(uint8 uart_no)
+{
+    if(uart_no==1){
+        os_install_putc1(uart1_write_char);
+    }else{
+        /*option 1: do not wait if uart fifo is full,drop current character*/
+        os_install_putc1(uart0_write_char_no_wait);
+	/*option 2: wait for a while if uart fifo is full*/
+	os_install_putc1(uart0_write_char);
+    }
+}
+
+
+//========================================================
+
+
+/*test code*/
+void ICACHE_FLASH_ATTR
+uart_init_2(UartBautRate uart0_br, UartBautRate uart1_br)
+{
+    // rom use 74880 baut_rate, here reinitialize
+    UartDev.baut_rate = uart0_br;
+    UartDev.exist_parity = STICK_PARITY_EN;
+    UartDev.parity = EVEN_BITS;
+    UartDev.stop_bits = ONE_STOP_BIT;
+    UartDev.data_bits = EIGHT_BITS;
+	
+    uart_config(UART0);
+    UartDev.baut_rate = uart1_br;
+    uart_config(UART1);
+    ETS_UART_INTR_ENABLE();
+
+    // install uart1 putc callback
+    os_install_putc1((void *)uart1_write_char);//print output at UART1
+}
+
+

+ 42 - 0
gdbstub/Makefile

@@ -0,0 +1,42 @@
+
+#############################################################
+# 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 = libgdbstub.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 +=
+
+#############################################################
+# 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
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile

+ 785 - 0
gdbstub/gdbstub.c

@@ -0,0 +1,785 @@
+/******************************************************************************
+ * Copyright 2015 Espressif Systems
+ *
+ * Description: A stub to make the ESP8266 debuggable by GDB over the serial
+ * port.
+ *
+ * License: ESPRESSIF MIT License
+ *******************************************************************************/
+
+#include "ets_sys.h"
+#include "eagle_soc.h"
+#include "c_types.h"
+#include "gpio.h"
+#include "xtensa/corebits.h"
+
+#include "gdbstub/gdbstub.h"
+#include "gdbstub/gdbstub-entry.h"
+#include "gdbstub/gdbstub-cfg.h"
+
+
+//From xtruntime-frames.h
+struct XTensa_exception_frame_s {
+	uint32_t pc;
+	uint32_t ps;
+	uint32_t sar;
+	uint32_t vpri;
+	uint32_t a0;
+	uint32_t a[14]; //a2..a15
+//These are added manually by the exception code; the HAL doesn't set these on an exception.
+	uint32_t litbase;
+	uint32_t sr176;
+	uint32_t sr208;
+	uint32_t a1;
+	 //'reason' is abused for both the debug and the exception vector: if bit 7 is set,
+	//this contains an exception reason, otherwise it contains a debug vector bitmap.
+	uint32_t reason;
+};
+
+
+struct XTensa_rtos_int_frame_s {
+	uint32_t exitPtr;
+	uint32_t pc;
+	uint32_t ps;
+	uint32_t a[16];
+	uint32_t sar;
+};
+
+#if GDBSTUB_FREERTOS
+/*
+Definitions for FreeRTOS. This redefines some os_* functions to use their non-os* counterparts. It
+also sets up some function pointers for ROM functions that aren't in the FreeRTOS ld files.
+*/
+#include <string.h>
+#include <stdio.h>
+void _xt_isr_attach(int inum, void *fn);
+void _xt_isr_unmask(int inum);
+void os_install_putc1(void (*p)(char c));
+#define os_printf(...) printf(__VA_ARGS__)
+#define os_memcpy(a,b,c) memcpy(a,b,c)
+typedef void wdtfntype();
+static wdtfntype *ets_wdt_disable=(wdtfntype *)0x400030f0;
+static wdtfntype *ets_wdt_enable=(wdtfntype *)0x40002fa0;
+
+#else
+/*
+OS-less SDK defines. Defines some headers for things that aren't in the include files, plus
+the xthal stack frame struct.
+*/
+#include "osapi.h"
+#include "user_interface.h"
+
+void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame));
+int os_printf_plus(const char *format, ...)  __attribute__ ((format (printf, 1, 2)));
+
+#endif
+
+#define EXCEPTION_GDB_SP_OFFSET 0x100
+
+
+//We need some UART register defines.
+#define ETS_UART_INUM 5
+#define REG_UART_BASE( i )  (0x60000000+(i)*0xf00)
+#define UART_STATUS( i )                        (REG_UART_BASE( i ) + 0x1C)
+#define UART_RXFIFO_CNT 0x000000FF
+#define UART_RXFIFO_CNT_S 0
+#define UART_TXFIFO_CNT 0x000000FF
+#define UART_TXFIFO_CNT_S                   16
+#define UART_FIFO( i )                          (REG_UART_BASE( i ) + 0x0)
+#define UART_INT_ENA(i)                     (REG_UART_BASE(i) + 0xC)
+#define UART_INT_CLR(i)                 (REG_UART_BASE(i) + 0x10)
+#define UART_RXFIFO_TOUT_INT_ENA            (BIT(8))
+#define UART_RXFIFO_FULL_INT_ENA            (BIT(0))
+#define UART_RXFIFO_TOUT_INT_CLR            (BIT(8))
+#define UART_RXFIFO_FULL_INT_CLR            (BIT(0))
+
+
+
+
+//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
+//implies a minimum size of about 190 bytes.
+#define PBUFLEN 256
+//Length of gdb stdout buffer, for console redirection
+#define OBUFLEN 32
+
+//The asm stub saves the Xtensa registers here when a debugging exception happens.
+struct XTensa_exception_frame_s gdbstub_savedRegs;
+#if GDBSTUB_USE_OWN_STACK
+//This is the debugging exception stack.
+int exceptionStack[256];
+#endif
+
+static unsigned char cmd[PBUFLEN];		//GDB command input buffer
+static char chsum;						//Running checksum of the output packet
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+static unsigned char obuf[OBUFLEN];		//GDB stdout buffer
+static int obufpos=0;					//Current position in the buffer
+#endif
+static int32_t singleStepPs=-1;			//Stores ps when single-stepping instruction. -1 when not in use.
+
+//Small function to feed the hardware watchdog. Needed to stop the ESP from resetting
+//due to a watchdog timeout while reading a command.
+static void ATTR_GDBFN keepWDTalive() {
+	uint64_t *wdtval=(uint64_t*)0x3ff21048;
+	uint64_t *wdtovf=(uint64_t*)0x3ff210cc;
+	int *wdtctl=(int*)0x3ff210c8;
+	*wdtovf=*wdtval+1600000;
+	*wdtctl|=(1<<31);
+}
+
+//Receive a char from the uart. Uses polling and feeds the watchdog.
+static int ATTR_GDBFN gdbRecvChar() {
+	int i;
+	while (((READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) {
+		keepWDTalive();
+	}
+	i=READ_PERI_REG(UART_FIFO(0));
+	return i;
+}
+
+//Send a char to the uart.
+static void ATTR_GDBFN gdbSendChar(char c) {
+	while (((READ_PERI_REG(UART_STATUS(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
+	WRITE_PERI_REG(UART_FIFO(0), c);
+}
+
+//Send the start of a packet; reset checksum calculation.
+static void ATTR_GDBFN gdbPacketStart() {
+	chsum=0;
+	gdbSendChar('$');
+}
+
+//Send a char as part of a packet
+static void ATTR_GDBFN gdbPacketChar(char c) {
+	if (c=='#' || c=='$' || c=='}' || c=='*') {
+		gdbSendChar('}');
+		gdbSendChar(c^0x20);
+		chsum+=(c^0x20)+'}';
+	} else {
+		gdbSendChar(c);
+		chsum+=c;
+	}
+}
+
+//Send a string as part of a packet
+static void ATTR_GDBFN gdbPacketStr(char *c) {
+	while (*c!=0) {
+		gdbPacketChar(*c);
+		c++;
+	}
+}
+
+//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
+static void ATTR_GDBFN gdbPacketHex(int val, int bits) {
+	char hexChars[]="0123456789abcdef";
+	int i;
+	for (i=bits; i>0; i-=4) {
+		gdbPacketChar(hexChars[(val>>(i-4))&0xf]);
+	}
+}
+
+//Finish sending a packet.
+static void ATTR_GDBFN gdbPacketEnd() {
+	gdbSendChar('#');
+	gdbPacketHex(chsum, 8);
+}
+
+//Error states used by the routines that grab stuff from the incoming gdb packet
+#define ST_ENDPACKET -1
+#define ST_ERR -2
+#define ST_OK -3
+#define ST_CONT -4
+
+//Grab a hex value from the gdb packet. Ptr will get positioned on the end
+//of the hex string, as far as the routine has read into it. Bits/4 indicates
+//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much
+//hex chars as possible.
+static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) {
+	int i;
+	int no;
+	unsigned int v=0;
+	char c;
+	no=bits/4;
+	if (bits==-1) no=64;
+	for (i=0; i<no; i++) {
+		c=**ptr;
+		(*ptr)++;
+		if (c>='0' && c<='9') {
+			v<<=4;
+			v|=(c-'0');
+		} else if (c>='A' && c<='F') {
+			v<<=4;
+			v|=(c-'A')+10;
+		} else if (c>='a' && c<='f') {
+			v<<=4;
+			v|=(c-'a')+10;
+		} else if (c=='#') {
+			if (bits==-1) {
+				(*ptr)--;
+				return v;
+			}
+			return ST_ENDPACKET;
+		} else {
+			if (bits==-1) {
+				(*ptr)--;
+				return v;
+			}
+			return ST_ERR;
+		}
+	}
+	return v;
+}
+
+//Swap an int into the form gdb wants it
+static int ATTR_GDBFN iswap(int i) {
+	int r;
+	r=((i>>24)&0xff);
+	r|=((i>>16)&0xff)<<8;
+	r|=((i>>8)&0xff)<<16;
+	r|=((i>>0)&0xff)<<24;
+	return r;
+}
+
+//Read a byte from the ESP8266 memory.
+static unsigned char ATTR_GDBFN readbyte(unsigned int p) {
+	int *i=(int*)(p&(~3));
+	if (p<0x20000000 || p>=0x60000000) return -1;
+	return *i>>((p&3)*8);
+}
+
+//Write a byte to the ESP8266 memory.
+static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d) {
+	int *i=(int*)(p&(~3));
+	if (p<0x20000000 || p>=0x60000000) return;
+	if ((p&3)==0) *i=(*i&0xffffff00)|(d<<0);
+	if ((p&3)==1) *i=(*i&0xffff00ff)|(d<<8);
+	if ((p&3)==2) *i=(*i&0xff00ffff)|(d<<16);
+	if ((p&3)==3) *i=(*i&0x00ffffff)|(d<<24);
+}
+
+//Returns 1 if it makes sense to write to addr p
+static int ATTR_GDBFN validWrAddr(int p) {
+	if (p>=0x3ff00000 && p<0x40000000) return 1;
+	if (p>=0x40100000 && p<0x40140000) return 1;
+	if (p>=0x60000000 && p<0x60002000) return 1;
+	return 0;
+}
+
+/*
+Register file in the format lx106 gdb port expects it.
+Inspired by gdb/regformats/reg-xtensa.dat from
+https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar
+As decoded by Cesanta.
+*/
+struct regfile {
+	uint32_t a[16];
+	uint32_t pc;
+	uint32_t sar;
+	uint32_t litbase;
+	uint32_t sr176;
+	uint32_t sr208;
+	uint32_t ps;
+};
+
+
+//Send the reason execution is stopped to GDB.
+static void ATTR_GDBFN sendReason() {
+#if 0
+	char *reason=""; //default
+#endif
+	//exception-to-signal mapping
+	char exceptionSignal[]={4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
+	int i=0;
+	gdbPacketStart();
+	gdbPacketChar('T');
+	if (gdbstub_savedRegs.reason==0xff) {
+		gdbPacketHex(2, 8); //sigint
+	} else if (gdbstub_savedRegs.reason&0x80) {
+		//We stopped because of an exception. Convert exception code to a signal number and send it.
+		i=gdbstub_savedRegs.reason&0x7f;
+		if (i<sizeof(exceptionSignal)) gdbPacketHex(exceptionSignal[i], 8); else gdbPacketHex(11, 8);
+	} else {
+		//We stopped because of a debugging exception.
+		gdbPacketHex(5, 8); //sigtrap
+//Current Xtensa GDB versions don't seem to request this, so let's leave it off.
+#if 0
+		if (gdbstub_savedRegs.reason&(1<<0)) reason="break";
+		if (gdbstub_savedRegs.reason&(1<<1)) reason="hwbreak";
+		if (gdbstub_savedRegs.reason&(1<<2)) reason="watch";
+		if (gdbstub_savedRegs.reason&(1<<3)) reason="swbreak";
+		if (gdbstub_savedRegs.reason&(1<<4)) reason="swbreak";
+
+		gdbPacketStr(reason);
+		gdbPacketChar(':');
+		//ToDo: watch: send address
+#endif
+	}
+	gdbPacketEnd();
+}
+
+//Handle a command as received from GDB.
+static int ATTR_GDBFN gdbHandleCommand(unsigned char *cmd, int len) {
+	//Handle a command
+	int i, j, k;
+	unsigned char *data=cmd+1;
+	if (cmd[0]=='g') {		//send all registers to gdb
+		gdbPacketStart();
+		gdbPacketHex(iswap(gdbstub_savedRegs.a0), 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.a1), 32);
+		for (i=2; i<16; i++) gdbPacketHex(iswap(gdbstub_savedRegs.a[i-2]), 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.pc), 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.sar), 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.litbase), 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.sr176), 32);
+		gdbPacketHex(0, 32);
+		gdbPacketHex(iswap(gdbstub_savedRegs.ps), 32);
+		gdbPacketEnd();
+	} else if (cmd[0]=='G') {	//receive content for all registers from gdb
+		gdbstub_savedRegs.a0=iswap(gdbGetHexVal(&data, 32));
+		gdbstub_savedRegs.a1=iswap(gdbGetHexVal(&data, 32));
+		for (i=2; i<16; i++) gdbstub_savedRegs.a[i-2]=iswap(gdbGetHexVal(&data, 32));
+		gdbstub_savedRegs.pc=iswap(gdbGetHexVal(&data, 32));
+		gdbstub_savedRegs.sar=iswap(gdbGetHexVal(&data, 32));
+		gdbstub_savedRegs.litbase=iswap(gdbGetHexVal(&data, 32));
+		gdbstub_savedRegs.sr176=iswap(gdbGetHexVal(&data, 32));
+		gdbGetHexVal(&data, 32);
+		gdbstub_savedRegs.ps=iswap(gdbGetHexVal(&data, 32));
+		gdbPacketStart();
+		gdbPacketStr("OK");
+		gdbPacketEnd();
+	} else if (cmd[0]=='m') {	//read memory to gdb
+		i=gdbGetHexVal(&data, -1);
+		data++;
+		j=gdbGetHexVal(&data, -1);
+		gdbPacketStart();
+		for (k=0; k<j; k++) {
+			gdbPacketHex(readbyte(i++), 8);
+		}
+		gdbPacketEnd();
+	} else if (cmd[0]=='M') {	//write memory from gdb
+		i=gdbGetHexVal(&data, -1); //addr
+		data++; //skip ,
+		j=gdbGetHexVal(&data, -1); //length
+		data++; //skip :
+		if (validWrAddr(i) && validWrAddr(i+j)) {
+			for (k=0; k<j; k++) {
+				writeByte(i, gdbGetHexVal(&data, 8));
+				i++;
+			}
+			//Make sure caches are up-to-date. Procedure according to Xtensa ISA document, ISYNC inst desc.
+			asm volatile("ISYNC\nISYNC\n");
+			gdbPacketStart();
+			gdbPacketStr("OK");
+			gdbPacketEnd();
+		} else {
+			//Trying to do a software breakpoint on a flash proc, perhaps?
+			gdbPacketStart();
+			gdbPacketStr("E01");
+			gdbPacketEnd();
+		}
+	} else if (cmd[0]=='?') {	//Reply with stop reason
+		sendReason();
+//	} else if (strncmp(cmd, "vCont?", 6)==0) {
+//		gdbPacketStart();
+//		gdbPacketStr("vCont;c;s");
+//		gdbPacketEnd();
+	} else if (strncmp((char*)cmd, "vCont;c", 7)==0 || cmd[0]=='c') {	//continue execution
+		return ST_CONT;
+	} else if (strncmp((char*)cmd, "vCont;s", 7)==0 || cmd[0]=='s') {	//single-step instruction
+		//Single-stepping can go wrong if an interrupt is pending, especially when it is e.g. a task switch:
+		//the ICOUNT register will overflow in the task switch code. That is why we disable interupts when
+		//doing single-instruction stepping.
+		singleStepPs=gdbstub_savedRegs.ps;
+		gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps & ~0xf)|(XCHAL_DEBUGLEVEL-1);
+		gdbstub_icount_ena_single_step();
+		return ST_CONT;
+	} else if (cmd[0]=='q') {	//Extended query
+		if (strncmp((char*)&cmd[1], "Supported", 9)==0) { //Capabilities query
+			gdbPacketStart();
+			gdbPacketStr("swbreak+;hwbreak+;PacketSize=255");
+			gdbPacketEnd();
+		} else {
+			//We don't support other queries.
+			gdbPacketStart();
+			gdbPacketEnd();
+			return ST_ERR;
+		}
+	} else if (cmd[0]=='Z') {	//Set hardware break/watchpoint.
+		data+=2; //skip 'x,'
+		i=gdbGetHexVal(&data, -1);
+		data++; //skip ','
+		j=gdbGetHexVal(&data, -1);
+		gdbPacketStart();
+		if (cmd[1]=='1') {	//Set breakpoint
+			if (gdbstub_set_hw_breakpoint(i, j)) {
+				gdbPacketStr("OK");
+			} else {
+				gdbPacketStr("E01");
+			}
+		} else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //Set watchpoint
+			int access=0;
+			int mask=0;
+			if (cmd[1]=='2') access=2; //write
+			if (cmd[1]=='3') access=1; //read
+			if (cmd[1]=='4') access=3; //access
+			if (j==1) mask=0x3F;
+			if (j==2) mask=0x3E;
+			if (j==4) mask=0x3C;
+			if (j==8) mask=0x38;
+			if (j==16) mask=0x30;
+			if (j==32) mask=0x20;
+			if (j==64) mask=0x00;
+			if (mask!=0 && gdbstub_set_hw_watchpoint(i,mask, access)) {
+				gdbPacketStr("OK");
+			} else {
+				gdbPacketStr("E01");
+			}
+		}
+		gdbPacketEnd();
+	} else if (cmd[0]=='z') {	//Clear hardware break/watchpoint
+		data+=2; //skip 'x,'
+		i=gdbGetHexVal(&data, -1);
+		data++; //skip ','
+		j=gdbGetHexVal(&data, -1);
+		gdbPacketStart();
+		if (cmd[1]=='1') {	//hardware breakpoint
+			if (gdbstub_del_hw_breakpoint(i)) {
+				gdbPacketStr("OK");
+			} else {
+				gdbPacketStr("E01");
+			}
+		} else if (cmd[1]=='2' || cmd[1]=='3' || cmd[1]=='4') { //hardware watchpoint
+			if (gdbstub_del_hw_watchpoint(i)) {
+				gdbPacketStr("OK");
+			} else {
+				gdbPacketStr("E01");
+			}
+		}
+		gdbPacketEnd();
+	} else {
+		//We don't recognize or support whatever GDB just sent us.
+		gdbPacketStart();
+		gdbPacketEnd();
+		return ST_ERR;
+	}
+	return ST_OK;
+}
+
+
+//Lower layer: grab a command packet and check the checksum
+//Calls gdbHandleCommand on the packet if the checksum is OK
+//Returns ST_OK on success, ST_ERR when checksum fails, a
+//character if it is received instead of the GDB packet
+//start char.
+static int ATTR_GDBFN gdbReadCommand() {
+	unsigned char c;
+	unsigned char chsum=0, rchsum;
+	unsigned char sentchs[2];
+	int p=0;
+	unsigned char *ptr;
+	c=gdbRecvChar();
+	if (c!='$') return c;
+	while(1) {
+		c=gdbRecvChar();
+		if (c=='#') {	//end of packet, checksum follows
+			cmd[p]=0;
+			break;
+		}
+		chsum+=c;
+		if (c=='$') {
+			//Wut, restart packet?
+			chsum=0;
+			p=0;
+			continue;
+		}
+		if (c=='}') {		//escape the next char
+			c=gdbRecvChar();
+			chsum+=c;
+			c^=0x20;
+		}
+		cmd[p++]=c;
+		if (p>=PBUFLEN) return ST_ERR;
+	}
+	//A # has been received. Get and check the received chsum.
+	sentchs[0]=gdbRecvChar();
+	sentchs[1]=gdbRecvChar();
+	ptr=&sentchs[0];
+	rchsum=gdbGetHexVal(&ptr, 8);
+//	os_printf("c %x r %x\n", chsum, rchsum);
+	if (rchsum!=chsum) {
+		gdbSendChar('-');
+		return ST_ERR;
+	} else {
+		gdbSendChar('+');
+		return gdbHandleCommand(cmd, p);
+	}
+}
+
+//Get the value of one of the A registers
+static unsigned int ATTR_GDBFN getaregval(int reg) {
+	if (reg==0) return gdbstub_savedRegs.a0;
+	if (reg==1) return gdbstub_savedRegs.a1;
+	return gdbstub_savedRegs.a[reg-2];
+}
+
+//Set the value of one of the A registers
+static void ATTR_GDBFN setaregval(int reg, unsigned int val) {
+	os_printf("%x -> %x\n", val, reg);
+	if (reg==0) gdbstub_savedRegs.a0=val;
+	if (reg==1) gdbstub_savedRegs.a1=val;
+	gdbstub_savedRegs.a[reg-2]=val;
+}
+
+//Emulate the l32i/s32i instruction we're stopped at.
+static void ATTR_GDBFN emulLdSt() {
+	unsigned char i0=readbyte(gdbstub_savedRegs.pc);
+	unsigned char i1=readbyte(gdbstub_savedRegs.pc+1);
+	unsigned char i2=readbyte(gdbstub_savedRegs.pc+2);
+	int *p;
+	if ((i0&0xf)==2 && (i1&0xf0)==0x20) {
+		//l32i
+		p=(int*)getaregval(i1&0xf)+(i2*4);
+		setaregval(i0>>4, *p);
+		gdbstub_savedRegs.pc+=3;
+	} else if ((i0&0xf)==0x8) {
+		//l32i.n
+		p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
+		setaregval(i0>>4, *p);
+		gdbstub_savedRegs.pc+=2;
+	} else if ((i0&0xf)==2 && (i1&0xf0)==0x60) {
+		//s32i
+		p=(int*)getaregval(i1&0xf)+(i2*4);
+		*p=getaregval(i0>>4);
+		gdbstub_savedRegs.pc+=3;
+	} else if ((i0&0xf)==0x9) {
+		//s32i.n
+		p=(int*)getaregval(i1&0xf)+((i1>>4)*4);
+		*p=getaregval(i0>>4);
+		gdbstub_savedRegs.pc+=2;
+	} else {
+		os_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0);
+	}
+}
+
+//We just caught a debug exception and need to handle it. This is called from an assembly
+//routine in gdbstub-entry.S
+void ATTR_GDBFN gdbstub_handle_debug_exception() {
+	ets_wdt_disable();
+
+	if (singleStepPs!=-1) {
+		//We come here after single-stepping an instruction. Interrupts are disabled
+		//for the single step. Re-enable them here.
+		gdbstub_savedRegs.ps=(gdbstub_savedRegs.ps&~0xf)|(singleStepPs&0xf);
+		singleStepPs=-1;
+	}
+
+	sendReason();
+	while(gdbReadCommand()!=ST_CONT);
+	if ((gdbstub_savedRegs.reason&0x84)==0x4) {
+		//We stopped due to a watchpoint. We can't re-execute the current instruction
+		//because it will happily re-trigger the same watchpoint, so we emulate it
+		//while we're still in debugger space.
+		emulLdSt();
+	} else if ((gdbstub_savedRegs.reason&0x88)==0x8) {
+		//We stopped due to a BREAK instruction. Skip over it.
+		//Check the instruction first; gdb may have replaced it with the original instruction
+		//if it's one of the breakpoints it set.
+		if (readbyte(gdbstub_savedRegs.pc+2)==0 &&
+					(readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0x40 &&
+					(readbyte(gdbstub_savedRegs.pc)&0x0f)==0x00) {
+			gdbstub_savedRegs.pc+=3;
+		}
+	} else if ((gdbstub_savedRegs.reason&0x90)==0x10) {
+		//We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction
+		//actually is a BREAK.N
+		if ((readbyte(gdbstub_savedRegs.pc+1)&0xf0)==0xf0 &&
+					readbyte(gdbstub_savedRegs.pc)==0x2d) {
+			gdbstub_savedRegs.pc+=3;
+		}
+	}
+	ets_wdt_enable();
+}
+
+
+#if GDBSTUB_FREERTOS
+//Freetos exception. This routine is called by an assembly routine in gdbstub-entry.S
+void ATTR_GDBFN gdbstub_handle_user_exception() {
+	ets_wdt_disable();
+	gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
+	sendReason();
+	while(gdbReadCommand()!=ST_CONT);
+	ets_wdt_enable();
+}
+#else
+
+//Non-OS exception handler. Gets called by the Xtensa HAL.
+static void ATTR_GDBFN gdb_exception_handler(struct XTensa_exception_frame_s *frame) {
+	//Save the extra registers the Xtensa HAL doesn't save
+	gdbstub_save_extra_sfrs_for_exception();
+	//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+	os_memcpy(&gdbstub_savedRegs, frame, 19*4);
+	//Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it
+	//has a fixed offset from the address of the passed frame, we can recover it.
+	gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+	gdbstub_savedRegs.reason|=0x80; //mark as an exception reason
+
+	ets_wdt_disable();
+	sendReason();
+	while(gdbReadCommand()!=ST_CONT);
+	ets_wdt_enable();
+
+	//Copy any changed registers back to the frame the Xtensa HAL uses.
+	os_memcpy(frame, &gdbstub_savedRegs, 19*4);
+}
+#endif
+
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+//Replacement putchar1 routine. Instead of spitting out the character directly, it will buffer up to
+//OBUFLEN characters (or up to a \n, whichever comes earlier) and send it out as a gdb stdout packet.
+static void ATTR_GDBFN gdb_semihost_putchar1(char c) {
+	int i;
+	obuf[obufpos++]=c;
+	if (c=='\n' || obufpos==OBUFLEN) {
+		gdbPacketStart();
+		gdbPacketChar('O');
+		for (i=0; i<obufpos; i++) gdbPacketHex(obuf[i], 8);
+		gdbPacketEnd();
+		obufpos=0;
+	}
+}
+#endif
+
+#if !GDBSTUB_FREERTOS
+//The OS-less SDK uses the Xtensa HAL to handle exceptions. We can use those functions to catch any
+//fatal exceptions and invoke the debugger when this happens.
+static void ATTR_GDBINIT install_exceptions() {
+	int i;
+	int exno[]={EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL, EXCCAUSE_INSTR_ERROR, EXCCAUSE_LOAD_STORE_ERROR,
+			EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR,
+			EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR, EXCCAUSE_INSTR_PROHIBITED,
+			EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
+	for (i=0; i<(sizeof(exno)/sizeof(exno[0])); i++) {
+		_xtos_set_exception_handler(exno[i], gdb_exception_handler);
+	}
+}
+#else
+//FreeRTOS doesn't use the Xtensa HAL for exceptions, but uses its own fatal exception handler.
+//We use a small hack to replace that with a jump to our own handler, which then has the task of
+//decyphering and re-instating the registers the FreeRTOS code left.
+extern void user_fatal_exception_handler();
+extern void gdbstub_user_exception_entry();
+
+static void ATTR_GDBINIT install_exceptions() {
+	//Replace the user_fatal_exception_handler by a jump to our own code
+	int *ufe=(int*)user_fatal_exception_handler;
+	//This mess encodes as a relative jump instruction to user_fatal_exception_handler
+	*ufe=((((int)gdbstub_user_exception_entry-(int)user_fatal_exception_handler)-4)<<6)|6;
+}
+#endif
+
+
+
+#if GDBSTUB_CTRLC_BREAK
+
+#if !GDBSTUB_FREERTOS
+
+static void ATTR_GDBFN uart_hdlr(void *arg, void *frame) {
+	int doDebug=0, fifolen=0;
+	//Save the extra registers the Xtensa HAL doesn't save
+	gdbstub_save_extra_sfrs_for_exception();
+
+	fifolen=(READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+	while (fifolen!=0) {
+		if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
+		fifolen--;
+	}
+	WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+
+	if (doDebug) {
+		//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+		os_memcpy(&gdbstub_savedRegs, frame, 19*4);
+		gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+		gdbstub_savedRegs.reason=0xff; //mark as user break reason
+
+		ets_wdt_disable();
+		sendReason();
+		while(gdbReadCommand()!=ST_CONT);
+		ets_wdt_enable();
+		//Copy any changed registers back to the frame the Xtensa HAL uses.
+		os_memcpy(frame, &gdbstub_savedRegs, 19*4);
+	}
+}
+
+static void ATTR_GDBINIT install_uart_hdlr() {
+	ets_isr_attach(ETS_UART_INUM, uart_hdlr, NULL);
+	SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+	ets_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
+}
+
+#else
+
+void ATTR_GDBFN gdbstub_handle_uart_int(struct XTensa_rtos_int_frame_s *frame) {
+	int doDebug=0, fifolen=0, x;
+
+	fifolen=(READ_PERI_REG(UART_STATUS(0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
+	while (fifolen!=0) {
+		if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) doDebug=1; //Check if any of the chars is control-C. Throw away rest.
+		fifolen--;
+	}
+	WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
+
+	if (doDebug) {
+		//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
+		gdbstub_savedRegs.pc=frame->pc;
+		gdbstub_savedRegs.ps=frame->ps;
+		gdbstub_savedRegs.sar=frame->sar;
+		gdbstub_savedRegs.a0=frame->a[0];
+		gdbstub_savedRegs.a1=frame->a[1];
+		for (x=2; x<16; x++) gdbstub_savedRegs.a[x-2]=frame->a[x];
+
+//		gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
+
+		gdbstub_savedRegs.reason=0xff; //mark as user break reason
+
+//		ets_wdt_disable();
+		sendReason();
+		while(gdbReadCommand()!=ST_CONT);
+//		ets_wdt_enable();
+		//Copy any changed registers back to the frame the Xtensa HAL uses.
+		frame->pc=gdbstub_savedRegs.pc;
+		frame->ps=gdbstub_savedRegs.ps;
+		frame->sar=gdbstub_savedRegs.sar;
+		frame->a[0]=gdbstub_savedRegs.a0;
+		frame->a[1]=gdbstub_savedRegs.a1;
+		for (x=2; x<16; x++) frame->a[x]=gdbstub_savedRegs.a[x-2];
+	}
+}
+
+static void ATTR_GDBINIT install_uart_hdlr() {
+	_xt_isr_attach(ETS_UART_INUM, gdbstub_uart_entry);
+	SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+	_xt_isr_unmask((1<<ETS_UART_INUM)); //enable uart interrupt
+}
+
+#endif
+
+#endif
+
+
+
+//gdbstub initialization routine.
+void ATTR_GDBINIT gdbstub_init() {
+#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+	os_install_putc1(gdb_semihost_putchar1);
+#endif
+#if GDBSTUB_CTRLC_BREAK
+	install_uart_hdlr();
+#endif
+	install_exceptions();
+	gdbstub_init_debug_entry();
+#if GDBSTUB_BREAK_ON_INIT
+	gdbstub_do_break();
+#endif
+}

+ 1565 - 0
hal/lps25hb.c

@@ -0,0 +1,1565 @@
+/**
+  ******************************************************************************
+  * @file    lps25hb.c
+  * @author  HESA Application Team
+  * @version 1.0.0
+  * @date    07/04/2014
+  * @brief   LPS25HB driver file
+
+  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+  *
+  * THIS SOURCE CODE IS PROTECTED BY A LICENSE.
+  * FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED
+  * IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE.
+  *
+  * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
+
+  ******************************************************************************
+*/
+
+/* Includes ------------------------------------------------------------------*/
+#include "hal/lps25hb.h"
+#include "driver/i2c_master.h"
+
+
+#ifdef  USE_FULL_ASSERT_LPS25HB
+#include <stdio.h>
+#endif
+
+
+
+/** @addtogroup Environmental_Sensor
+  * @{
+  */
+
+/** @defgroup LPS25HB_DRIVER
+* @brief LPS25HB DRIVER
+  * @{
+  */
+
+#define LPS25HB_WRITE_ADDRESS   0xB8
+#define LPS25HB_READ_ADDRESS    0xB9
+
+uint8_t ICACHE_FLASH_ATTR Sensor_IO_Write(uint8_t WriteAddr, uint16_t nBytesToWrite, uint8_t *pBuffer)
+{
+  uint16_t i;
+
+
+  i2c_master_init();
+  // write device address
+  i2c_master_start();
+  i2c_master_writeByte(LPS25HB_WRITE_ADDRESS);
+  if (!i2c_master_checkAck()) {
+    i2c_master_stop();
+    return 1;
+  }
+
+  // write initial address for reg to be written to
+  i2c_master_writeByte(WriteAddr);
+  if (!i2c_master_checkAck()) {
+    i2c_master_stop();
+    return 1;
+  }
+
+  // write bytes
+  for (i=0; i<(nBytesToWrite); i++) {
+    i2c_master_writeByte(pBuffer[i]);
+    if (!i2c_master_checkAck()) {
+      i2c_master_stop();
+      return 1;
+    }
+  }
+  i2c_master_stop();
+  return 0;
+
+  // enable LSM6DS3 for SPI communication
+  //lsm6ds3_i2c_short(false);
+}
+
+uint8_t ICACHE_FLASH_ATTR Sensor_IO_Read(uint8_t ReadAddr, uint16_t nBytesToRead, uint8_t *pBuffer)
+{
+  uint16_t i;
+  i2c_master_init();
+
+  // enable LSM6DS3 for I2C communication
+  //lsm6ds3_i2c_short(true);
+  // open connection to devive to write
+  i2c_master_start();
+  i2c_master_writeByte(LPS25HB_WRITE_ADDRESS);
+  if (!i2c_master_checkAck()) {
+    i2c_master_stop();
+    return 1;
+  }
+  // write read address
+  i2c_master_writeByte(ReadAddr);
+    if (!i2c_master_checkAck()) {
+    i2c_master_stop();
+    return 1;
+  }
+  // open connection to device to read
+  i2c_master_start();
+  i2c_master_writeByte(LPS25HB_READ_ADDRESS);
+  if (!i2c_master_checkAck()) {
+    i2c_master_stop();
+    return 1;
+  }
+  // read bytes
+  for (i=0; i<nBytesToRead; i++)
+  {
+    pBuffer[i] = i2c_master_readByte();
+    //os_printf("Byte %x\r\n", pBuffer[i]);
+    if (i == (nBytesToRead - 1))
+      i2c_master_send_nack();
+    else
+      i2c_master_send_ack();
+  }
+  i2c_master_stop();
+
+  // enable LSM6DS3 for SPI communication
+  // lsm6ds3_i2c_short(false);
+  return 0;
+
+}
+
+/** @defgroup LPS25HB_Public_Functions
+* @{
+*/
+
+/**
+  * @brief  Read identification code by WHO_AM_I register
+  * @param  Buffer to empty by Device identification Value.
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_DeviceID(uint8_t* deviceid)
+{
+  if(LPS25HB_ReadReg(LPS25HB_WHO_AM_I_REG, 1, deviceid))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+  * @brief  Get the LPS25HB driver version.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_DriverVersion(LPS25HB_DriverVersion_st *Version)
+{
+  Version->Major = LPS25HB_DriverVersion_Major;
+  Version->Minor = LPS25HB_DriverVersion_Minor;
+  Version->Point = LPS25HB_DriverVersion_Point;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Set LPS25HB Pressure and Temperature Resolution Mode
+  * @param  Pressure Resolution
+	* @param  Temperature Resolution
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_Avg(LPS25HB_Avgp_et avgp,LPS25HB_Avgt_et avgt )
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_AVGT(avgt));
+  LPS25HB_assert_param(IS_LPS25HB_AVGP(avgp));
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~(LPS25HB_AVGT_MASK | LPS25HB_AVGP_MASK);
+  tmp |= (uint8_t)avgp;
+  tmp |= (uint8_t)avgt;
+
+  if(LPS25HB_WriteReg(LPS25HB_RES_CONF_REG, 1, &tmp) )
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+  * @brief  Exit the shutdown mode for LPS25HB.
+  * @param  None
+  * @retval None
+*/
+
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Activate(void)
+{
+  if(LPS25HB_Set_PowerDownMode(LPS25HB_SET))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Enter the shutdown mode for LPS25HB.
+  * @param  None
+  * @retval None
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_DeActivate(void)
+{
+  if(LPS25HB_Set_PowerDownMode(LPS25HB_RESET))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Set LPS25HB Pressure Resolution Mode
+  * @param  Pressure Resolution
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_AvgP(LPS25HB_Avgp_et avgp)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_AVGP(avgp));
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_AVGP_MASK;
+  tmp |= (uint8_t)avgp;
+
+  if(LPS25HB_WriteReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Set LPS25HB Temperature Resolution Mode
+  * @param  Temperature Resolution
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_AvgT(LPS25HB_Avgt_et avgt)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_AVGT(avgt));
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_AVGT_MASK;
+  tmp |= (uint8_t)avgt;
+
+  if(LPS25HB_WriteReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Get LPS25HB Pressure Resolution Mode
+  * @param  Pressure Resolution
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_AvgP(LPS25HB_Avgp_et* avgp)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  *avgp = (LPS25HB_Avgp_et)(tmp & LPS25HB_AVGP_MASK);
+
+  return LPS25HB_OK;
+}
+
+
+/**
+  * @brief  Get LPS25HB Temperature Resolution Mode
+  * @param  Temperature Resolution
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_AvgT(LPS25HB_Avgt_et* avgt)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp) )
+    return LPS25HB_ERROR;
+
+  *avgt = (LPS25HB_Avgt_et)(tmp & LPS25HB_AVGT_MASK);
+
+  return LPS25HB_OK;
+}
+
+
+/**
+  * @brief  Set LPS25HB Output Data Rate
+  * @param  Output Data Rate
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_Odr(LPS25HB_Odr_et odr)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_ODR(odr));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_ODR_MASK;
+  tmp |= (uint8_t)odr;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+  * @brief  Get LPS25HB Output Data Rate
+  * @param  Buffer to empty with Output Data Rate
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_Odr(LPS25HB_Odr_et* odr)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  *odr = (LPS25HB_Odr_et)(tmp & LPS25HB_ODR_MASK);
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  SET/RESET LPS25HB Power Down Mode bit
+  * @param  LPS25HB_SET (Active Mode)/LPS25HB_RESET (Power Down Mode)
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_PowerDownMode(LPS25HB_BitStatus_et pd)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_BitStatus(pd));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_PD_MASK;
+  tmp |= ((uint8_t)pd)<<LPS25HB_PD_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Set Block Data Mode
+  * @detail It is recommended to set BDU bit to �1�.
+  * @detail This feature avoids reading LSB and MSB related to different samples.
+  * @param 	LPS25HB_BDU_CONTINUOS_UPDATE, LPS25HB_BDU_NO_UPDATE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_Bdu(LPS25HB_Bdu_et bdu)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_BDUMode(bdu));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_BDU_MASK;
+   tmp |= ((uint8_t)bdu);
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Get Block Data Mode
+  * @param 	Buffer to empty whit thw bdu mode read from sensor
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_Bdu(LPS25HB_Bdu_et* bdu)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  *bdu = (LPS25HB_Bdu_et)(tmp & LPS25HB_BDU_MASK);
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Enable/Disable Interrupt Circuit.
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptCircuitEnable(LPS25HB_State_et diff_en)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(diff_en));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_DIFF_EN_MASK;
+    tmp |= ((uint8_t)diff_en)<<LPS25HB_DIFF_EN_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief  Get the Interrupt Circuit bit.
+* @param Buffer to empty whit thw diff_en mode read from sensor
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_InterruptCircuitEnable(LPS25HB_State_et* diff_en)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  *diff_en= (LPS25HB_State_et)((tmp & LPS25HB_DIFF_EN_MASK)>>LPS25HB_DIFF_EN_BIT);
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief  Set ResetAutoZero Function bit
+* @details REF_P reg (@0x08..0A) set pressure reference to default tmp RPDS reg (0x39/3A).
+* @param  None
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_ResetAZ(void)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+	/* Set the RESET_AZ bit*/
+	/* RESET_AZ is self cleared*/
+  tmp |= LPS25HB_RESET_AZ_MASK;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief  Set SPI mode: 3 Wire Interface or 4 Wire Interface
+* @param   LPS25HB_SPI_3_WIRE, LPS25HB_SPI_4_WIRE
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_SpiInterface(LPS25HB_SPIMode_et spimode)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_SPIMode(spimode));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_SIM_MASK;
+  tmp |= (uint8_t)spimode;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief  Get SPI mode: 3 Wire Interface or 4 Wire Interface
+* @param  Buffer to empty with spi mode read from Sensor
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_SpiInterface(LPS25HB_SPIMode_et* spimode)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  *spimode = (LPS25HB_SPIMode_et)(tmp & LPS25HB_SIM_MASK);
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief  Enable/Disable I2C Mode
+  * @param State: Enable (reset bit)/ Disable (set bit)
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_I2C(LPS25HB_State_et statei2c)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(statei2c));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_I2C_MASK;
+  if(statei2c == LPS25HB_DISABLE) {
+    tmp |= LPS25HB_I2C_MASK;
+  }
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+
+}
+
+/**
+* @brief  Set the one-shot bit in order to start acquisition when the ONE SHOT mode
+          has been selected by the ODR configuration.
+* @detail Once the measurement is done, ONE_SHOT bit will self-clear.
+* @param  None
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_StartOneShotMeasurement(void)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  /* Set the one shot bit */
+	/* Once the measurement is done, one shot bit will self-clear*/
+  tmp |= LPS25HB_ONE_SHOT_MASK;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+
+}
+
+/**
+* @brief  Set AutoZero Function bit
+* @detail When set to �1�, the actual pressure output is copied in the REF_P reg (@0x08..0A)
+* @param  LPS25HB_SET/LPS25HB_RESET
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_AutoZeroFunction(LPS25HB_BitStatus_et autozero)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_BitStatus(autozero));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &=  ~LPS25HB_AUTO_ZERO_MASK;
+  tmp |= ((uint8_t)autozero)<<LPS25HB_AUTO_ZERO_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Software Reset. Self-clearing upon completion
+  * @param   None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_SwReset(void)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp |= (0x01<<LPS25HB_SW_RESET_BIT);
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief  Reboot Memory Content
+* @param 	 None
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_MemoryBoot(void)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp |= (0x01<<LPS25HB_BOOT_BIT);
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Software Reset ann Reboot Memory Content.
+* @detail  The device is reset to the power on configuration if the SWRESET bit is set to �1�
+           and BOOT is set to �1�; Self-clearing upon completion.
+* @param  None
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_SwResetAndMemoryBoot(void)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp |= ((0x01<<LPS25HB_SW_RESET_BIT) | (0x01<<LPS25HB_BOOT_BIT));
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Enable/Disable FIFO Mode
+  * @param   LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoModeUse(LPS25HB_State_et status)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(status));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_FIFO_EN_MASK;
+  tmp |= ((uint8_t)status)<<LPS25HB_FIFO_EN_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief    Enable/Disable FIFO Watermark Level Use
+* @param    LPS25HB_ENABLE/LPS25HB_DISABLE
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoWatermarkLevelUse(LPS25HB_State_et status)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(status));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_WTM_EN_MASK;
+  tmp |= ((uint8_t)status)<<LPS25HB_WTM_EN_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Enable/Disable 1 HZ ODR Decimation
+* @param   LPS25HB_ENABLE/LPS25HB_DISABLE
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoMeanDecUse(LPS25HB_State_et status)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(status));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_FIFO_MEAN_MASK;
+  tmp |= ((uint8_t)status)<<LPS25HB_FIFO_MEAN_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+
+}
+
+/**
+* @brief   Enable/Disable Interrupt Active High (default tmp 0) or Low(tmp 1)
+* @param   LPS25HB_ENABLE/LPS25HB_DISABLE
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptActiveLevel(LPS25HB_State_et status)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(status));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_INT_H_L_MASK;
+  tmp |= ((uint8_t)status)<<LPS25HB_INT_H_L_BIT;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Push-pull/open drain selection on interrupt pads. Default tmp: 0
+* @param LPS25HB_PushPull/LPS25HB_OpenDrain
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptOutputType(LPS25HB_OutputType_et output)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_OutputType(output));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_PP_OD_MASK;
+  tmp |= (uint8_t)output;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Set Data signal on INT1 pad control bits. Default tmp: 00
+* @param   LPS25HB_DATA,LPS25HB_P_HIGH_LPS25HB_P_LOW,LPS25HB_P_LOW_HIGH
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptControlConfig(LPS25HB_OutputSignalConfig_et config)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_OutputSignal(config));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~(LPS25HB_INT1_S2_MASK | LPS25HB_INT1_S1_MASK);
+  tmp |= (uint8_t)config;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Set INT1 interrupt pins configuration
+  * @param   LPS25HB_EMPTY,LPS25HB_WTM,LPS25HB_OVR,LPS25HB_DATA_READY
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptDataConfig(LPS25HB_DataSignalType_et signal)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_DataSignal(signal));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG4, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~(LPS25HB_P1_EMPTY_MASK | LPS25HB_P1_WTM_MASK \
+          | LPS25HB_P1_OVERRUN_MASK  | LPS25HB_P1_DRDY_MASK );
+  tmp |= (uint8_t)signal;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_REG4, 1, &tmp))
+
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Enable\Disable Interrupt Generation on differential pressure low and/or high event
+  * @param   LPS25HB_DISABLE_INT, LPS25HB_PHE,LPS25HB_PLE,LPS25HB_PLE_PHE
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptDifferentialConfig(LPS25HB_InterruptDiffConfig_et config)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_InterruptDiff(config));
+
+  if(LPS25HB_ReadReg(LPS25HB_INTERRUPT_CFG_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~(LPS25HB_PL_E_MASK | LPS25HB_PH_E_MASK);
+  tmp |= (uint8_t)config;
+  if(config!=LPS25HB_DISABLE_INT){
+      /* Enable DIFF_EN bit in CTRL_REG1 */
+       if(LPS25HB_Set_InterruptCircuitEnable(LPS25HB_ENABLE))
+          return LPS25HB_ERROR;
+  }
+
+  if(LPS25HB_WriteReg(LPS25HB_INTERRUPT_CFG_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Enable/Disable Latch Interrupt request into INT_SOURCE register.
+  * @param   LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_LatchInterruptRequest(LPS25HB_State_et status)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_State(status));
+
+  if(LPS25HB_ReadReg(LPS25HB_INTERRUPT_CFG_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_LIR_MASK;
+  tmp |= (((uint8_t)status)<<LPS25HB_LIR_BIT);
+
+  if(LPS25HB_WriteReg(LPS25HB_INTERRUPT_CFG_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Get the Interrupt Generation on differential pressure status event.
+  * @detail  The INT_SOURCE register is cleared by reading it.
+  * @param  Status Event Flag: PH,PL,IA
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_InterruptDifferentialEventStatus(LPS25HB_InterruptDiffStatus_st* interruptsource)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_INTERRUPT_SOURCE_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  interruptsource->PH = (uint8_t)(tmp & LPS25HB_PH_MASK);
+  interruptsource->PL = (uint8_t)((tmp & LPS25HB_PL_MASK)>>LPS25HB_PL_BIT);
+  interruptsource->IA = (uint8_t)((tmp & LPS25HB_IA_MASK)>>LPS25HB_IA_BIT);
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Get the status of Pressure and Temperature data
+  * @param   Data Status Flag:  TempDataAvailable, TempDataOverrun, PressDataAvailable, PressDataOverrun
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_DataStatus(LPS25HB_DataStatus_st* datastatus)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_STATUS_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  datastatus->TempDataAvailable = (tmp & LPS25HB_TDA_MASK);
+  datastatus->PressDataAvailable = (uint8_t)((tmp & LPS25HB_PDA_MASK)>>LPS25HB_PDA_BIT);
+  datastatus->TempDataOverrun = (uint8_t)((tmp & LPS25HB_TOR_MASK)>>LPS25HB_TOR_BIT);
+  datastatus->PressDataOverrun = (uint8_t)((tmp & LPS25HB_POR_MASK)>>LPS25HB_POR_BIT);
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief    Get the raw pressure tmp
+* @detail   The data are expressed as PRESS_OUT_H/_L/_XL in 2�s complement.
+            Pout(hPA)=PRESS_OUT / 4096
+* @param    The buffer to empty with the pressure raw tmp
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_RawPressure(int32_t *raw_press)
+{
+  uint8_t buffer[3];
+  uint32_t tmp = 0;
+  uint8_t i;
+
+  if(LPS25HB_ReadReg(LPS25HB_PRESS_OUT_XL_REG, 3, buffer))
+      return LPS25HB_ERROR;
+
+  /* Build the raw data */
+  for(i=0; i<3; i++)
+    tmp |= (((uint32_t)buffer[i]) << (8*i));
+
+  /* convert the 2's complement 24 bit to 2's complement 32 bit */
+  if(tmp & 0x00800000)
+    tmp |= 0xFF000000;
+
+  *raw_press = ((int32_t)tmp);
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief    Get the Pressure value in hPA.
+* @detail   The data are expressed as PRESS_OUT_H/_L/_XL in 2�s complement.
+            Pout(hPA)=PRESS_OUT / 4096
+* @param    The buffer to empty with the pressure value that must be divided by 100 to get the value in hPA
+* @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_Pressure(int32_t* Pout)
+{
+  int32_t raw_press;
+
+  if(LPS25HB_Get_RawPressure(&raw_press))
+      return LPS25HB_ERROR;
+
+  *Pout = (raw_press*100)/4096;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief    Get the Raw Temperature tmp.
+* @detail   Temperature data are expressed as TEMP_OUT_H&TEMP_OUT_L as 2�s complement number.
+            Tout(degC)=42.5+ (TEMP_OUT/480)
+* @param    Buffer to empty with the temperature raw tmp.
+* @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_RawTemperature(int16_t* raw_data)
+{
+  uint8_t buffer[2];
+  uint16_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_TEMP_OUT_L_REG, 2, buffer))
+      return LPS25HB_ERROR;
+
+  /* Build the raw tmp */
+  tmp = (((uint16_t)buffer[1]) << 8) + (uint16_t)buffer[0];
+
+  *raw_data = ((int16_t)tmp);
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief    Get the Temperature value in �C.
+* @detail   Temperature data are expressed as TEMP_OUT_H&TEMP_OUT_L as 2�s complement number.
+*            Tout(degC)=42.5+ (TEMP_OUT/480)
+* @param    Buffer to empty with the temperature value that must be divided by 10 to get the value in �C
+* @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_Temperature(int16_t* Tout)
+{
+  int16_t raw_data;
+
+  if(LPS25HB_Get_RawTemperature(&raw_data))
+    return LPS25HB_ERROR;
+
+  *Tout = raw_data/48 + 425;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief    Get the threshold tmp used for pressure interrupt generation (hPA).
+* @detail   THS_P=THS_P_H&THS_P_L and is expressed as unsigned number.
+            P_ths(hPA)=(THS_P)/16.
+* @param    Buffer to empty with the pressure threshold in hPA
+* @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_PressureThreshold(int16_t* P_ths)
+{
+  uint8_t tempReg[2];
+
+  if(LPS25HB_ReadReg(LPS25HB_THS_P_LOW_REG, 2, tempReg))
+    return LPS25HB_ERROR;
+
+  *P_ths= (((((uint16_t)tempReg[1])<<8) + tempReg[0])/16);
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief    Set the threshold tmp used for pressure interrupt generation (hPA).
+* @detail   THS_P=THS_P_H&THS_P_L and is expressed as unsigned number.
+            P_ths(hPA)=(THS_P)/16.
+* @param    Pressure threshold in hPA
+* @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_PressureThreshold(int16_t P_ths)
+{
+  uint8_t buffer[2];
+
+  buffer[0] = (uint8_t)(16 * P_ths);
+  buffer[1] = (uint8_t)(((uint16_t)(16 * P_ths))>>8);
+
+  if(LPS25HB_WriteReg(LPS25HB_THS_P_LOW_REG, 2, buffer))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief  Set Fifo Mode
+* @param  LPS25HB_FIFO_BYPASS_MODE, LPS25HB_FIFO_MODE, LPS25HB_FIFO_STREAM_MODE, LPS25HB_FIFO_TRIGGER_STREAMTOFIFO_MODE,
+          LPS25HB_FIFO_TRIGGER_BYPASSTOSTREAM_MODE,LPS25HB_FIFO_MEAN_MODE, LPS25HB_FIFO_TRIGGER_BYPASSTOFIFO_MODE
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoMode(LPS25HB_FifoMode_et fifomode)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_FifoMode(fifomode));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+		return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_FMODE_MASK;
+  tmp |= (uint8_t)fifomode;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+		return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief    Get Fifo Mode
+* @param 	  buffer to empty with fifo mode tmp
+  * @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_FifoMode(LPS25HB_FifoMode_et* fifomode)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+      return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_WTM_POINT_MASK;
+  *fifomode = (LPS25HB_FifoMode_et)tmp;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief    Get the Fifo Status
+  * @param 	  Status Flag: FIFO_WTM,FIFO_EMPTY,FIFO_FULL,FIFO_LEVEL
+  * @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_FifoStatus(LPS25HB_FifoStatus_st* status)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_STATUS_FIFO_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  status->FIFO_WTM = (uint8_t)((tmp & LPS25HB_WTM_FIFO_MASK)>>LPS25HB_WTM_FIFO_BIT);
+  status->FIFO_FULL = (uint8_t)((tmp & LPS25HB_FULL_FIFO_MASK)>>LPS25HB_FULL_FIFO_BIT);
+  status->FIFO_EMPTY = (uint8_t)((tmp & LPS25HB_EMPTY_FIFO_MASK)>>LPS25HB_EMPTY_FIFO_BIT);
+  status->FIFO_LEVEL = (uint8_t)(tmp & LPS25HB_DIFF_POINT_MASK);
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief    Set Watermark Value
+  * @param 	  wtmlevel = [0,31]
+  * @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoWatermarkLevel(uint8_t wtmlevel)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_WtmLevel(wtmlevel));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+			return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_WTM_POINT_MASK;
+  tmp |= wtmlevel;
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief    Get Watermark Value
+* @param 	  wtmlevel tmp read from sensor
+  * @retval   Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_FifoWatermarkLevel(uint8_t *wtmlevel)
+{
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, wtmlevel))
+			return LPS25HB_ERROR;
+
+  *wtmlevel &= LPS25HB_WTM_POINT_MASK;
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Set the number of sample to perform moving average when FIFO_MEAN_MODE is used
+  * @param 	 LPS25HB_FIFO_SAMPLE_2,LPS25HB_FIFO_SAMPLE_4,LPS25HB_FIFO_SAMPLE_8,LPS25HB_FIFO_SAMPLE_16,LPS25HB_FIFO_SAMPLE_32
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoSampleSize(LPS25HB_FifoMeanModeSample_et samplesize)
+{
+  uint8_t tmp;
+
+  LPS25HB_assert_param(IS_LPS25HB_FifoMeanModeSample(samplesize));
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+	return LPS25HB_ERROR;
+
+  tmp &= ~LPS25HB_WTM_POINT_MASK;
+  tmp |= (uint8_t)samplesize;
+
+
+  if(LPS25HB_WriteReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+	return LPS25HB_ERROR;
+
+
+  return LPS25HB_OK;
+}
+
+/**
+  * @brief   Get the number of sample to perform moving average when FIFO_MEAN_MODE is used
+* @param 	 buffer to empty with sample size tmp
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_FifoSampleSize(LPS25HB_FifoMeanModeSample_et* samplesize)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+	return LPS25HB_ERROR;
+
+  tmp &= LPS25HB_WTM_POINT_MASK;
+  *samplesize = (LPS25HB_FifoMeanModeSample_et)tmp;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Get the reference pressure after soldering for computing differential pressure (hPA)
+* @param   buffer to empty with the he pressure tmp (hPA)
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_PressureOffsetValue(int16_t *pressoffset)
+{
+  uint8_t buffer[2];
+  int16_t raw_press;
+
+  if(LPS25HB_ReadReg(LPS25HB_RPDS_L_REG, 2, buffer))
+      return LPS25HB_ERROR;
+
+  raw_press = (int16_t)((((uint16_t)buffer[1]) << 8) + (uint16_t)buffer[0]);
+
+  *pressoffset = (raw_press*100)/4096;
+
+  return LPS25HB_OK;
+}
+
+/**
+* @brief   Set Generic Configuration
+* @param   Struct to empty with the chosen tmp
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_GenericConfig(LPS25HB_ConfigTypeDef_st* pxLPS25HBInit)
+{
+      /* Step 1. Init REF_P register*/
+      /* The REF_P is the Reference Pressure. Its reset tmp is 0x00*/
+      /* The REF_P will be set to the defualt RPDS (0x39h) tmp  if Reset_AZ is enabled.*/
+      /* The REF_P will be set the actual pressure output if AutoZero is enabled*/
+
+      if((pxLPS25HBInit->Reset_AZ)==LPS25HB_ENABLE){
+              if(LPS25HB_ResetAZ())
+                      return LPS25HB_ERROR;
+      }
+      else if((pxLPS25HBInit->AutoZero)==LPS25HB_ENABLE){
+            if(LPS25HB_Set_AutoZeroFunction(LPS25HB_SET))
+                      return LPS25HB_ERROR;
+      }
+
+      /* Step 2. Init the Pressure and Temperature Resolution*/
+      if(LPS25HB_Set_Avg(pxLPS25HBInit->PressResolution,pxLPS25HBInit->TempResolution))
+              return LPS25HB_ERROR;
+
+      /* Step 3. Init the Output Data Rate*/
+      if(LPS25HB_Set_Odr(pxLPS25HBInit->OutputDataRate))
+              return LPS25HB_ERROR;
+
+      /*Step 4. BDU bit is used to inhibit the output registers update between the reading of upper and
+              lower register parts. In default mode (BDU = �0�), the lower and upper register parts are
+              updated continuously. If it is not sure to read faster than output data rate, it is recommended
+              to set BDU bit to �1�. In this way, after the reading of the lower (upper) register part, the
+              content of that output registers is not updated until the upper (lower) part is read too.
+              This feature avoids reading LSB and MSB related to different samples.*/
+
+      if(LPS25HB_Set_Bdu(pxLPS25HBInit->BDU))
+              return LPS25HB_ERROR;
+
+      /*Step 5. SIM bit selects the SPI serial interface mode.*/
+      /* This feature has effect only if SPI interface is used*/
+
+      if(LPS25HB_Set_SpiInterface(pxLPS25HBInit->Sim))
+              return LPS25HB_ERROR;
+
+       return LPS25HB_OK;
+}
+
+
+/**
+* @brief   Get Generic Configuration
+* @param   Struct to empty with the  tmp read from sensor
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_GenericConfig(LPS25HB_ConfigTypeDef_st* pxLPS25HBInit)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_RES_CONF_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+    pxLPS25HBInit->PressResolution=(LPS25HB_Avgp_et)(tmp&LPS25HB_AVGP_MASK);
+    pxLPS25HBInit->TempResolution=(LPS25HB_Avgt_et)(tmp& LPS25HB_AVGT_MASK);
+
+    if(LPS25HB_ReadReg(LPS25HB_CTRL_REG1, 1, &tmp))
+      return LPS25HB_ERROR;
+
+
+  pxLPS25HBInit->OutputDataRate= (LPS25HB_Odr_et)(tmp & LPS25HB_ODR_MASK);
+
+  pxLPS25HBInit->BDU=(LPS25HB_Bdu_et)(tmp & LPS25HB_BDU_MASK);
+  pxLPS25HBInit->Sim=(LPS25HB_SPIMode_et)(tmp& LPS25HB_SIM_MASK);
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  pxLPS25HBInit->AutoZero=(LPS25HB_State_et)((tmp&LPS25HB_RESET_AZ_MASK)>>LPS25HB_AUTO_ZERO_BIT);
+
+
+  return LPS25HB_OK;
+
+}
+
+/**
+* @brief   Set Interrupt Configuration
+* @param    Struct to empty with the chosen tmp
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_InterruptConfig(LPS25HB_InterruptTypeDef_st* pLPS25HBInt)
+{
+    if(LPS25HB_Set_InterruptActiveLevel(pLPS25HBInt->INT_H_L))
+            return LPS25HB_ERROR;
+
+    if(LPS25HB_Set_InterruptOutputType(pLPS25HBInt->PP_OD))
+            return LPS25HB_ERROR;
+
+    if(LPS25HB_Set_InterruptControlConfig(pLPS25HBInt->OutputSignal_INT1))
+                    return LPS25HB_ERROR;
+
+    if(pLPS25HBInt->OutputSignal_INT1==LPS25HB_DATA){
+
+            if(LPS25HB_Set_InterruptDataConfig(pLPS25HBInt->DataInterrupt_INT1))
+                    return LPS25HB_ERROR;
+    }
+
+    if(LPS25HB_LatchInterruptRequest(pLPS25HBInt->LatchIRQ))
+                    return LPS25HB_ERROR;
+
+    if(LPS25HB_Set_PressureThreshold(pLPS25HBInt->fP_threshold))
+                    return LPS25HB_ERROR;
+
+    /*DIFF_EN bit is used to enable the circuitry for the computing of differential pressure output.*/
+    /*It is suggested to turn on the circuitry only after the configuration of REF_P_x and THS_P_x.*/
+
+    if(LPS25HB_Set_InterruptDifferentialConfig(pLPS25HBInt->PressureInterrupt))
+                    return LPS25HB_ERROR;
+
+    return LPS25HB_OK;
+}
+
+/**
+* @brief   Get Interrupt Configuration
+* @param   Struct to empty with the tmp read from sensor
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_InterruptConfig(LPS25HB_InterruptTypeDef_st* pLPS25HBInt)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_REG3, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  pLPS25HBInt->INT_H_L=(LPS25HB_State_et)((tmp&LPS25HB_INT_H_L_MASK)>>LPS25HB_INT_H_L_BIT);
+
+  pLPS25HBInt->PP_OD =(LPS25HB_OutputType_et)(tmp&LPS25HB_PP_OD_MASK);
+  pLPS25HBInt->OutputSignal_INT1=(LPS25HB_OutputSignalConfig_et)((tmp&0x03));
+
+  if(pLPS25HBInt->OutputSignal_INT1==LPS25HB_DATA){
+    if(LPS25HB_ReadReg(LPS25HB_CTRL_REG4, 1, &tmp))
+			return LPS25HB_ERROR;
+
+    pLPS25HBInt->DataInterrupt_INT1=(LPS25HB_DataSignalType_et)(tmp &=0x0F);
+  }
+  if(LPS25HB_ReadReg(LPS25HB_INTERRUPT_CFG_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  pLPS25HBInt->LatchIRQ=(LPS25HB_State_et)((tmp &LPS25HB_LIR_MASK)>>LPS25HB_LIR_BIT);
+  pLPS25HBInt->PressureInterrupt=(LPS25HB_InterruptDiffConfig_et)(tmp &LPS25HB_PE_MASK);
+
+  if(LPS25HB_Get_PressureThreshold(&pLPS25HBInt->fP_threshold))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+/**
+  * @brief   Set Fifo Configuration
+* @param 	 Struct to empty with the chosen tmp
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Set_FifoConfig(LPS25HB_FIFOTypeDef_st* pLPS25HBFIFO)
+{
+  if(pLPS25HBFIFO->FIFO_MODE == LPS25HB_FIFO_BYPASS_MODE) {
+		/* FIFO Disable-> FIFO_EN bit=0 in CTRL_REG2*/
+		if(LPS25HB_Set_FifoModeUse(LPS25HB_DISABLE))
+			return LPS25HB_ERROR;
+  }
+  else {
+		/* FIFO Enable-> FIFO_EN bit=1 in CTRL_REG2*/
+		if(LPS25HB_Set_FifoModeUse(LPS25HB_ENABLE))
+			return LPS25HB_ERROR;
+
+			if(pLPS25HBFIFO->FIFO_MODE==LPS25HB_FIFO_MEAN_MODE){
+                                    if(LPS25HB_Set_FifoSampleSize(pLPS25HBFIFO->MEAN_MODE_SAMPLE))
+                                            return LPS25HB_ERROR;
+                                    if(pLPS25HBFIFO->FIFO_MEAN_DEC)
+                                            if(LPS25HB_Set_FifoMeanDecUse(LPS25HB_ENABLE))
+                                              return LPS25HB_ERROR;
+			}
+			else{
+                                  if (pLPS25HBFIFO->WTM_INT){
+                                          if(LPS25HB_Set_FifoWatermarkLevelUse(LPS25HB_ENABLE))
+                                                  return LPS25HB_ERROR;
+                                          if(LPS25HB_Set_FifoWatermarkLevel(pLPS25HBFIFO->WTM_LEVEL))
+                                                  return LPS25HB_ERROR;
+                                  }
+			}
+	}
+
+  if(LPS25HB_Set_FifoMode(pLPS25HBFIFO->FIFO_MODE))
+    return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+
+}
+
+/**
+  * @brief   Get Fifo Configuration
+* @param 	 Struct to empty with the  tmp read from sensor
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_FifoConfig(LPS25HB_FIFOTypeDef_st* pLPS25HBFIFO)
+{
+  uint8_t tmp;
+
+  if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  pLPS25HBFIFO->FIFO_MODE=(LPS25HB_FifoMode_et)(tmp&LPS25HB_FMODE_MASK);
+
+  if(pLPS25HBFIFO->FIFO_MODE==LPS25HB_FIFO_MEAN_MODE){
+
+    pLPS25HBFIFO->MEAN_MODE_SAMPLE=(LPS25HB_FifoMeanModeSample_et)(tmp&LPS25HB_WTM_POINT_MASK);
+    if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+      return LPS25HB_ERROR;
+    pLPS25HBFIFO->FIFO_MEAN_DEC=(LPS25HB_State_et)((tmp&LPS25HB_FIFO_MEAN_MASK)>>LPS25HB_FIFO_MEAN_BIT);
+
+  }
+  else{
+	if(pLPS25HBFIFO->FIFO_MODE != LPS25HB_FIFO_BYPASS_MODE) {
+          if(LPS25HB_ReadReg(LPS25HB_CTRL_REG2, 1, &tmp))
+            return LPS25HB_ERROR;
+          pLPS25HBFIFO->WTM_INT=(LPS25HB_State_et)((tmp&LPS25HB_WTM_EN_MASK)>>LPS25HB_WTM_EN_BIT);
+          if (pLPS25HBFIFO->WTM_INT){
+            if(LPS25HB_ReadReg(LPS25HB_CTRL_FIFO_REG, 1, &tmp))
+              return LPS25HB_ERROR;
+            pLPS25HBFIFO->WTM_LEVEL=(uint8_t)(tmp&LPS25HB_WTM_POINT_MASK);
+          }
+        }
+  }
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief   Get the Reference Pressure tmp that is sum to the sensor output pressure
+* @param   Buffer to empty with reference pressure tmp
+* @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_ReferencePressure(int32_t* RefP)
+{
+  uint8_t buffer[3];
+  uint32_t tempVal=0;
+  int32_t raw_press;
+  uint8_t i;
+
+  if(LPS25HB_ReadReg(LPS25HB_REF_P_XL_REG, 3, buffer))
+      return LPS25HB_ERROR;
+
+  /* Build the raw data */
+  for(i=0; i<3; i++)
+      tempVal |= (((uint32_t)buffer[i]) << (8*i));
+
+  /* convert the 2's complement 24 bit to 2's complement 32 bit */
+  if(tempVal & 0x00800000)
+    tempVal |= 0xFF000000;
+
+  raw_press =((int32_t)tempVal);
+  *RefP = (raw_press*100)/4096;
+
+  return LPS25HB_OK;
+}
+
+
+/**
+* @brief  Check if the single measurement has completed.
+* @param  tmp is set to 1, when the measure is completed
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_IsMeasurementCompleted(uint8_t* Is_Measurement_Completed)
+{
+  uint8_t tmp;
+  LPS25HB_DataStatus_st datastatus;
+
+  if(LPS25HB_ReadReg(LPS25HB_STATUS_REG, 1, &tmp))
+    return LPS25HB_ERROR;
+
+  datastatus.TempDataAvailable=(uint8_t)(tmp&0x01);
+  datastatus.PressDataAvailable= (uint8_t)((tmp&0x02)>>LPS25HB_PDA_BIT);
+
+  *Is_Measurement_Completed=(uint8_t)((datastatus.PressDataAvailable) & (datastatus.TempDataAvailable));
+
+  return LPS25HB_OK;
+ }
+
+/**
+* @brief  Get the values of the last single measurement.
+* @param  Pressure and temperature tmp
+* @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_Get_Measurement(LPS25HB_MeasureTypeDef_st *Measurement_Value)
+{
+  int16_t Tout;
+  int32_t Pout;
+
+  if(LPS25HB_Get_Temperature(&Tout))
+    return LPS25HB_ERROR;
+
+  Measurement_Value->Tout=Tout;
+
+  if(LPS25HB_Get_Pressure(&Pout))
+    return LPS25HB_ERROR;
+
+  Measurement_Value->Pout=Pout;
+
+  return LPS25HB_OK;
+
+ }
+
+
+/**
+* @brief  De initialization function for LPS25HB.
+*         This function put the LPS25HB in power down, make a memory boot and clear the data output flags.
+* @param  None.
+* @retval Error code [LPS25HB_OK, LPS25HB_ERROR].
+*/
+LPS25HB_Error_et ICACHE_FLASH_ATTR LPS25HB_DeInit(void)
+{
+  LPS25HB_MeasureTypeDef_st Measurement_Value;
+
+  /* LPS25HB in power down */
+  if(LPS25HB_Set_PowerDownMode(LPS25HB_RESET))
+     return LPS25HB_ERROR;
+
+  /* Make LPS25HB Reset and Reboot */
+  if(LPS25HB_SwResetAndMemoryBoot())
+     return LPS25HB_ERROR;
+
+  /* Dump of data output */
+  if(LPS25HB_Get_Measurement(& Measurement_Value))
+     return LPS25HB_ERROR;
+
+  return LPS25HB_OK;
+}
+
+
+
+#ifdef  USE_FULL_ASSERT_LPS25HB
+/**
+* @brief  Reports the name of the source file and the source line number
+*         where the assert_param error has occurred.
+* @param file: pointer to the source file name
+* @param line: assert_param error line source number
+* @retval : None
+*/
+void ICACHE_FLASH_ATTR LPS25HB_assert_failed(uint8_t* file, uint32_t line)
+{
+  /* User can add his own implementation to report the file name and line number */
+  printf("Wrong parameters tmp: file %s on line %d\r\n", file, line);
+
+  /* Infinite loop */
+  while (1)
+  {
+  }
+}
+#endif
+
+ /**
+* @}
+*/
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+*/
+
+/******************* (C) COPYRIGHT 2013 STMicroelectronics *****END OF FILE****/

+ 364 - 0
hal/lsm6ds3.c

@@ -0,0 +1,364 @@
+/******************************************************************************
+ * 2016 ideasX (Tyler Berezowsky and Marc Jurchak)
+ *
+ * FileName: LSM6DS3.c
+ *
+ * Description: SPIdriver for LSM6DS3
+ * Modification history:
+ *     2015/10/12, v1.0 created this file (Marc)
+ *     2016/3/15,  v1.1 added comments for Tyler.
+*******************************************************************************/
+#include "hal/lsm6ds3.h"
+#include "log/esp_log.h"
+
+static const char* TAG = "lsm6ds3.c";
+
+static int32_t ICACHE_FLASH_ATTR Sensor_IO_Write(uint16_t WriteAddr, uint8_t nBytesToWrite, uint32_t *pBuffer)
+{
+    // Initalize HSPI Interface GPIO
+    WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
+
+    // Setup SPI Attributes Struct
+    SpiAttr spiConfig;
+    spiConfig.mode =  SpiMode_Master;
+    spiConfig.subMode = SpiSubMode_0;
+    spiConfig.speed = SpiSpeed_8MHz;
+    spiConfig.bitOrder = SpiBitOrder_MSBFirst;
+
+    // Initalize SPI Interface
+    SPIInit(SpiNum_HSPI, &spiConfig);
+
+    // Setup SPI Data Struct
+    SpiData spiData;
+    uint32_t addr = (WriteAddr);
+
+    spiData.cmd = addr;
+    spiData.cmdLen = 1;
+    spiData.addrLen = 0;
+    spiData.addr = 0;
+    spiData.data  = pBuffer;
+    spiData.dataLen = nBytesToWrite;
+
+    // Write Data to SPI port
+    return SPIMasterSendData(SpiNum_HSPI, &spiData);
+}
+
+static int32_t ICACHE_FLASH_ATTR Sensor_IO_Read(uint16_t ReadAddr, uint8_t nBytesToRead, uint32_t *pBuffer)
+{
+    // Initalize HSPI Interface GPIO
+    WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
+
+    // Setup SPI Attributes Struct
+    SpiAttr spiConfig;
+    spiConfig.mode =  SpiMode_Master;
+    spiConfig.subMode = SpiSubMode_0;
+    spiConfig.speed = SpiSpeed_8MHz;
+    spiConfig.bitOrder = SpiBitOrder_MSBFirst;
+
+    // Initalize SPI Interface
+    SPIInit(SpiNum_HSPI, &spiConfig);
+
+    // Setup SPI Data Struct
+    SpiData spiData;
+    uint32_t addr = (ReadAddr | 0x80);
+
+    spiData.cmd = addr;
+    spiData.cmdLen = 1;
+    spiData.addrLen = 0;
+    spiData.addr = 0;
+    spiData.data  = pBuffer;
+    spiData.dataLen = nBytesToRead;
+
+    return SPIMasterRecvData(SpiNum_HSPI, &spiData);
+}
+
+static int32_t ICACHE_FLASH_ATTR Sensor_IO_Set_Register(uint16_t WriteAddr, uint32_t v0)
+{
+    uint32_t v1;
+    Sensor_IO_Write(WriteAddr, 1, &v0);
+    Sensor_IO_Read(WriteAddr, 1, &v1);
+    if (v0 == v1)
+        return 0;
+    else
+        return -1;
+}
+/******************************************************************************
+ * FunctionName : lsm6ds3_i2c_enable
+ * Description  : Setup LSM6DS3 registers for I2C sensor hub.
+ * Parameters   : uint8_t start
+ 				  1: enable
+ 				  0: disable
+ * Returns      : uint8_t 1: success 0: failed
+*******************************************************************************/
+int32_t ICACHE_FLASH_ATTR
+LSM6DS3_Enable_I2C_Pullups(uint8_t enable)
+{
+    uint32_t ctrl10_c, master_config;
+
+    Sensor_IO_Read(LSM6DS3_CTRL10_C, 1,  &ctrl10_c);
+    Sensor_IO_Read(LSM6DS3_MASTER_CONFIG, 1, &master_config);
+    if (enable)
+    {
+        ctrl10_c |= LSM6DS3_FUNC_EN;
+        //master_config |= (PULL_UP_EN + MASTER_ON);
+        master_config |= LSM6DS3_PULL_UP_EN;	// pull-ups on
+        master_config &= ~LSM6DS3_MASTER_ON;	// disable i2c master function?
+    }
+    else
+    {
+        ctrl10_c &= ~LSM6DS3_FUNC_EN;
+        master_config &= ~(LSM6DS3_PULL_UP_EN + LSM6DS3_MASTER_ON);
+    }
+    return (Sensor_IO_Set_Register(LSM6DS3_CTRL10_C, ctrl10_c) & Sensor_IO_Set_Register(LSM6DS3_MASTER_CONFIG, master_config));
+}
+
+
+int32_t ICACHE_FLASH_ATTR
+LSM6DS3_Enable_I2C_Bridge(uint8_t enable)
+{
+    LSM6DS3_Enable_I2C_Pullups(1);
+
+    uint32_t master_config;
+    Sensor_IO_Read(LSM6DS3_MASTER_CONFIG, 1, &master_config);
+    if (enable)
+    {
+        master_config |= LSM6DS3_PASS_THROUGH_MODE;
+    }
+    else
+    {
+        master_config &= ~LSM6DS3_PASS_THROUGH_MODE;
+    }
+    ESP_LOGI(TAG, "Writing %x to LSM6DS3_MASTER_CONFIG", master_config);
+    return Sensor_IO_Set_Register(LSM6DS3_MASTER_CONFIG, master_config);
+}
+
+// /******************************************************************************
+//  * FunctionName : lsm6ds3_xl_config
+//  * Description  : Setup LSM6DS3 registers for accel. sample and other cool nonsense.
+//  				  Note: 20ms is required from boot for the sensor to load some magic before you
+//  				  can play.
+//  * Parameters   : bool en_hp_mode: Enable or Disable high performance mode. NOTE: HP mode is
+//  				  is required for LP filter data and certain sampling rates.
+//  				  odr_xl: Output data rate for XL. See .h file for available rates.
+//  				  uint8_t scale_xl: Range of senstiviity selection. See .h file for available rates.
+//  				  uint8_t bw_xl: Anti-aliasing LP filter selection. See .h file and datasheet.
+//  * Returns      : bool 1: success 0: failed
+// *******************************************************************************/
+// bool ICACHE_FLASH_ATTR
+// lsm6ds3_xl_config(bool en_hp_mode, uint8_t odr_xl, uint8_t scale_xl, uint8_t bw_xl)
+// {
+//     uint8_t ctrl6_c = spi_rx8_address(HSPI, LSM6DS3_CTRL6_C);
+//     uint8_t ctrl1_xl = odr_xl | scale_xl | bw_xl;
+//
+//     if(en_hp_mode)
+//     ctrl6_c &= ~LSM6DS3_XL_HM_MODE;
+//     else
+//     ctrl6_c |= LSM6DS3_XL_HM_MODE;
+//     spi_tx8_address(HSPI, LSM6DS3_CTRL6_C, ctrl6_c);
+//     spi_tx8_address(HSPI, LSM6DS3_CTRL1_XL, ctrl1_xl);
+//     if ( (spi_rx8_address(HSPI, LSM6DS3_CTRL1_XL) == ctrl1_xl) & (spi_rx8_address(HSPI, LSM6DS3_CTRL6_C) == ctrl6_c) )
+//     return 1;
+//     else
+//     return 0;
+// }
+// /******************************************************************************
+//  * FunctionName : lsm6ds3_g_config
+//  * Description  : Setup LSM6DS3 registers for accel. sample and other cool nonsense.
+//  				  Note: 20ms is required from boot for the sensor to load some magic before you
+//  				  can play.
+//  * Parameters   : bool en_hp_mode: Enable or Disable high performance mode. NOTE: HP mode is
+//  				  is required for LP filter data and certain sampling rates.
+//  				  odr_xl: Output data rate for XL. See .h file for available rates.
+//  				  uint8_t scale_xl: Range of senstiviity selection. See .h file for available rates.
+//  				  uint8_t bw_xl: Anti-aliasing LP filter selection. See .h file and datasheet.
+//  * Returns      : bool 1: success 0: failed
+// *******************************************************************************/
+// bool ICACHE_FLASH_ATTR
+// lsm6ds3_g_config(bool en_hp_mode, bool hp_g_en, bool hp_g_rst,
+//     uint8_t odr_g, uint8_t scale_g, uint8_t hpcf_g)
+// {
+//     uint8_t ctrl7_g;
+//     uint8_t ctrl2_g = odr_g | scale_g;
+//
+//     if (en_hp_mode)
+//     ctrl7_g = LSM6DS3_G_HM_MODE;
+//     else
+//     ctrl7_g &= ~LSM6DS3_G_HM_MODE;
+//     if (hp_g_en)
+//     ctrl7_g |= LSM6DS3_HP_G_EN | hpcf_g;
+//     else
+//     ctrl7_g &= ~LSM6DS3_HP_G_EN;
+//     if (hp_g_rst)
+//     ctrl7_g |= LSM6DS3_HP_G_RST;
+//     else
+//     ctrl7_g &= ~LSM6DS3_HP_G_RST;
+//
+//     spi_tx8_address(HSPI, LSM6DS3_CTRL2_G, ctrl2_g);
+//     spi_tx8_address(HSPI, LSM6DS3_CTRL7_G, ctrl7_g);
+//     if ( (spi_rx8_address(HSPI, LSM6DS3_CTRL2_G) == ctrl2_g) & (spi_rx8_address(HSPI, LSM6DS3_CTRL7_G) == ctrl7_g))
+//     return 1;
+//     else
+//     return 0;
+// }
+// /******************************************************************************
+//  * FunctionName : lsm6ds3_fifo_config
+//  * Description  : Setup LSM6DS3 registers for FIFO. FIFO is automatically placed into continous mode.
+//  				  Decimation is set to zero, and the ODR of the FIFO is set to match that max(XL_ODR, G_ODR)
+//  				  INT1 is automatically enabled / disabled for FIFO overflow and threshold.
+//  				  If FIFO is enable it will automatically disable the significant motion ISR.
+//  * Parameters   : bool enable: Enable or Disable FIFO
+//  				  threshold: Set the threshold level of the FIFO
+//  * Returns      : bool 1: success 0: failed
+// *******************************************************************************/
+// bool ICACHE_FLASH_ATTR
+// lsm6ds3_fifo_config(uint16_t threshold)
+// {
+//     uint8_t ctrl1_xl, ctrl2_g, max_odr, fifo_ctrl3;
+//
+//     // read ODR rates
+//     ctrl1_xl = spi_rx8_address(HSPI, LSM6DS3_CTRL1_XL) & 0xF0;			// get ODR bits and clear the rest
+//     ctrl2_g = spi_rx8_address(HSPI, LSM6DS3_CTRL2_G) & 0xF0;			// get ODR bits and clear the rest
+//     os_printf("CTRL1_XL, CTRL2_G: %x, %x\r\n", ctrl1_xl, ctrl2_g);
+//     if (!(ctrl1_xl || ctrl2_g))
+//     {
+//     // disable FIFO
+//     os_printf("LSM6DS3: XL and G disabled. FIFO disabled.\r\n");
+//     lsm6ds3_set_register(LSM6DS3_FIFO_CTRL5, 0x00);
+//     lsm6ds3_set_register(LSM6DS3_INT1_CTRL, 0x00); 				// disable INT1 for overflow and threshold
+//
+//     }
+//     else
+//     {
+//
+//     // set Decimation Factor to 1 if sensor is active
+//     //lsm6ds3_set_register(FIFO_CTRL3, 0b00001001);
+//
+//     // set threshold
+//     lsm6ds3_set_register(LSM6DS3_FIFO_CTRL1, (uint8_t)(0xFF & threshold));
+//     lsm6ds3_set_register(LSM6DS3_FIFO_CTRL2, (uint8_t)(0xFF & (threshold >> 8)));
+//
+//     // set decimation factor to one if sensor ODR is not zero
+//     fifo_ctrl3 = 0;
+//     if (ctrl1_xl & 0xF0)
+//     fifo_ctrl3 = BIT0;
+//     if(ctrl2_g & 0xF0)
+//     fifo_ctrl3 |= BIT3;
+//     lsm6ds3_set_register(LSM6DS3_FIFO_CTRL3, fifo_ctrl3);
+//     os_printf("FIFO_CTRL3: %x\r\n", fifo_ctrl3);
+//
+//     // determine max ODR
+//     if ( (ctrl1_xl) >= (ctrl2_g) )
+//     max_odr = ctrl1_xl;
+//     else
+//     max_odr = ctrl2_g;
+//     max_odr = max_odr >> 1; 									// format for fifo register
+//     lsm6ds3_set_register(LSM6DS3_FIFO_CTRL5, max_odr | 0x06);	// set FIFO ODR and mode to continously
+//     lsm6ds3_set_register(LSM6DS3_INT1_CTRL, BIT3); 				// set INT1 for overflow and threshold
+//     }
+//     return 1;
+// }
+//
+// bool ICACHE_FLASH_ATTR lsm6ds3_reset(void)
+// {
+//     lsm6ds3_set_register(LSM6DS3_CTRL3_C, BIT0);
+//     os_delay_us(30000);
+//     return !(bool)(spi_rx8_address(HSPI, LSM6DS3_CTRL3_C) & BIT7);
+// }
+//
+// uint16_t ICACHE_FLASH_ATTR lsm6ds3_fifo_dump(uint16_t *buf, uint16_t buf_len, uint16_t bufPos)
+// {
+//     uint16_t samples = (uint16_t)spi_rx8_address(HSPI, LSM6DS3_FIFO_STATUS1);
+//     samples |= (((uint16_t)spi_rx8_address(HSPI, LSM6DS3_FIFO_STATUS2) & 0x0F) << 8);
+//
+//     // read and store into buff in multiples of 3
+//     if (samples <=  (buf_len - bufPos) && samples != 0)
+//     {
+//     uint16_t i;
+//     for(i=bufPos; i<samples+bufPos; i++)
+//     {
+//     buf[i] = spi_rx16_address(HSPI, LSM6DS3_FIFO_DATA_OUT_L);
+//     }
+//     return samples;
+//     }
+//     else
+//     return 0;
+//
+// }
+//
+//
+// uint8_t ICACHE_FLASH_ATTR lsm6ds3_fifo_getFlags(void)
+// {
+//     /*	There is (2) possible sources of interrupts caused by the IMU
+//     that the ESP8266 actually cares about.
+//     1) The significant motion interrupt
+//     2) The FIFO interrupts
+//
+//     LSM6DS3_FIFO_EMPTY
+//     LSM6DS3_FIFO_FULL
+//     LSM6DS3_FIFO_OVER_RUN
+//     LSM6DS3_FIFO_THRESHOLD
+//     */
+//     return (uint8_t)spi_rx8_address(HSPI, LSM6DS3_FIFO_STATUS2);
+// }
+//
+// bool ICACHE_FLASH_ATTR lsm6ds3_read_motion(void)
+// {
+//     uint8_t wake_up_src;
+//     wake_up_src = SPIread(LSM6DS3_WAKE_UP_SRC);
+//     //if (wake_up_src)
+//     {
+//     os_printf("WAKE_UP_SRC: %x\r\n", wake_up_src);
+//     os_printf("Direction ");
+//     if (wake_up_src & BIT2)
+//     os_printf("x");
+//     if (wake_up_src & BIT1)
+//     os_printf("y");
+//     if (wake_up_src & BIT0)
+//     os_printf("z");
+//
+//     os_printf("\r\n");
+//     }
+//     return wake_up_src & BIT3;
+// }
+//
+// bool ICACHE_FLASH_ATTR lsm6ds3_motion_enable(void)
+// {
+//     SPIwrite(LSM6DS3_CTRL2_G, LSM6DS3_ODR_G_POWERDOWN);								// disable gyro
+//     SPIwrite(LSM6DS3_CTRL1_XL, (LSM6DS3_ODR_XL_13Hz + LSM6DS3_FS_XL_2G));					// 208Hz 2g scale
+//     SPIwrite(LSM6DS3_TAP_CFG, LSM6DS3_LIR); 										// enable interuppt latch and slope filter
+//     SPIwrite(LSM6DS3_WAKE_UP_THS, 0x01); 									// set thres 32/64*2G = 1G
+//     SPIwrite(LSM6DS3_WAKE_UP_DUR, 0x02); 									// zero duration
+//     SPIwrite(LSM6DS3_MD1_CFG, LSM6DS3_INT1_WU);										// set interrupt for INTX (1 is connected to PBA)
+//     SPIwrite(LSM6DS3_CTRL3_C, LSM6DS3_H_LACTIVE);                                   // set int lines active low
+//     os_printf("MOTION PROCESS: Setup IMU for motion detection\r\n");
+//
+//     return 1;
+// }
+//
+// bool ICACHE_FLASH_ATTR lsm6ds3_motion_disable(void)
+// {
+//     lsm6ds3_reset();
+//     SPIwrite(LSM6DS3_CTRL2_G, LSM6DS3_ODR_G_POWERDOWN); 							// disable gyro
+//     SPIwrite(LSM6DS3_CTRL1_XL, LSM6DS3_ODR_XL_POWERDOWN); 							// disable XL
+//     SPIwrite(LSM6DS3_CTRL3_C, LSM6DS3_H_LACTIVE);
+//     return 1;
+// }
+//
+// #if LSM6DS3_DEBUG
+// void ICACHE_FLASH_ATTR
+// lsm6ds3_xl_print(void)
+// {
+//     os_printf("XL_X: %d\r\nXL_Y: %d\r\n XL_Z: %d\r\n",
+//     (SPIread(LSM6DS3_OUTX_H_XL)<<8)+SPIread(LSM6DS3_OUTX_L_XL), (SPIread(LSM6DS3_OUTY_H_XL)<<8)+SPIread(LSM6DS3_OUTY_L_XL),
+//     (SPIread(LSM6DS3_OUTZ_H_XL)<<8)+SPIread(LSM6DS3_OUTX_L_XL));
+//     return;
+// }
+// #endif

+ 175 - 0
hal/max17043.c

@@ -0,0 +1,175 @@
+/******************************************************************************
+ * 2016 ideasX (Tyler Berezowsky)
+ *
+ * FileName: MAX17043.h
+ *
+ * Description: i2c driver for MAX17042 gas gauge IC
+ *              Needs to implement code to resent/re-request data based on
+ *              ack. or nack.
+ *
+ * Modification history:
+ *     2016/3/15, v1.0 created this file
+*******************************************************************************/
+
+#include "ets_sys.h"
+#include "hal/max17043.h"
+#include "osapi.h"
+#include "driver/i2c_master.h"
+
+/******************************************************************************
+ * FunctionName : max17042_get_voltage()
+ * Description  : get 12-bit ADC voltage value from gas gauge IC
+                  VCELL FORMAT (MSB first)
+                  [d|d|d|d|d|d|d|d] [d|d|d|d|0|0|0|0]
+                  d = vaild data
+                  0 = nothing
+                  resolution = 1.25mV
+                  NOTE: 500ms after POR or sleep for vaild value
+ * Parameters   : NONE
+ * Returns      : uint16_t, 0 if failed
+*******************************************************************************/
+
+uint16_t ICACHE_FLASH_ATTR
+max17043_getVoltage(void)
+{
+	max17043_i2c_init();
+	uint16_t voltage;
+
+	//i2c_master_init();
+	i2c_master_start();
+	i2c_master_writeByte(WRITE_ADDRESS);
+	if (!i2c_master_checkAck()) {
+		i2c_master_stop();
+		return 0;
+	}
+
+	i2c_master_writeByte(VCELL_H);
+	if (!i2c_master_checkAck()) {
+		i2c_master_stop();
+		return 0;
+	}
+
+	i2c_master_start();
+	i2c_master_writeByte(READ_ADDRESS);
+	if (!i2c_master_checkAck()) {
+		i2c_master_stop();
+		return 0;
+	}
+	voltage = (i2c_master_readByte() << 4);
+	i2c_master_send_ack();
+	voltage |= (i2c_master_readByte() >> 4);
+	i2c_master_send_nack();
+	i2c_master_stop();
+    #if MAX17043_DEBUG
+        os_printf("Voltage: %d\r\n", voltage);
+    #endif
+	return voltage;
+}
+/******************************************************************************
+ * FunctionName : max17042_getSOC
+ * Description  : get 16-bit SOC value from gas gauge IC
+                  SOC FORMAT
+                  [2^7|2^6|2^5|2^4|...|2^0][2^-1|2^-2|...|2^-8]
+                  Resolution 1.0%
+ * Parameters   : NONE
+ * Returns      : uint16_t, 0 if failed
+*******************************************************************************/
+uint16_t ICACHE_FLASH_ATTR
+max17043_getSOC(void)
+{
+	max17043_i2c_init();
+    uint16_t soc;
+    i2c_master_start();                     // sent srt. cond.
+    i2c_master_writeByte(WRITE_ADDRESS);    // send w. addr.
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_writeByte(SOC_H);          // sent reg. addr. to be read
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+
+    i2c_master_start();
+    i2c_master_writeByte(READ_ADDRESS);     // send r. addr.
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    soc = (i2c_master_readByte()<<8);       // read VCELL_H into voltage
+    i2c_master_send_ack();                  // sent ack.
+    soc |= i2c_master_readByte();           // read VCELL_L into voltage
+    i2c_master_send_nack();                 // send nack.
+    i2c_master_stop();                      // send stop cond.
+    #if MAX17043_DEBUG
+        os_printf("SOC: %d\r\n", soc);
+    #endif
+    return soc;
+}
+/******************************************************************************
+ * FunctionName : max17042_sleep
+ * Description  : sets gas gauge IC to sleep
+ * Parameters   : uint8_t enable, true: set to sleep, false: wake from sleep
+ * Returns      : Success 1, Fail 0
+*******************************************************************************/
+bool ICACHE_FLASH_ATTR
+max17043_sleep(uint8_t enable)
+{
+	max17043_i2c_init();
+    i2c_master_start();
+    i2c_master_writeByte(WRITE_ADDRESS);
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_writeByte(CONFIG_L);
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    if (enable) {
+        i2c_master_writeByte(0x80);
+    }
+    else {
+        i2c_master_writeByte(0x00);
+    }
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_stop();
+    return 1;
+}
+/******************************************************************************
+ * FunctionName : max17042_quick_start
+ * Description  : soft reset gas guage IC to fix battery calculation
+ * Parameters   : NONE
+ * Returns      : Success 1, Failed o
+*******************************************************************************/
+bool ICACHE_FLASH_ATTR
+max17043_quickStart(void)
+{
+    i2c_master_start();
+    i2c_master_writeByte(WRITE_ADDRESS);
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_writeByte(MODE_H);
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_writeByte(0x40);
+    if (!i2c_master_checkAck()){
+    	i2c_master_stop();
+    }
+    i2c_master_writeByte(0x00);
+    if (!i2c_master_checkAck()) {
+        i2c_master_stop();
+        return 0;
+    }
+    i2c_master_stop();
+    return 1;
+}

+ 164 - 0
hal/ws2812.c

@@ -0,0 +1,164 @@
+#include "hal/ws2812.h"
+#include "ets_sys.h"
+#include "osapi.h"
+#include "gpio.h"
+#include "math.h"
+
+#define LEDUPDATEDELAY 60
+
+//       	LOCAL const
+
+LOCAL uint8_t pulseBuffer[100] = { 127, 135, 143, 151, 159, 166, 174, 181, 188,
+								   195, 202, 208, 214, 220, 225, 230, 235, 239,
+								   242, 246, 248, 250, 252, 253, 254, 255, 254,
+								   253, 252, 250, 248, 246, 242, 239, 235, 230,
+								   225, 220, 214, 208, 202, 195, 188, 181, 174,
+								   166, 159, 151, 143, 135, 127, 119, 111, 103,
+								   95, 88, 80, 73, 66, 59, 52, 46, 40, 34, 29,
+								   24, 19, 15, 12, 8, 6, 4, 2, 1, 0, 0, 0, 1, 2,
+								   4, 6, 8, 12, 15, 19, 24, 29, 34, 40, 46, 52,
+								   59, 66, 73, 80, 88, 95, 103, 111, 119};
+
+
+// LOCAL uint8_t pulseBuffer[100] = { 50, 53, 56, 59, 62, 65, 68, 71,
+// 							  74, 76, 79, 81, 84, 86, 88, 90,
+// 							  92, 93, 95, 96, 97, 98, 99, 99,
+// 							  99, 100, 99, 99, 99, 98, 97, 96,
+// 							  95, 93, 92, 90, 88, 86, 84, 81,
+// 							  79, 76, 74, 71, 68, 65, 62, 59,
+// 							  56, 53, 50, 46, 43, 40, 37, 34,
+// 							  31, 28, 25, 23, 20, 18, 15, 13,
+// 							  11, 9, 7, 6, 4, 3, 2, 1, 0, 0,
+// 							  0, 0, 0, 0, 0, 1, 2, 3, 4, 6,
+// 							  7, 9, 11, 13, 15, 18, 20, 23,
+// 							  25, 28, 31, 34, 37, 40, 43, 46};
+
+// uint8_t pulseBuffer[100] = {68, 75, 83, 90, 99, 107, 116, 126,
+//  							135, 145, 155, 165, 175, 184, 194,
+//  							203, 212, 220, 228, 235, 240, 245,
+//  							249, 252, 254, 255, 254, 252, 249,
+//  							245, 240, 235, 228, 220, 212, 203,
+//  							194, 184, 175, 165, 155, 145, 135,
+//  							126, 116, 107, 99, 90, 83, 75, 68,
+//  							61, 55, 50, 44, 39, 35, 30, 27, 23,
+//  							20, 17, 14, 12, 10, 8, 6, 5, 3, 2,
+//  							2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2,
+//  							3, 5, 6, 8, 10, 12, 14, 17, 20, 23,
+//  							27, 30, 35, 39, 44, 50, 55, 61};
+// LOCAL uint8_t pulseBuffer[100] = {26, 29, 32, 35, 38, 42, 45, 49,
+// 								  53, 57, 60, 64, 68, 72, 76, 79,
+// 								  83, 86, 89, 92, 94, 96, 97, 99,
+// 								  99, 100, 99, 99, 97, 96, 94, 92,
+// 								  89, 86, 83, 79, 76, 72, 68, 64,
+// 								  60, 57, 53, 49, 45, 42, 38, 35,
+// 								  32, 29, 26, 24, 21, 19, 17, 15,
+// 								  13, 12, 10, 9, 7, 6, 5, 4, 4,
+// 								  3, 2, 2, 1, 1, 0, 0, 0, 0, 0,
+// 								  0, 0, 0, 0, 0, 0, 1, 1, 2, 2,
+// 								  3, 4, 4, 5, 6, 7, 9, 10, 12,
+// 								  13, 15, 17, 19, 21, 24};
+
+LOCAL uint8_t ledState;
+LOCAL os_timer_t statLEDTimer;
+
+
+//#define GPIO_OUTPUT_SET(gpio_no, bit_value)
+//	gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)
+
+
+static void send_ws_0(void)
+{
+	uint8_t time;
+#if WS2811_COMPATIBLE
+	time = 7; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
+	time = 28; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
+#else
+	// time = 6; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
+	// time = 10; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
+	//os_printf("Hola\r\n");
+	time = 6; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO));
+	time = 10; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO));
+#endif
+}
+
+static void send_ws_1(void)
+{
+	uint8_t time;
+#if WS2811_COMPATIBLE
+	time = 15; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
+	time = 16; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
+#else
+	// time = 10; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
+	// time = 6; while(time--) WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
+	time = 10; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, BIT(WSGPIO));
+	time = 6; while(time--) GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, BIT(WSGPIO));
+	//os_printf("Hermosa\r\n");
+#endif
+}
+
+// void ws2812_outBuffer( uint8_t * buffer, uint16_t length )
+// {
+// 	ETS_INTR_LOCK();							// why is this different than a normal disable interupts again?
+// 	uint16_t i;
+// 	GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);	// set gpio as output (redundent?)
+//
+//
+// 	for( i = 0; i < length; i++ )
+// 	{
+// 		uint8_t mask = 0x80;
+// 		uint8_t byte = buffer[i];
+// 		while (mask)
+// 		{
+// 			if( byte & mask ) send_ws_1(); else send_ws_0();
+// 			mask >>= 1;
+//         }
+// 	}
+//
+// 	ETS_INTR_LOCK();
+// }
+//
+// void updateLED(void)
+// {
+// 	uint8_t outBuffer[3] = {0, 0, 0};
+// 	uint8_t ledValue = pulseBuffer[ledState];
+//
+// 	if (sysCfg.module_state.searching == TRUE)
+// 	{
+// 		outBuffer[0] = ledValue;
+// 	}
+// 	else if (sysCfg.module_state.connected == TRUE)
+// 	{
+// 		outBuffer[2] = ledValue;
+// 	}
+// 	else
+// 	{
+// 		outBuffer[1] = ledValue;
+// 	}
+// 	ws2812_outBuffer(outBuffer, sizeof(outBuffer));
+// 	ledState++;
+// 	if (ledState == sizeof(pulseBuffer))
+// 		ledState = 0;
+// }
+//
+// void ws2812_shutdown(void)
+// {
+// 	os_timer_disarm(&statLEDTimer);
+// 	uint8_t i, outBuf[3] = {0x00, 0x00, 0x00};
+// 	for(i=0;i<6;i++)
+// 	{
+// 		outBuf[1] = outBuf[1] ^ 0xFF;
+// 		ws2812_outBuffer(outBuf, sizeof(outBuf));
+// 		os_delay_us(500000);
+// 	}
+// }
+//
+// void ws2812_init(void)
+// {
+// 	sin(0);
+// 	ledState = 0;
+// 	uint8_t initBuffer[3] = {0x00, 0x00, 0x00};
+// 	ws2812_outBuffer(initBuffer, sizeof(initBuffer));
+// 	os_timer_disarm(&statLEDTimer);												// disarm health publish timer
+// 	os_timer_setfn(&statLEDTimer, (os_timer_func_t *)updateLED, NULL);	// attach function for health publish
+// 	os_timer_arm(&statLEDTimer, LEDUPDATEDELAY, 1); 								// activate health packet timer
+// }

+ 33 - 0
include/driver/gpio16.h

@@ -0,0 +1,33 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 __GPIO16_H__
+#define __GPIO16_H__
+
+void gpio16_output_conf(void);
+void gpio16_output_set(uint8 value);
+void gpio16_input_conf(void);
+uint8 gpio16_input_get(void);
+
+#endif

+ 93 - 0
include/driver/i2c_master.h

@@ -0,0 +1,93 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 __I2C_MASTER_H__
+#define __I2C_MASTER_H__
+
+/*------------------------------------------------------------------------------*/
+// Configuration for V0.2 ideasX Module
+// SCL Line = I2C Clock
+// SDA Line = I2C Data
+/*------------------------------------------------------------------------------*/
+#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_MTCK_U	//PERIPHS_IO_MUX_GPIO2_U
+#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U    //PERIPHS_IO_MUX_MTMS_U
+#define I2C_MASTER_SDA_GPIO 13	                    //2
+#define I2C_MASTER_SCL_GPIO 14	                    //14
+#define I2C_MASTER_SDA_FUNC FUNC_GPIO13	            //FUNC_GPIO2
+#define I2C_MASTER_SCL_FUNC FUNC_GPIO14	            //FUNC_GPIO14
+
+// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
+// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U
+// #define I2C_MASTER_SDA_GPIO 2
+// #define I2C_MASTER_SCL_GPIO 14
+// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2
+// #define I2C_MASTER_SCL_FUNC FUNC_GPIO14
+
+//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U
+//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U
+//#define I2C_MASTER_SDA_GPIO 2
+//#define I2C_MASTER_SCL_GPIO 0
+//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2
+//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0
+
+#if 0
+#define I2C_MASTER_GPIO_SET(pin)  \
+    gpio_output_set(1<<pin,0,1<<pin,0)
+
+#define I2C_MASTER_GPIO_CLR(pin) \
+    gpio_output_set(0,1<<pin,1<<pin,0)
+
+#define I2C_MASTER_GPIO_OUT(pin,val) \
+    if(val) I2C_MASTER_GPIO_SET(pin);\
+    else I2C_MASTER_GPIO_CLR(pin)
+#endif
+
+#define I2C_MASTER_SDA_HIGH_SCL_HIGH()  \
+    gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
+
+#define I2C_MASTER_SDA_HIGH_SCL_LOW()  \
+    gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
+
+#define I2C_MASTER_SDA_LOW_SCL_HIGH()  \
+    gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
+
+#define I2C_MASTER_SDA_LOW_SCL_LOW()  \
+    gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)
+
+void i2c_master_gpio_init(void);
+void i2c_master_init(void);
+
+#define i2c_master_wait    os_delay_us
+void i2c_master_stop(void);
+void i2c_master_start(void);
+void i2c_master_setAck(uint8 level);
+uint8 i2c_master_getAck(void);
+uint8 i2c_master_readByte(void);
+void i2c_master_writeByte(uint8 wrdata);
+
+bool i2c_master_checkAck(void);
+void i2c_master_send_ack(void);
+void i2c_master_send_nack(void);
+
+#endif

+ 51 - 0
include/driver/key.h

@@ -0,0 +1,51 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 __KEY_H__
+#define __KEY_H__
+
+#include "gpio.h"
+
+typedef void (* key_function)(void);
+
+struct single_key_param {
+    uint8 key_level;
+    uint8 gpio_id;
+    uint8 gpio_func;
+    uint32 gpio_name;
+    os_timer_t key_5s;
+    os_timer_t key_50ms;
+    key_function short_press;
+    key_function long_press;
+};
+
+struct keys_param {
+    uint8 key_num;
+    struct single_key_param **single_key;
+};
+
+struct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press);
+void key_init(struct keys_param *key);
+
+#endif

+ 40 - 0
include/driver/sdio_slv.h

@@ -0,0 +1,40 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 __SDIO_SLAVE_H__
+#define __SDIO_SLAVE_H__
+#include "c_types.h"

+#include "user_interface.h"
+
+#define RX_AVAILIBLE 2
+#define TX_AVAILIBLE 1
+#define INIT_STAGE	 0
+
+void sdio_slave_init(void);
+
+int32 sdio_load_data(const uint8* data,uint32 len);
+typedef void (*sdio_recv_data_callback_t)(uint8* data,uint32 len);
+
+bool sdio_register_recv_cb(sdio_recv_data_callback_t cb);
+#endif

+ 300 - 0
include/driver/slc_register.h

@@ -0,0 +1,300 @@
+//Generated at 2012-10-23 19:55:03
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 SLC_REGISTER_H_
+#define SLC_REGISTER_H_
+
+#define REG_SLC_BASE  0x60000B00
+//version value:32'h091700
+
+#define SLC_CONF0                                (REG_SLC_BASE + 0x0)
+#ifndef ESP_MAC_5
+#define SLC_MODE 0x00000003
+#define SLC_MODE_S 12
+#endif
+#define SLC_DATA_BURST_EN (BIT(9))
+#define SLC_DSCR_BURST_EN (BIT(8))
+#define SLC_RX_NO_RESTART_CLR (BIT(7))
+#define SLC_RX_AUTO_WRBACK (BIT(6))
+#define SLC_RX_LOOP_TEST (BIT(5))
+#define SLC_TX_LOOP_TEST (BIT(4))
+#define SLC_AHBM_RST (BIT(3))
+#define SLC_AHBM_FIFO_RST (BIT(2))
+#define SLC_RXLINK_RST (BIT(1))
+#define SLC_TXLINK_RST (BIT(0))
+
+#define SLC_INT_RAW                              (REG_SLC_BASE + 0x4)
+#define SLC_TX_DSCR_EMPTY_INT_RAW (BIT(21))
+#define SLC_RX_DSCR_ERR_INT_RAW (BIT(20))
+#define SLC_TX_DSCR_ERR_INT_RAW (BIT(19))
+#define SLC_TOHOST_INT_RAW (BIT(18))
+#define SLC_RX_EOF_INT_RAW (BIT(17))
+#define SLC_RX_DONE_INT_RAW (BIT(16))
+#define SLC_TX_EOF_INT_RAW (BIT(15))
+#define SLC_TX_DONE_INT_RAW (BIT(14))
+#define SLC_TOKEN1_1TO0_INT_RAW (BIT(13))
+#define SLC_TOKEN0_1TO0_INT_RAW (BIT(12))
+#define SLC_TX_OVF_INT_RAW (BIT(11))
+#define SLC_RX_UDF_INT_RAW (BIT(10))
+#define SLC_TX_START_INT_RAW (BIT(9))
+#define SLC_RX_START_INT_RAW (BIT(8))
+#define SLC_FRHOST_BIT7_INT_RAW (BIT(7))
+#define SLC_FRHOST_BIT6_INT_RAW (BIT(6))
+#define SLC_FRHOST_BIT5_INT_RAW (BIT(5))
+#define SLC_FRHOST_BIT4_INT_RAW (BIT(4))
+#define SLC_FRHOST_BIT3_INT_RAW (BIT(3))
+#define SLC_FRHOST_BIT2_INT_RAW (BIT(2))
+#define SLC_FRHOST_BIT1_INT_RAW (BIT(1))
+#define SLC_FRHOST_BIT0_INT_RAW (BIT(0))
+
+#define SLC_INT_STATUS                               (REG_SLC_BASE + 0x8)
+#define SLC_TX_DSCR_EMPTY_INT_ST (BIT(21))
+#define SLC_RX_DSCR_ERR_INT_ST (BIT(20))
+#define SLC_TX_DSCR_ERR_INT_ST (BIT(19))
+#define SLC_TOHOST_INT_ST (BIT(18))
+#define SLC_RX_EOF_INT_ST (BIT(17))
+#define SLC_RX_DONE_INT_ST (BIT(16))
+#define SLC_TX_EOF_INT_ST (BIT(15))
+#define SLC_TX_DONE_INT_ST (BIT(14))
+#define SLC_TOKEN1_1TO0_INT_ST (BIT(13))
+#define SLC_TOKEN0_1TO0_INT_ST (BIT(12))
+#define SLC_TX_OVF_INT_ST (BIT(11))
+#define SLC_RX_UDF_INT_ST (BIT(10))
+#define SLC_TX_START_INT_ST (BIT(9))
+#define SLC_RX_START_INT_ST (BIT(8))
+#define SLC_FRHOST_BIT7_INT_ST (BIT(7))
+#define SLC_FRHOST_BIT6_INT_ST (BIT(6))
+#define SLC_FRHOST_BIT5_INT_ST (BIT(5))
+#define SLC_FRHOST_BIT4_INT_ST (BIT(4))
+#define SLC_FRHOST_BIT3_INT_ST (BIT(3))
+#define SLC_FRHOST_BIT2_INT_ST (BIT(2))
+#define SLC_FRHOST_BIT1_INT_ST (BIT(1))
+#define SLC_FRHOST_BIT0_INT_ST (BIT(0))
+
+#define SLC_INT_ENA                              (REG_SLC_BASE + 0xC)
+#define SLC_TX_DSCR_EMPTY_INT_ENA (BIT(21))
+#define SLC_RX_DSCR_ERR_INT_ENA (BIT(20))
+#define SLC_TX_DSCR_ERR_INT_ENA (BIT(19))
+#define SLC_TOHOST_INT_ENA (BIT(18))
+#define SLC_RX_EOF_INT_ENA (BIT(17))
+#define SLC_RX_DONE_INT_ENA (BIT(16))
+#define SLC_TX_EOF_INT_ENA (BIT(15))
+#define SLC_TX_DONE_INT_ENA (BIT(14))
+#define SLC_TOKEN1_1TO0_INT_ENA (BIT(13))
+#define SLC_TOKEN0_1TO0_INT_ENA (BIT(12))
+#define SLC_TX_OVF_INT_ENA (BIT(11))
+#define SLC_RX_UDF_INT_ENA (BIT(10))
+#define SLC_TX_START_INT_ENA (BIT(9))
+#define SLC_RX_START_INT_ENA (BIT(8))
+#define SLC_FRHOST_BIT7_INT_ENA (BIT(7))
+#define SLC_FRHOST_BIT6_INT_ENA (BIT(6))
+#define SLC_FRHOST_BIT5_INT_ENA (BIT(5))
+#define SLC_FRHOST_BIT4_INT_ENA (BIT(4))
+#define SLC_FRHOST_BIT3_INT_ENA (BIT(3))
+#define SLC_FRHOST_BIT2_INT_ENA (BIT(2))
+#define SLC_FRHOST_BIT1_INT_ENA (BIT(1))
+#define SLC_FRHOST_BIT0_INT_ENA (BIT(0))
+
+#define SLC_FRHOST_BIT_INT_ENA_ALL  0xff
+
+#define SLC_INT_CLR                              (REG_SLC_BASE + 0x10)
+#define SLC_TX_DSCR_EMPTY_INT_CLR (BIT(21))
+#define SLC_RX_DSCR_ERR_INT_CLR (BIT(20))
+#define SLC_TX_DSCR_ERR_INT_CLR (BIT(19))
+#define SLC_TOHOST_INT_CLR (BIT(18))
+#define SLC_RX_EOF_INT_CLR (BIT(17))
+#define SLC_RX_DONE_INT_CLR (BIT(16))
+#define SLC_TX_EOF_INT_CLR (BIT(15))
+#define SLC_TX_DONE_INT_CLR (BIT(14))
+#define SLC_TOKEN1_1TO0_INT_CLR (BIT(13))
+#define SLC_TOKEN0_1TO0_INT_CLR (BIT(12))
+#define SLC_TX_OVF_INT_CLR (BIT(11))
+#define SLC_RX_UDF_INT_CLR (BIT(10))
+#define SLC_TX_START_INT_CLR (BIT(9))
+#define SLC_RX_START_INT_CLR (BIT(8))
+#define SLC_FRHOST_BIT7_INT_CLR (BIT(7))
+#define SLC_FRHOST_BIT6_INT_CLR (BIT(6))
+#define SLC_FRHOST_BIT5_INT_CLR (BIT(5))
+#define SLC_FRHOST_BIT4_INT_CLR (BIT(4))
+#define SLC_FRHOST_BIT3_INT_CLR (BIT(3))
+#define SLC_FRHOST_BIT2_INT_CLR (BIT(2))
+#define SLC_FRHOST_BIT1_INT_CLR (BIT(1))
+#define SLC_FRHOST_BIT0_INT_CLR (BIT(0))
+
+#define SLC_RX_STATUS                            (REG_SLC_BASE + 0x14)
+#define SLC_RX_EMPTY (BIT(1))
+#define SLC_RX_FULL (BIT(0))
+
+#define SLC_RX_FIFO_PUSH                          (REG_SLC_BASE + 0x18)
+#define SLC_RXFIFO_PUSH (BIT(16))
+#define SLC_RXFIFO_WDATA 0x000001FF
+#define SLC_RXFIFO_WDATA_S 0
+
+#define SLC_TX_STATUS                            (REG_SLC_BASE + 0x1C)
+#define SLC_TX_EMPTY (BIT(1))
+#define SLC_TX_FULL (BIT(0))
+
+#define SLC_TX_FIFO_POP                           (REG_SLC_BASE + 0x20)
+#define SLC_TXFIFO_POP (BIT(16))
+#define SLC_TXFIFO_RDATA 0x000007FF
+#define SLC_TXFIFO_RDATA_S 0
+
+#define SLC_RX_LINK                              (REG_SLC_BASE + 0x24)
+#define SLC_RXLINK_PARK (BIT(31))
+#define SLC_RXLINK_RESTART (BIT(30))
+#define SLC_RXLINK_START  (BIT(29))
+#define SLC_RXLINK_STOP  (BIT(28))
+#define SLC_RXLINK_DESCADDR_MASK 0x000FFFFF
+#define SLC_RXLINK_ADDR_S 0
+
+#define SLC_TX_LINK                              (REG_SLC_BASE + 0x28)
+#define SLC_TXLINK_PARK (BIT(31))
+#define SLC_TXLINK_RESTART (BIT(30))
+#define SLC_TXLINK_START  (BIT(29))
+#define SLC_TXLINK_STOP  (BIT(28))
+#define SLC_TXLINK_DESCADDR_MASK 0x000FFFFF
+#define SLC_TXLINK_ADDR_S 0
+
+#define SLC_INTVEC_TOHOST                        (REG_SLC_BASE + 0x2C)
+#define SLC_TOHOST_INTVEC 0x000000FF
+#define SLC_TOHOST_INTVEC_S 0
+
+#define SLC_TOKEN0                               (REG_SLC_BASE + 0x30)
+#define SLC_TOKEN0_MASK 0x00000FFF
+#define SLC_TOKEN0_S 16
+#define SLC_TOKEN0_LOCAL_INC_MORE (BIT(14))
+#define SLC_TOKEN0_LOCAL_INC (BIT(13))
+#define SLC_TOKEN0_LOCAL_WR (BIT(12))
+#define SLC_TOKEN0_LOCAL_WDATA_MASK 0x00000FFF
+#define SLC_TOKEN0_LOCAL_WDATA_S 0
+
+#define SLC_TOKEN1                               (REG_SLC_BASE + 0x34)
+#define SLC_TOKEN1_MASK 0x00000FFF
+#define SLC_TOKEN1_S 16
+#define SLC_TOKEN1_LOCAL_INC_MORE (BIT(14))
+#define SLC_TOKEN1_LOCAL_INC (BIT(13))
+#define SLC_TOKEN1_LOCAL_WR (BIT(12))
+#define SLC_TOKEN1_LOCAL_WDATA 0x00000FFF
+#define SLC_TOKEN1_LOCAL_WDATA_S 0
+
+#define SLC_CONF1                                (REG_SLC_BASE + 0x38)
+#define SLC_STATE0                               (REG_SLC_BASE + 0x3C)
+#define SLC_STATE1                               (REG_SLC_BASE + 0x40)
+
+#define SLC_BRIDGE_CONF                          (REG_SLC_BASE + 0x44)
+#ifndef ESP_MAC_5
+#define SLC_TX_PUSH_IDLE_NUM 0x0000FFFF
+#define SLC_TX_PUSH_IDLE_NUM_S 16
+#define SLC_TX_DUMMY_MODE (BIT(12))
+#endif
+#define SLC_FIFO_MAP_ENA 0x0000000F
+#define SLC_FIFO_MAP_ENA_S 8
+#define SLC_TXEOF_ENA  0x0000003F
+#define SLC_TXEOF_ENA_S 0
+
+#define SLC_RX_EOF_DES_ADDR                       (REG_SLC_BASE + 0x48)
+#define SLC_TX_EOF_DES_ADDR                       (REG_SLC_BASE + 0x4C)
+#define SLC_FROM_HOST_LAST_DESC                   SLC_TX_EOF_DES_ADDR
+#define SLC_TO_HOST_LAST_DESC                     SLC_RX_EOF_DES_ADDR
+
+#define SLC_RX_EOF_BFR_DES_ADDR                 (REG_SLC_BASE + 0x50)
+#define SLC_AHB_TEST                            (REG_SLC_BASE + 0x54)
+#define SLC_AHB_TESTADDR 0x00000003
+#define SLC_AHB_TESTADDR_S 4
+#define SLC_AHB_TESTMODE 0x00000007
+#define SLC_AHB_TESTMODE_S 0
+
+#define SLC_SDIO_ST                             (REG_SLC_BASE + 0x58)
+#define SLC_BUS_ST 0x00000007
+#define SLC_BUS_ST_S 12
+#define SLC_SDIO_WAKEUP (BIT(8))
+#define SLC_FUNC_ST 0x0000000F
+#define SLC_FUNC_ST_S 4
+#define SLC_CMD_ST 0x00000007
+#define SLC_CMD_ST_S 0
+
+#define SLC_RX_DSCR_CONF                        (REG_SLC_BASE + 0x5C)
+#ifdef ESP_MAC_5
+#define SLC_INFOR_NO_REPLACE (BIT(9))
+#define SLC_TOKEN_NO_REPLACE (BIT(8))
+#define SLC_POP_IDLE_CNT 0x000000FF
+#else
+#define SLC_RX_FILL_EN (BIT(20))
+#define SLC_RX_EOF_MODE (BIT(19))
+#define SLC_RX_FILL_MODE (BIT(18))
+#define SLC_INFOR_NO_REPLACE (BIT(17))
+#define SLC_TOKEN_NO_REPLACE (BIT(16))  //
+#define SLC_POP_IDLE_CNT 0x0000FFFF
+#endif
+#define SLC_POP_IDLE_CNT_S 0
+
+#define SLC_TXLINK_DSCR                         (REG_SLC_BASE + 0x60)
+#define SLC_TXLINK_DSCR_BF0                     (REG_SLC_BASE + 0x64)
+#define SLC_TXLINK_DSCR_BF1                     (REG_SLC_BASE + 0x68)
+#define SLC_RXLINK_DSCR                         (REG_SLC_BASE + 0x6C)
+#define SLC_RXLINK_DSCR_BF0                     (REG_SLC_BASE + 0x70)
+#define SLC_RXLINK_DSCR_BF1                     (REG_SLC_BASE + 0x74)
+#define SLC_DATE                                 (REG_SLC_BASE + 0x78)
+#define SLC_ID                                   (REG_SLC_BASE + 0x7C)
+
+#define SLC_HOST_CONF_W0                         (REG_SLC_BASE + 0x80 + 0x14)
+#define SLC_HOST_CONF_W1                         (REG_SLC_BASE + 0x80 + 0x18)
+#define SLC_HOST_CONF_W2                         (REG_SLC_BASE + 0x80 + 0x20)
+#define SLC_HOST_CONF_W3                         (REG_SLC_BASE + 0x80 + 0x24)
+#define SLC_HOST_CONF_W4                         (REG_SLC_BASE + 0x80 + 0x28)
+
+#define SLC_HOST_INTR_ST                         (REG_SLC_BASE + 0x80 + 0x1c)
+#define SLC_HOST_INTR_CLR                         (REG_SLC_BASE + 0x80 + 0x30)
+#define SLC_HOST_INTR_SOF_BIT                     (BIT(12))
+
+#define SLC_HOST_INTR_ENA                         (REG_SLC_BASE + 0x80 + 0x34)
+#define SLC_RX_NEW_PACKET_INT_ENA 		(BIT23)
+#define SLC_HOST_TOHOST_BIT0_INT_ENA		(BIT0)
+#define SLC_HOST_CONF_W5                          (REG_SLC_BASE + 0x80 + 0x3C)
+#define SLC_HOST_INTR_RAW                         (REG_SLC_BASE + 0x80 + 0x8)
+#define SLC_HOST_INTR_ENA_BIT                      (BIT(23))
+//[15:12]: 0x3ff9xxxx -- 0b01  from_host
+//         0x3ffaxxxx -- 0b10  general
+//         0x3ffbxxxx -- 0b11  to_host
+#define SLC_DATA_ADDR_CLEAR_MASK                    (~(0xf<<12)) 
+#define SLC_FROM_HOST_ADDR_MASK                     (0x1<<12)
+#define SLC_TO_HOST_ADDR_MASK                       (0x3<<12)
+
+#define SLC_SET_FROM_HOST_ADDR_MASK(v)   do { \
+    (v) &= SLC_DATA_ADDR_CLEAR_MASK;  \
+    (v) |= SLC_FROM_HOST_ADDR_MASK;   \
+} while(0);
+
+#define SLC_SET_TO_HOST_ADDR_MASK(v)   do { \
+    (v) &= SLC_DATA_ADDR_CLEAR_MASK;  \
+    (v) |= SLC_TO_HOST_ADDR_MASK;   \
+} while(0);
+
+
+#define SLC_TX_DESC_DEBUG_REG  0x3ff0002c  //[15:0] set to 0xcccc
+
+
+#endif // SLC_REGISTER_H_INCLUDED

+ 74 - 0
include/driver/spi.h

@@ -0,0 +1,74 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 "spi_register.h"
+#include "ets_sys.h"
+#include "osapi.h"
+#include "uart.h"
+#include "os_type.h"
+#include "spi_flash.h"
+
+#define SPI_FLASH_BYTES_LEN                24
+#define IODATA_START_ADDR                 BIT0
+#define SPI_BUFF_BYTE_NUM                    32
+
+/*SPI number define*/
+#define SPI 			0
+#define HSPI			1
+
+void cache_flush(void);
+//spi master init funtion
+void spi_master_init(uint8 spi_no);
+
+//lcd drive function
+void spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit);
+//use spi send 8bit data
+void spi_mast_byte_write(uint8 spi_no,uint8 data);
+
+//transmit data to esp8266 slave buffer,which needs 16bit transmission ,
+//first byte is master command 0x04, second byte is master data
+void spi_byte_write_espslave(uint8 spi_no,uint8 data);
+//read data from esp8266 slave buffer,which needs 16bit transmission ,
+//first byte is master command 0x06, second byte is to read slave data
+void spi_byte_read_espslave(uint8 spi_no,uint8 *data);
+
+ //esp8266 slave mode initial
+void spi_slave_init(uint8 spi_no,uint8 data_len);
+  //esp8266 slave isr handle funtion,tiggered when any transmission is finished.
+  //the function is registered in spi_slave_init.
+void spi_slave_isr_handler(void *para); 
+
+
+//hspi test function, used to test esp8266 spi slave
+void hspi_master_readwrite_repeat(void);
+
+
+void spi_test_init(void);
+
+
+#endif
+

+ 353 - 0
include/driver/spi_interface.h

@@ -0,0 +1,353 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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.
+ *
+ */
+
+/**
+ * @file spi_interface.h
+ * @brief Defines and Macros for the SPI.
+ */
+#ifndef __SPI_INTERFACE_H__
+#define __SPI_INTERFACE_H__
+
+#include "driver/spi_register.h"
+#include "c_types.h"
+
+//*****************************************************************************
+//
+// Make sure all of the definitions in this header have a C binding.
+//
+//*****************************************************************************
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/**
+ * @brief Defines slave commands. Default value based on slave ESP8266.
+ */
+#define MASTER_WRITE_DATA_TO_SLAVE_CMD                      2
+#define MASTER_READ_DATA_FROM_SLAVE_CMD                     3
+
+#define MASTER_WRITE_STATUS_TO_SLAVE_CMD                    1
+#define MASTER_READ_STATUS_FROM_SLAVE_CMD                   4
+
+/**
+ * @brief Support HSPI and SPI module.
+ *
+ */
+typedef enum
+{
+    SpiNum_SPI   = 0,
+    SpiNum_HSPI  = 1,
+} SpiNum;
+
+/**
+ * @brief The SPI module can work in either master or slave mode.
+ *
+ */
+typedef enum
+{
+    SpiMode_Master = 0,
+    SpiMode_Slave  = 1,
+} SpiMode;
+
+/**
+ *  @brief SPI sub mode
+ *
+ * Support 4 sub modes based on SPI clock polarity and phase.
+ * SPI_CPOL SPI_CPHA  SubMode
+ *   0        0        0
+ *   0        1        1
+ *   1        0        2
+ *   1        1        3
+ */
+typedef enum
+{
+    SpiSubMode_0 = 0,
+    SpiSubMode_1 = 1,
+    SpiSubMode_2 = 2,
+    SpiSubMode_3 = 3,
+} SpiSubMode;
+
+/**
+ * @brief The SPI module working speed.
+ *
+ * @attention Max speed 80MHz
+ *
+ */
+typedef enum
+{
+    SpiSpeed_0_5MHz     = 160,
+    SpiSpeed_1MHz       = 80,
+    SpiSpeed_2MHz       = 40,
+    SpiSpeed_5MHz       = 16,
+    SpiSpeed_8MHz       = 10,
+    SpiSpeed_10MHz      = 8,
+ 
+} SpiSpeed;
+
+/**
+ * @brief The SPI mode working speed.
+ *
+ */
+typedef enum
+{
+    SpiBitOrder_MSBFirst = 0,
+    SpiBitOrder_LSBFirst = 1,
+} SpiBitOrder;
+
+// @brief SPI interrupt soource defined.
+typedef enum
+{
+    SpiIntSrc_TransDone = SPI_TRANS_DONE,
+    SpiIntSrc_WrStaDone = SPI_SLV_WR_STA_DONE,
+    SpiIntSrc_RdStaDone = SPI_SLV_RD_STA_DONE,
+    SpiIntSrc_WrBufDone = SPI_SLV_WR_BUF_DONE,
+    SpiIntSrc_RdBufDone = SPI_SLV_RD_BUF_DONE,
+} SpiIntSrc;
+
+// @brief SPI CS pin.
+typedef enum
+{
+    SpiPinCS_0 = 1,
+    SpiPinCS_1 = 2,
+    SpiPinCS_2 = 4,
+} SpiPinCS;
+
+#pragma pack (1)
+
+/**
+ * @brief SPI attribute
+ */
+typedef struct
+{
+    SpiMode        mode;           ///< Master or slave mode
+    SpiSubMode     subMode;        ///< SPI SPI_CPOL SPI_CPHA mode
+    SpiSpeed       speed;          ///< SPI Clock
+    SpiBitOrder    bitOrder;       ///< SPI bit order
+} SpiAttr;
+
+/**
+ * @brief SPI data package
+ */
+typedef struct
+{
+    uint16_t    cmd;            ///< Command value
+    uint8_t     cmdLen;         ///< Command byte length
+    uint32_t    *addr;          ///< Point to address value
+    uint8_t     addrLen;        ///< Address byte length
+    uint32_t    *data;          ///< Point to data buffer
+    uint8_t     dataLen;        ///< Data byte length.
+} SpiData;
+
+
+/**
+ * @brief SPI interrupt information
+ */
+typedef struct
+{
+    SpiIntSrc       src;                ///< Interrupt source  
+    void            *isrFunc;           ///< SPI interrupt callback function.
+
+} SpiIntInfo;
+
+#pragma upack (1)
+
+/**
+ * @brief Initialize SPI module.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pAttr
+ *             Pointer to a struct SpiAttr that indicates SPI working attribution.
+ *
+ * @return void.
+ */
+void SPIInit(SpiNum spiNum, SpiAttr* pAttr);
+
+/**
+ * @brief Set slave address value by master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] addr
+ *             Slave address to be set.
+ *
+ * @return void.
+ */
+void SPIMasterCfgAddr(SpiNum spiNum, uint32_t addr);
+
+/**
+ * @brief Set command value by master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] cmd
+ *             Command will be send to slave.
+ *
+ * @return void.
+ */
+void SPIMasterCfgCmd(SpiNum spiNum, uint32_t cmd);
+
+/**
+ * @brief Send data to slave from master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pInData
+ *             Pointer to a strcuture that will be send.
+ *
+ * @return int, -1:indicates failure,others indicates success.
+ */
+ int SPIMasterSendData(SpiNum spiNum, SpiData* pInData);
+
+/**
+ * @brief Receive data from slave by master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pOutData
+ *             Point to data buffer.
+ *
+ * @return int, -1:indicates failure,others indicates success.
+ *
+ */
+ int SPIMasterRecvData(SpiNum spiNum, SpiData* pOutData);
+
+/**
+ * @brief Load data to slave send buffer.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pInData
+ *             Point to data buffer.
+ * @param [in] inLen
+ *             The number of bytes to be set.
+ *
+ * @return int, -1:indicates failure,others indicates success.
+ */
+int SPISlaveSendData(SpiNum spiNum, uint32_t *pInData, uint8_t inLen);
+
+/**
+ * @brief Receive data by slave.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] isrFunc
+ *             isrFunc is a pointer to the function to be called when the SPI interrupt occurs.
+ *
+ * @return int, -1:indicates failure,others indicates success.
+ */
+int SPISlaveRecvData(SpiNum spiNum);
+
+/**
+ * @brief Set slave status by master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] data
+ *             Data will be write to slave SPI_WR_STATUS.
+ *
+ * @return void.
+ *
+ * @attention Just for ESP8266(slave) register of RD_STATUS or WR_STATUS.
+ */
+void SPIMasterSendStatus(SpiNum spiNum, uint8_t data);
+
+/**
+ * @brief Get salve status by master.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ *
+ * @return int, -1: indicates failure; other value in slave status.
+ *
+ * @attention Just for ESP8266(slave) register of RD_STATUS or WR_STATUS.
+ */
+int SPIMasterRecvStatus(SpiNum spiNum);
+
+/**
+ * @brief Select SPI CS pin.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pinCs
+ *             Indicates which SPI pin to choose.
+ *
+ * @return void.
+ */
+void SPICsPinSelect(SpiNum spiNum, SpiPinCS pinCs);
+
+/**
+ * @brief Set SPI module interrupt source and callback function.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] pIntInfo
+ *             Pointer to a struct SpiIntInfo that indicates SPI interrupt information.
+ *
+ * @return void.
+ */
+void SPIIntCfg(SpiNum spiNum, SpiIntInfo *pIntInfo);
+
+/**
+ * @brief Enable SPI module interrupt source.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] intSrc
+ *             Indicates which interrupt source to enable.
+ *
+ * @return void.
+ */
+void SPIIntEnable(SpiNum spiNum, SpiIntSrc intSrc);
+
+/**
+ * @brief Disable SPI module interrupt source.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ * @param [in] intSrc
+ *             Indicates which interrupt source to disable.
+ *
+ * @return void.
+ */
+void SPIIntDisable(SpiNum spiNum, SpiIntSrc intSrc);
+
+/**
+ * @brief Clear all of spi interrupt.
+ *
+ * @param [in] spiNum
+ *             Indicates which submode to be used, SPI or HSPI.
+ *
+ * @return void.
+ */
+void SPIIntClear(SpiNum spiNum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //  __SPI_INTERFACE_H__

+ 85 - 0
include/driver/spi_overlap.h

@@ -0,0 +1,85 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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_OVERLAP_APP_H
+#define SPI_OVERLAP_APP_H
+
+#include "ets_sys.h"
+#include "spi_flash.h"
+#define HSPI_OVERLAP
+//#define NO_HSPI_DEVICE
+#define HOST_INF_SEL 0x3ff00028 
+#define FUNC_SPI_CS2 1
+#define FUNC_SPI_CS1 1
+#define reg_cspi_overlap  (BIT7)
+
+#define SPI_FLASH_BYTES_LEN                24
+#define IODATA_START_ADDR                 BIT0
+#define SPI_BUFF_BYTE_NUM                    32
+
+#define PERIPHS_IO_MUX_BACKUP		0
+#define SPI_USER_BACKUP  	1
+#define SPI_CTRL_BACKUP  	2 
+#define SPI_CLOCK_BACKUP 	3
+#define SPI_USER1_BACKUP	4
+#define SPI_USER2_BACKUP	5
+#define SPI_CMD_BACKUP		6
+#define SPI_PIN_BACKUP		7
+#define SPI_SLAVE_BACKUP	8
+
+#define HSPI_CS_DEV			0
+#define SPI_CS1_DEV			1
+#define SPI_CS2_DEV			2
+#define SPI_CS0_FLASH		3
+#define HSPI_IDLE			4
+
+struct hspi_device_config{
+	uint8 active:1;
+	uint8 clk_polar:1;
+	uint8 res:1;
+	uint8 clk_div:5;
+};
+
+struct hspi_device_register{
+	uint32 hspi_flash_reg_backup[9];
+	uint32 hspi_dev_reg_backup[9];
+	struct hspi_device_config hspi_dev_conf[4];
+	uint8 selected_dev_num:3;
+	uint8 spi_io_80m:1;
+	uint8 hspi_reg_backup_flag:1;
+	uint8 res:3;
+};
+
+void hspi_overlap_init(void);
+void hspi_overlap_deinit(void);
+void spi_reg_recover(uint8 spi_no,uint32* backup_mem);
+void spi_reg_backup(uint8 spi_no,uint32* backup_mem);
+
+void hspi_master_dev_init(uint8 dev_no,uint8 clk_polar,uint8 clk_div);
+void hspi_dev_sel(uint8 dev_no);
+
+void hspi_overlap_flash_init(void);
+SpiFlashOpResult hspi_overlap_read_flash_data(SpiFlashChip * spi, uint32 flash_addr, uint32 * addr_dest, uint32 byte_length);
+
+#endif

+ 222 - 0
include/driver/spi_register.h

@@ -0,0 +1,222 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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_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                          BIT31
+#define SPI_FLASH_WREN                         BIT30
+#define SPI_FLASH_WRDI                         BIT29
+#define SPI_FLASH_RDID                          BIT28
+#define SPI_FLASH_RDSR                          BIT27
+#define SPI_FLASH_WRSR                         BIT26
+#define SPI_FLASH_PP                              BIT25
+#define SPI_FLASH_SE                              BIT24
+#define SPI_FLASH_BE                              BIT23
+#define SPI_FLASH_CE                              BIT22
+#define SPI_FLASH_RES                            BIT20
+
+#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_QOUT_MODE (BIT(20))
+#define SPI_DOUT_MODE (BIT(14))
+#define SPI_FASTRD_MODE (BIT(13))
+
+#define SPI_CTRL1(i)                         (REG_SPI_BASE(i)  + 0xc)
+#define  SPI_CS_HOLD_DELAY  0xf  
+#define  SPI_CS_HOLD_DELAY_S   28
+#define  SPI_CS_HOLD_DELAY_RES  0xfff 
+#define  SPI_CS_HOLD_DELAY_RES_S   16
+
+
+#define SPI_RD_STATUS(i)                         (REG_SPI_BASE(i)  + 0x10)
+
+#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
+#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_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_MOSI_HIGHPART (BIT(25))
+#define SPI_USR_MISO_HIGHPART (BIT(24))
+
+
+#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_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_FLASH_MODE (BIT(2))
+
+#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)
+#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_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_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
+
+#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)
+
+#define SPI_EXT2(i)                           (REG_SPI_BASE(i)  + 0xF8)
+
+#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

+ 229 - 0
include/driver/uart.h

@@ -0,0 +1,229 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 UART_APP_H
+#define UART_APP_H
+
+#include "uart_register.h"
+#include "eagle_soc.h"
+#include "c_types.h"
+
+#define UART_TX_BUFFER_SIZE 256  //Ring buffer length of tx buffer
+#define UART_RX_BUFFER_SIZE 256 //Ring buffer length of rx buffer
+
+#define UART_BUFF_EN  0   //use uart buffer  , FOR UART0
+#define UART_SELFTEST  0  //set 1:enable the loop test demo for uart buffer, FOR UART0
+
+#define UART_HW_RTS   0   //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0
+#define UART_HW_CTS  0    //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0
+
+
+
+
+#define UART0   0
+#define UART1   1
+
+
+typedef enum {
+    FIVE_BITS = 0x0,
+    SIX_BITS = 0x1,
+    SEVEN_BITS = 0x2,
+    EIGHT_BITS = 0x3
+} UartBitsNum4Char;
+
+typedef enum {
+    ONE_STOP_BIT             = 0x1,
+    ONE_HALF_STOP_BIT        = 0x2,
+    TWO_STOP_BIT             = 0x3
+} UartStopBitsNum;
+
+typedef enum {
+    NONE_BITS = 0x2,
+    ODD_BITS   = 1,
+    EVEN_BITS = 0
+} UartParityMode;
+
+typedef enum {
+    STICK_PARITY_DIS   = 0,
+    STICK_PARITY_EN    = 1
+} UartExistParity;
+
+typedef enum {
+    UART_None_Inverse = 0x0,
+    UART_Rxd_Inverse = UART_RXD_INV,
+    UART_CTS_Inverse = UART_CTS_INV,
+    UART_Txd_Inverse = UART_TXD_INV,
+    UART_RTS_Inverse = UART_RTS_INV,
+} UART_LineLevelInverse;
+
+
+typedef enum {
+    BIT_RATE_300 = 300,
+    BIT_RATE_600 = 600,
+    BIT_RATE_1200 = 1200,
+    BIT_RATE_2400 = 2400,
+    BIT_RATE_4800 = 4800,
+    BIT_RATE_9600   = 9600,
+    BIT_RATE_19200  = 19200,
+    BIT_RATE_38400  = 38400,
+    BIT_RATE_57600  = 57600,
+    BIT_RATE_74880  = 74880,
+    BIT_RATE_115200 = 115200,
+    BIT_RATE_230400 = 230400,
+    BIT_RATE_460800 = 460800,
+    BIT_RATE_921600 = 921600,
+    BIT_RATE_1843200 = 1843200,
+    BIT_RATE_3686400 = 3686400,
+} UartBautRate;
+
+typedef enum {
+    NONE_CTRL,
+    HARDWARE_CTRL,
+    XON_XOFF_CTRL
+} UartFlowCtrl;
+
+typedef enum {
+    USART_HardwareFlowControl_None = 0x0,
+    USART_HardwareFlowControl_RTS = 0x1,
+    USART_HardwareFlowControl_CTS = 0x2,
+    USART_HardwareFlowControl_CTS_RTS = 0x3
+} UART_HwFlowCtrl;
+
+typedef enum {
+    EMPTY,
+    UNDER_WRITE,
+    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 {
+    BAUD_RATE_DET,
+    WAIT_SYNC_FRM,
+    SRCH_MSG_HEAD,
+    RCV_MSG_BODY,
+    RCV_ESC_CHAR,
+} RcvMsgState;
+
+typedef struct {
+    UartBautRate 	     baut_rate;
+    UartBitsNum4Char  data_bits;
+    UartExistParity      exist_parity;
+    UartParityMode 	    parity;    
+    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);
+void uart0_sendStr(const char *str);
+
+
+///////////////////////////////////////
+#define UART_FIFO_LEN  128  //define the tx fifo length
+#define UART_TX_EMPTY_THRESH_VAL 0x10
+
+
+ struct UartBuffer{
+    uint32     UartBuffSize;
+    uint8     *pUartBuff;
+    uint8     *pInPos;
+    uint8     *pOutPos;
+    STATUS  BuffState;
+    uint16    Space;  //remanent space of the buffer
+    uint8  TcpControl;
+    struct  UartBuffer     *  nextBuff;
+};
+
+struct UartRxBuff{
+    uint32     UartRxBuffSize;
+    uint8     *pUartRxBuff;
+    uint8     *pWritePos;
+    uint8     *pReadPos;
+    STATUS RxBuffState;
+    uint32    Space;  //remanent space of the buffer
+} ;
+
+typedef enum {
+    RUN = 0,
+    BLOCK = 1,
+} TCPState;
+
+//void ICACHE_FLASH_ATTR uart_test_rx();
+STATUS uart_tx_one_char(uint8 uart, uint8 TxChar);
+STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar);
+void  uart1_sendStr_no_wait(const char *str);
+struct UartBuffer*  Uart_Buf_Init();
+
+
+#if UART_BUFF_EN
+LOCAL void  Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len);
+void  uart_buf_free(struct UartBuffer* pBuff);
+void  tx_buff_enq(char* pdata, uint16 data_len );
+LOCAL void  tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len,  uint8 uart_no);
+void  tx_start_uart_buffer(uint8 uart_no);
+uint16  rx_buff_deq(char* pdata, uint16 data_len );
+void  Uart_rx_buff_enq();
+#endif
+void  uart_rx_intr_enable(uint8 uart_no);
+void  uart_rx_intr_disable(uint8 uart_no);
+void uart0_tx_buffer(uint8 *buf, uint16 len);
+
+//==============================================
+#define FUNC_UART0_CTS 4
+#define FUNC_U0CTS                      4
+#define FUNC_U1TXD_BK                   2
+#define UART_LINE_INV_MASK  (0x3f<<19)
+void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len);
+void UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num);
+void UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask);
+void UART_SetParity(uint8 uart_no, UartParityMode Parity_mode);
+void UART_SetBaudrate(uint8 uart_no,uint32 baud_rate);
+void UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh);
+void UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us); //do not use if tx flow control enabled
+void UART_ResetFifo(uint8 uart_no);
+void UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask);
+void UART_SetIntrEna(uint8 uart_no,uint32 ena_mask);
+void UART_SetPrintPort(uint8 uart_no);
+bool UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us);
+//==============================================
+
+#endif
+

+ 159 - 0
include/driver/uart_register.h

@@ -0,0 +1,159 @@
+/*
+ * ESPRSSIF MIT License
+ *
+ * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
+ *
+ * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
+ * it is 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 UART_REGISTER_H_
+#define UART_REGISTER_H_
+
+#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_DTR_INV                        (BIT(24))
+#define UART_RTS_INV                        (BIT(23))
+#define UART_TXD_INV                        (BIT(22))
+#define UART_DSR_INV                        (BIT(21))
+#define UART_CTS_INV                        (BIT(20))
+#define UART_RXD_INV                        (BIT(19))
+#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_EN_M                0x00000001
+#define UART_PARITY_EN_S                 1
+#define UART_PARITY                         (BIT(0))
+#define UART_PARITY_M                       0x00000001
+#define UART_PARITY_S                        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
+

+ 17 - 0
include/esp_common.h

@@ -0,0 +1,17 @@
+/*
+ * Title: esp_common
+ * Description: The purpose of this file is to simplfy includes for
+ * the esp non-rtos sdk
+ * Author: Tyler Berezowsky
+ *
+ */
+
+#ifndef __USER_CONFIG_H__
+#define __USER_CONFIG_H__
+
+#include "ets_sys.h"
+#include "user_interface.h"
+#include "mem.h"
+#include "osapi.h"
+
+#endif

+ 63 - 0
include/gdbstub/gdbstub-cfg.h

@@ -0,0 +1,63 @@
+#ifndef GDBSTUB_CFG_H
+#define  GDBSTUB_CFG_H
+
+/*
+Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL
+and do some other magic to make everything work and compile under FreeRTOS.
+*/
+#ifndef GDBSTUB_FREERTOS
+#define GDBSTUB_FREERTOS 0
+#endif
+
+/*
+Enable this to make the exception and debugging handlers switch to a private stack. This will use
+up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's
+normally disabled because not many situations need it. If for some reason the GDB communication
+stops when you run into an error in your code, try enabling this.
+*/
+#ifndef GDBSTUB_USE_OWN_STACK
+#define GDBSTUB_USE_OWN_STACK 0
+#endif
+
+/*
+If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by
+hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't
+work for your program anymore. This will fail if your program sets an UART interrupt handler after
+the gdbstub_init call.
+*/
+#ifndef GDBSTUB_CTRLC_BREAK
+#define GDBSTUB_CTRLC_BREAK 1
+#endif
+
+/*
+Enabling this will redirect console output to GDB. This basically means that printf/os_printf output
+will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if
+you use a normal terminal, you can't read the printfs anymore.
+*/
+#ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT
+#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 0
+#endif
+
+/*
+Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by
+breaking in the init routine; use the gdb 'c' command (continue) to start the program.
+*/
+#ifndef GDBSTUB_BREAK_ON_INIT
+#define GDBSTUB_BREAK_ON_INIT 0
+#endif
+
+/*
+Function attributes for function types.
+Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function
+(and related) can always be in flash, because it's called in the normal code flow. The rest of the
+gdbstub functions can be in flash too, but only if there's no chance of them being called when the
+flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines
+are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most
+likely crash.
+*/
+#define ATTR_GDBINIT	ICACHE_FLASH_ATTR
+#ifndef ATTR_GDBFN
+#define ATTR_GDBFN
+#endif
+
+#endif

+ 25 - 0
include/gdbstub/gdbstub-entry.h

@@ -0,0 +1,25 @@
+#ifndef GDBSTUB_ENTRY_H
+#define GDBSTUB_ENTRY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gdbstub_init_debug_entry();
+void gdbstub_do_break();
+void gdbstub_icount_ena_single_step();
+void gdbstub_save_extra_sfrs_for_exception();
+void gdbstub_uart_entry();
+
+int gdbstub_set_hw_breakpoint(int addr, int len);
+int gdbstub_set_hw_watchpoint(int addr, int len, int type);
+int gdbstub_del_hw_breakpoint(int addr);
+int gdbstub_del_hw_watchpoint(int addr);
+
+extern void* gdbstub_do_break_breakpoint_addr;
+
+#ifdef __cplusplus
+{
+#endif
+
+#endif

+ 14 - 0
include/gdbstub/gdbstub.h

@@ -0,0 +1,14 @@
+#ifndef GDBSTUB_H
+#define GDBSTUB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gdbstub_init();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1309 - 0
include/hal/lps25hb.h

@@ -0,0 +1,1309 @@
+/**
+  ******************************************************************************
+* @file    LPS25HB_Driver.h
+  * @author  HESA Application Team
+   @version 1.0.0
+  * @date    07/04/2014
+  * @brief   LPS25HB driver header file
+
+  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+  *
+  * THIS SOURCE CODE IS PROTECTED BY A LICENSE.
+  * FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED
+  * IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE.
+  *
+  * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
+
+  ******************************************************************************
+*/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __LPS25HB_DRIVER__H
+#define __LPS25HB_DRIVER__H
+
+#include "esp_common.h"
+
+//include <stdint.h>
+// the user must include the proper file where HAL_ReadReg and HAL_WriteReg are implemented
+//#include "HAL_EnvSensors.h"
+
+/* Uncomment the line below to expanse the "assert_param" macro in the  drivers code */
+//#define USE_FULL_ASSERT_LPS25HB
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef  USE_FULL_ASSERT_LPS25HB
+
+/**
+  * @brief  The assert_param macro is used for function's parameters check.
+  * @param  expr: If expr is false, it calls assert_failed function which reports
+  *         the name of the source file and the source line number of the call
+  *         that failed. If expr is true, it returns no value.
+  * @retval None
+  */
+#define LPS25HB_assert_param(expr) ((expr) ? (void)0 : LPS25HB_assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+void LPS25HB_assert_failed(uint8_t* file, uint32_t line);
+#else
+#define LPS25HB_assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT_LPS25HB */
+
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** @addtogroup Environmental_Sensor
+  * @{
+  */
+
+/** @addtogroup LPS25HB_DRIVER
+  * @{
+  */
+
+/* Exported Types -------------------------------------------------------------*/
+/** @defgroup LPS25HB_Exported_Types
+  * @{
+  */
+
+/**
+* @brief  Error type.
+ */
+typedef enum {LPS25HB_OK = (uint8_t)0, LPS25HB_ERROR = !LPS25HB_OK} LPS25HB_Error_et;
+
+/**
+* @brief  Enable/Disable type.
+ */
+typedef enum {LPS25HB_DISABLE = (uint8_t)0, LPS25HB_ENABLE = !LPS25HB_DISABLE} LPS25HB_State_et;
+#define IS_LPS25HB_State(MODE) ((MODE == LPS25HB_ENABLE) || (MODE == LPS25HB_DISABLE) )
+
+/**
+* @brief  Bit status type.
+ */
+typedef enum {LPS25HB_RESET = (uint8_t)0, LPS25HB_SET = !LPS25HB_RESET} LPS25HB_BitStatus_et;
+#define IS_LPS25HB_BitStatus(MODE) ((MODE == LPS25HB_RESET) || (MODE == LPS25HB_SET))
+
+/**
+* @brief  Pressure average.
+ */
+typedef enum {
+  LPS25HB_AVGP_8          = (uint8_t)0x00,         /*!< Internal average on 8 samples */
+  LPS25HB_AVGP_32         = (uint8_t)0x01,         /*!< Internal average on 32 samples */
+  LPS25HB_AVGP_128        = (uint8_t)0x02,         /*!< Internal average on 128 samples */
+  LPS25HB_AVGP_512        = (uint8_t)0x03          /*!< Internal average on 512 sample */
+}LPS25HB_Avgp_et;
+#define IS_LPS25HB_AVGP(AVGP) ((AVGP == LPS25HB_AVGP_8) || (AVGP == LPS25HB_AVGP_32) || \
+                              (AVGP == LPS25HB_AVGP_128) || (AVGP == LPS25HB_AVGP_512))
+
+/**
+* @brief  Temperature average.
+ */
+typedef enum {
+LPS25HB_AVGT_8          = (uint8_t)0x00,        /*!< Internal average on 8 samples */
+LPS25HB_AVGT_16         = (uint8_t)0x04,        /*!< Internal average on 16 samples */
+LPS25HB_AVGT_32         = (uint8_t)0x08,        /*!< Internal average on 32 samples */
+LPS25HB_AVGT_64         = (uint8_t)0x0C         /*!< Internal average on 64 samples */
+}LPS25HB_Avgt_et;
+
+#define IS_LPS25HB_AVGT(AVGT) ((AVGT == LPS25HB_AVGT_8) || (AVGT == LPS25HB_AVGT_16) || \
+                              (AVGT == LPS25HB_AVGT_32) || (AVGT == LPS25HB_AVGT_64))
+
+/**
+* @brief  Output data rate configuration.
+ */
+typedef enum {
+
+LPS25HB_ODR_ONE_SHOT  = (uint8_t)0x00,         /*!< Output Data Rate: one shot */
+LPS25HB_ODR_1HZ       = (uint8_t)0x10,         /*!< Output Data Rate: 1Hz */
+LPS25HB_ODR_7HZ       = (uint8_t)0x20,         /*!< Output Data Rate: 7Hz */
+LPS25HB_ODR_12_5HZ    = (uint8_t)0x30,         /*!< Output Data Rate: 12.5Hz */
+LPS25HB_ODR_25HZ      = (uint8_t)0x40          /*!< Output Data Rate: 25Hz */
+} LPS25HB_Odr_et;
+
+#define IS_LPS25HB_ODR(ODR) ((ODR == LPS25HB_ODR_ONE_SHOT) || (ODR == LPS25HB_ODR_1HZ) || \
+                            (ODR == LPS25HB_ODR_7HZ) || (ODR == LPS25HB_ODR_12_5HZ)|| (ODR == LPS25HB_ODR_25HZ))
+/**
+ * @brief  LPS25HB Spi Mode configuration.
+ */
+typedef enum {
+  LPS25HB_SPI_4_WIRE   =  (uint8_t)0x00,
+  LPS25HB_SPI_3_WIRE   =  (uint8_t)0x01
+} LPS25HB_SPIMode_et;
+
+#define IS_LPS25HB_SPIMode(MODE) ((MODE == LPS25HB_SPI_4_WIRE) || (MODE == LPS25HB_SPI_3_WIRE))
+
+/**
+* @brief  Block data update.
+ */
+
+typedef enum {
+LPS25HB_BDU_CONTINUOUS_UPDATE     =  (uint8_t)0x00,  /*!< Data updated continuously */
+LPS25HB_BDU_NO_UPDATE             =  (uint8_t)0x04   /*!< Data updated after a read operation */
+} LPS25HB_Bdu_et;
+#define IS_LPS25HB_BDUMode(MODE) ((MODE == LPS25HB_BDU_CONTINUOUS_UPDATE) || (MODE == LPS25HB_BDU_NO_UPDATE))
+
+/**
+* @brief  Data Signal on INT1 pad control bits.
+ */
+typedef enum
+{
+  LPS25HB_DATA = (uint8_t)0x00,
+  LPS25HB_P_HIGH = (uint8_t)0x01,
+  LPS25HB_P_LOW = (uint8_t)0x02,
+  LPS25HB_P_LOW_HIGH = (uint8_t)0x03
+}LPS25HB_OutputSignalConfig_et;
+#define IS_LPS25HB_OutputSignal(MODE) ((MODE == LPS25HB_DATA) || (MODE == LPS25HB_P_HIGH)||\
+(MODE == LPS25HB_P_LOW) || (MODE == LPS25HB_P_LOW_HIGH))
+
+/**
+ * @brief  LPS25HB INT1 Interrupt pins configuration.
+ */
+typedef enum
+{
+  LPS25HB_DISABLE_DATA_INT = (uint8_t)0x00,
+  LPS25HB_DATA_READY = (uint8_t)0x01,
+  LPS25HB_OVR = (uint8_t)0x02,
+  LPS25HB_WTM = (uint8_t)0x04,
+  LPS25HB_EMPTY      = (uint8_t)0x08
+}LPS25HB_DataSignalType_et;
+#define IS_LPS25HB_DataSignal(MODE) ((MODE == LPS25HB_DISABLE_DATA_INT) ||(MODE == LPS25HB_EMPTY) || (MODE ==LPS25HB_WTM)||\
+                                    (MODE == LPS25HB_OVR) || (MODE == LPS25HB_DATA_READY))
+
+/**
+ * @brief  LPS25HB Push-pull/Open Drain selection on Interrupt pads.
+ */
+typedef enum
+{
+  LPS25HB_PushPull = (uint8_t)0x00,
+LPS25HB_OpenDrain  = (uint8_t)0x40
+}LPS25HB_OutputType_et;
+#define IS_LPS25HB_OutputType(MODE) ((MODE == LPS25HB_PushPull) || (MODE == LPS25HB_OpenDrain))
+
+/**
+ * @brief  LPS25HB Interrupt Differential Configuration.
+ */
+typedef enum
+{
+  LPS25HB_DISABLE_INT = (uint8_t)0x00,
+  LPS25HB_PHE = (uint8_t)0x01,
+  LPS25HB_PLE = (uint8_t)0x02,
+  LPS25HB_PLE_PHE = (uint8_t)0x03
+}LPS25HB_InterruptDiffConfig_et;
+
+#define IS_LPS25HB_InterruptDiff(MODE) ((MODE == LPS25HB_DISABLE_INT) || (MODE ==LPS25HB_PHE)||\
+                                      (MODE == LPS25HB_PLE) || (MODE == LPS25HB_PLE_PHE))
+
+/**
+ * @brief  LPS25HB Interrupt Differential Status.
+ */
+
+typedef struct
+{
+  uint8_t PH;          /*!< High Differential Pressure event occured */
+  uint8_t PL;          /*!< Low Differential Pressure event occured */
+  uint8_t IA;          /*!< One or more interrupt events have been  generated.Interrupt Active */
+}LPS25HB_InterruptDiffStatus_st;
+
+
+/**
+ * @brief  LPS25HB Pressure and Temperature data status.
+ */
+typedef struct
+{
+  uint8_t TempDataAvailable;           /*!< Temperature data available bit */
+  uint8_t PressDataAvailable;          /*!< Pressure data available bit */
+  uint8_t TempDataOverrun;             /*!< Temperature data over-run bit */
+  uint8_t PressDataOverrun;            /*!< Pressure data over-run bit */
+}LPS25HB_DataStatus_st;
+
+
+/**
+ * @brief  LPS25HB Fifo Mode.
+ */
+
+typedef enum {
+LPS25HB_FIFO_BYPASS_MODE             	   = (uint8_t)0x00,	/*!< The FIFO is disabled and empty. The pressure is read directly*/
+LPS25HB_FIFO_MODE                           = (uint8_t)0x20,    /*!< Stops collecting data when full */
+LPS25HB_FIFO_STREAM_MODE                    = (uint8_t)0x40,    /*!< Keep the newest measurements in the FIFO*/
+LPS25HB_FIFO_TRIGGER_STREAMTOFIFO_MODE      = (uint8_t)0x60,    /*!< STREAM MODE until trigger deasserted, then change to FIFO MODE*/
+LPS25HB_FIFO_TRIGGER_BYPASSTOSTREAM_MODE    = (uint8_t)0x80,    /*!< BYPASS MODE until trigger deasserted, then STREAM MODE*/
+LPS25HB_FIFO_MEAN_MODE                      = (uint8_t)0xC0,    /*!< FIFO is used to generate a running average filtered pressure */
+LPS25HB_FIFO_TRIGGER_BYPASSTOFIFO_MODE      = (uint8_t)0xE0     /*!< BYPASS mode until trigger deasserted, then FIFO MODE*/
+} LPS25HB_FifoMode_et;
+
+#define IS_LPS25HB_FifoMode(MODE) ((MODE == LPS25HB_FIFO_BYPASS_MODE) || (MODE ==LPS25HB_FIFO_MODE)||\
+				  (MODE == LPS25HB_FIFO_STREAM_MODE) || (MODE == LPS25HB_FIFO_TRIGGER_STREAMTOFIFO_MODE)||\
+                                  (MODE == LPS25HB_FIFO_TRIGGER_BYPASSTOSTREAM_MODE) || (MODE == LPS25HB_FIFO_MEAN_MODE)||\
+                                  (MODE == LPS25HB_FIFO_TRIGGER_BYPASSTOFIFO_MODE))
+
+
+/**
+ * @brief  LPS25HB Fifo Mean Mode Sample Size.
+ */
+
+typedef enum {
+  LPS25HB_FIFO_SAMPLE_2    = (uint8_t)0x01,	    /*!< 2 Fifo Mean Mode samples */
+  LPS25HB_FIFO_SAMPLE_4    = (uint8_t)0x03,  		/*!< 4 Fifo Mean Mode samples */
+  LPS25HB_FIFO_SAMPLE_8    = (uint8_t)0x07,     /*!< 8 Fifo Mean Mode samples */
+  LPS25HB_FIFO_SAMPLE_16   = (uint8_t)0x0F,     /*!< 16 Fifo Mean Mode samples */
+  LPS25HB_FIFO_SAMPLE_32   = (uint8_t)0x1F  	  /*!< 32 Fifo Mean Mode samples */
+} LPS25HB_FifoMeanModeSample_et;
+
+#define IS_LPS25HB_FifoMeanModeSample(MODE) ((MODE == LPS25HB_FIFO_SAMPLE_2) || (MODE ==LPS25HB_FIFO_SAMPLE_4)||\
+                                          (MODE == LPS25HB_FIFO_SAMPLE_8) || (MODE == LPS25HB_FIFO_SAMPLE_16)||\
+                                          (MODE == LPS25HB_FIFO_SAMPLE_32))
+/**
+ * @brief  LPS25HB Fifo Satus.
+ */
+typedef struct {
+  uint8_t FIFO_LEVEL;          /*!< FIFO Stored data level t */
+  uint8_t FIFO_EMPTY;          /*!< Empy FIFO bit.1 FIFO is empty	*/
+  uint8_t FIFO_FULL;           /*!< Overrun bit status. 1 FIFO is full */
+  uint8_t FIFO_WTM;            /*!< Watermark Status. 1 FIFO is equal or higher then wtm level.*/
+}LPS25HB_FifoStatus_st;
+
+
+/**
+ * @brief  LPS25HB Configuration structure definition.
+ */
+typedef struct
+{
+LPS25HB_Avgp_et 				PressResolution;         	/*!< Pressure sensor resolution */
+LPS25HB_Avgt_et 				TempResolution;     		/*!< Temperature sensor resolution */
+LPS25HB_Odr_et  				OutputDataRate;      		/*!< Output Data Rate */
+LPS25HB_Bdu_et  				BDU;                		/*!< Enable to inhibit the output registers update between the reading of upper and lower register parts.*/
+LPS25HB_State_et   		        AutoZero;			/*! < Auto zero feature enabled.the actual pressure output is copied in the REF_P*/
+LPS25HB_State_et 			Reset_AZ;   			/*!< Reset the Auto ZeroFunc. The daefualt RPDS value is copied in REF_P   */
+LPS25HB_SPIMode_et 		        Sim;  			 	/*!< SPI Serial Interface Mode selection */
+}LPS25HB_ConfigTypeDef_st;
+
+
+
+/**
+ * @brief  LPS25HB Interrupt structure definition .
+ */
+typedef struct {
+LPS25HB_State_et 			INT_H_L;                /*!< Interrupt active high, low. Default value: 0 */
+LPS25HB_OutputType_et 			PP_OD; 			/*!< Push-pull/open drain selection on interrupt pads. Default value: 0 */
+LPS25HB_OutputSignalConfig_et 		OutputSignal_INT1;	/*!< Data signal on INT1 Pad: Data,Pressure High, Preessure Low,P High or Low*/
+LPS25HB_DataSignalType_et       	DataInterrupt_INT1;	/*!< Interrupt Pin Config:DRDY, WTM, OVERRUN, EMPTY*/
+LPS25HB_InterruptDiffConfig_et 		PressureInterrupt;	/*!< Interrupt differential Configuration: PL_E and/or PH_E*/
+LPS25HB_State_et			LatchIRQ;		/*!< Latch Interrupt request in to INT_SOURCE reg*/
+int16_t 				fP_threshold;		/*!< Threshold value for pressure interrupt generation*/
+}LPS25HB_InterruptTypeDef_st;
+
+/**
+ * @brief  LPS25HB FIFO structure definition.
+ */
+typedef struct {
+LPS25HB_FifoMode_et 	        FIFO_MODE;              /*!< Fifo Mode Selection */
+LPS25HB_State_et		        WTM_INT; 		/*!< Enable/Disable the watermark interrupt*/
+LPS25HB_State_et			FIFO_MEAN_DEC;		/*!< Enable/Disable 1 Hz ODR decimation */
+LPS25HB_FifoMeanModeSample_et 	MEAN_MODE_SAMPLE;	/*!< FIFO Mean Mode Sample Size*/
+uint8_t 			WTM_LEVEL;		/*!< FIFO threshold.Watermark level setting*/
+}LPS25HB_FIFOTypeDef_st;
+
+#define IS_LPS25HB_WtmLevel(LEVEL) ((LEVEL > 0) && (LEVEL <=31))
+
+/**
+ * @brief  LPS25HB Measure Type definition.
+ */
+typedef struct {
+  int16_t Tout;
+  int32_t Pout;
+}LPS25HB_MeasureTypeDef_st;
+
+
+/**
+ * @brief  LPS25HB Driver Version Info structure definition.
+ */
+typedef struct {
+  uint8_t   Major;
+  uint8_t   Minor;
+  uint8_t Point;
+}LPS25HB_DriverVersion_st;
+
+
+/**
+* @brief  Bitfield positioning.
+*/
+#define LPS25HB_BIT(x) ((uint8_t)x)
+
+/**
+* @brief  I2C address.
+*/
+
+/*SDO/SA0 (pin5) is connected to the GND*/
+#define LPS25HB_ADDRESS  (uint8_t)0xB8
+
+/* SD0/SA0(pin 5) is connected to the voltage supply*/
+//#define LPS25HB_ADDRESS  (uint8_t)0xBA //SA0=1
+
+/**
+  * @brief  Set the LPS25HB driver version.
+*/
+#define LPS25HB_DriverVersion_Major (uint8_t)1
+#define LPS25HB_DriverVersion_Minor (uint8_t)0
+#define LPS25HB_DriverVersion_Point (uint8_t)0
+
+/**
+  * @}
+  */
+
+
+/* Exported Constants ---------------------------------------------------------*/
+ /** @defgroup LPS25HB_Exported_Constants
+  * @{
+  */
+
+
+/**
+ * @addtogroup LPS25HB_Register
+ * @{
+*/
+
+
+
+ /**
+ * @brief Device Identification register.
+ * \code
+ * Read
+ * Default value: 0xBD
+ * 7:0 This read-only register contains the device identifier that, for LPS25HB, is set to BDh.
+ * \endcode
+ */
+
+#define LPS25HB_WHO_AM_I_REG         (uint8_t)0x0F
+
+/**
+* @brief Device Identification value.
+*/
+#define LPS25HB_WHO_AM_I_VAL         (uint8_t)0xBD
+
+
+/**
+ * @brief Reference Pressure  Register(LSB data)
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:0 REFL7-0: Lower part of the reference pressure value that
+ *      is sum to the sensor output pressure.
+ * \endcode
+ */
+#define LPS25HB_REF_P_XL_REG         (uint8_t)0x08
+
+
+/**
+ * @brief Reference Pressure Register (Middle data)
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:0 REFL15-8: Middle part of the reference pressure value that
+ *      is sum to the sensor output pressure.
+ * \endcode
+ */
+#define LPS25HB_REF_P_L_REG          (uint8_t)0x09
+
+/**
+ * @brief Reference Pressure Register (MSB data)
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:0 REFL23-16 Higest part of the reference pressure value that
+ *      is sum to the sensor output pressure.
+ * \endcode
+ */
+#define LPS25HB_REF_P_H_REG          (uint8_t)0x0A
+
+
+/**
+ * @brief Pressure and temperature resolution mode Register
+ * \code
+ * Read/write
+ * Default value: 0x05
+ * 7:4 RFU
+ * 3:2 AVGT1-AVGT0: Select the temperature internal average.
+ *      AVGT1 | AVGT0 | Nr. Internal Average
+ *   ------------------------------------------------------
+ *       0    |  0    |     8
+ *       0    |  1    |     16
+ *       1    |  0    |     32
+ *       1    |  1    |     64
+
+ *
+ * 1:0 AVGP1-AVGP0: Select pressure internal average.
+ *      AVGP1 |  AVGP0 | Nr. Internal Average
+ *   ------------------------------------------------------
+ *      0    |   0    |      8
+ *      0    |   1    |      32
+ *      1    |   0    |      128
+ *      1    |   1    |      512
+ * \endcode
+ */
+#define LPS25HB_RES_CONF_REG     (uint8_t)0x10
+
+#define LPS25HB_AVGT_BIT         LPS25HB_BIT(2)
+#define LPS25HB_AVGP_BIT         LPS25HB_BIT(0)
+
+#define LPS25HB_AVGT_MASK        (uint8_t)0x0C
+#define LPS25HB_AVGP_MASK        (uint8_t)0x03
+
+/**
+ * @brief Control Register 1
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7 PD: power down control. 0 - power down mode; 1 - active mode
+ * 6:4 ODR2, ODR1, ODR0: output data rate selection.
+ *     ODR2  | ODR1  | ODR0  | Pressure output data-rate(Hz)  | Pressure output data-rate(Hz)
+ *   ----------------------------------------------------------------------------------
+ *      0    |  0    |  0    |         one shot               |         one shot
+ *      0    |  0    |  1    |            1                   |            1
+ *      0    |  1    |  0    |            7                   |            7
+ *      0    |  1    |  1    |            12.5                |            12.5
+ *      1    |  0    |  0    |            25                  |            25
+ *      1    |  0    |  1    |         Reserved               |         Reserved
+ *      1    |  1    |  0    |         Reserved               |         Reserved
+ *      1    |  1    |  1    |         Reserved               |         Reserved
+ *
+ * 3 DIFF_EN: Interrupt circuit Enable. 0 - interrupt generation disable; 1 - interrupt generation enable
+ * 2 BDU: block data update. 0 - continuous update; 1 - output registers not updated until MSB and LSB reading.
+ * 1 RESET_AZ: Reset AutoZero Function. Reset Ref_P reg, set pressure to default value in RDPS reg.  0 - disable;1 - Reset
+ * 0 SIM: SPI Serial Interface Mode selection. 0 - SPI 4-wire; 1 - SPI 3-wire
+ * \endcode
+ */
+#define LPS25HB_CTRL_REG1      (uint8_t)0x20
+#define LPS25HB_PD_BIT         LPS25HB_BIT(7)
+#define LPS25HB_ODR_BIT        LPS25HB_BIT(4)
+#define LPS25HB_DIFF_EN_BIT    LPS25HB_BIT(3)
+#define LPS25HB_BDU_BIT        LPS25HB_BIT(2)
+#define LPS25HB_RESET_AZ_BIT   LPS25HB_BIT(1)
+#define LPS25HB_SIM_BIT        LPS25HB_BIT(0)
+
+#define LPS25HB_PD_MASK        (uint8_t)0x80
+#define LPS25HB_ODR_MASK       (uint8_t)0x70
+#define LPS25HB_DIFF_EN_MASK   (uint8_t)0x08
+#define LPS25HB_BDU_MASK       (uint8_t)0x04
+#define LPS25HB_RESET_AZ_MASK  (uint8_t)0x02
+#define LPS25HB_SIM_MASK       (uint8_t)0x01
+
+
+/**
+ * @brief Control  Register 2
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7 BOOT:  Reboot memory content. 0: normal mode; 1: reboot memory content. Self-clearing upon completation
+ * 6 FIFO_EN: FIFO Enable. 0: disable; 1:  enable
+ * 5 WTM_EN:  FIFO Watermark level use. 0: disable; 1: enable
+ * 4 FIFO_MEAN_DEC: Enable 1 HZ decimation 0: enable; 1: disable
+ * 3 I2C Enable:  0: I2C Enable; 1: SPI disable
+ * 2 SWRESET: Software reset. 0: normal mode; 1: SW reset. Self-clearing upon completation
+ * 1 AUTO_ZERO: Autozero enable. 0: normal mode; 1: autozero enable.
+ * 0 ONE_SHOT: One shot enable. 0: waiting for start of conversion; 1: start for a new dataset
+ * \endcode
+ */
+#define LPS25HB_CTRL_REG2      (uint8_t)0x21
+#define LPS25HB_BOOT_BIT       LPS25HB_BIT(7)
+#define LPS25HB_FIFO_EN_BIT    LPS25HB_BIT(6)
+#define LPS25HB_WTM_EN_BIT     LPS25HB_BIT(5)
+#define LPS25HB_FIFO_MEAN_BIT  LPS25HB_BIT(4)
+#define LPS25HB_I2C_BIT        LPS25HB_BIT(3)
+#define LPS25HB_SW_RESET_BIT   LPS25HB_BIT(2)
+#define LPS25HB_AUTO_ZERO_BIT  LPS25HB_BIT(1)
+#define LPS25HB_ONE_SHOT_BIT   LPS25HB_BIT(0)
+
+#define LPS25HB_BOOT_MASK      (uint8_t)0x80
+#define LPS25HB_FIFO_EN_MASK   (uint8_t)0x40
+#define LPS25HB_WTM_EN_MASK    (uint8_t)0x20
+#define LPS25HB_FIFO_MEAN_MASK (uint8_t)0x10
+#define LPS25HB_I2C_MASK       (uint8_t)0x08
+#define LPS25HB_SW_RESET_MASK  (uint8_t)0x04
+#define LPS25HB_AUTO_ZERO_MASK (uint8_t)0x02
+#define LPS25HB_ONE_SHOT_MASK  (uint8_t)0x01
+
+
+/**
+ * @brief CTRL Reg3 Interrupt Control Register
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7 INT_H_L: Interrupt active high, low. 0:active high; 1: active low.
+ * 6 PP_OD: Push-Pull/OpenDrain selection on interrupt pads. 0: Push-pull; 1: open drain.
+ * 5:2 Reserved
+ * 1:0 INT1_S2, INT1_S1: data signal on INT1 pad control bits.
+ *    INT1_S2  | INT1_S1  | INT1 pin
+ *   ------------------------------------------------------
+ *        0       |      0      |     Data signal
+ *        0       |      1      |     Pressure high (P_high)
+ *        1       |      0      |     Pressure low (P_low)
+ *        1       |      1      |     P_low OR P_high
+ * \endcode
+ */
+#define LPS25HB_CTRL_REG3      (uint8_t)0x22
+#define LPS25HB_INT_H_L_BIT    LPS25HB_BIT(7)
+#define LPS25HB_PP_OD_BIT      LPS25HB_BIT(6)
+#define LPS25HB_INT1_S2_BIT    LPS25HB_BIT(1)
+#define LPS25HB_INT1_S1_BIT    LPS25HB_BIT(0)
+
+#define LPS25HB_INT_H_L_MASK   (uint8_t)0x80
+#define LPS25HB_PP_OD_MASK     (uint8_t)0x40
+#define LPS25HB_INT1_S2_MASK   (uint8_t)0x02
+#define LPS25HB_INT1_S1_MASK   (uint8_t)0x01
+
+/**
+ * @brief CTRL Reg4 Interrupt Configuration Register
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:4 Reserved: Keep these bits at 0
+ * 3 P1_EMPTY: Empty Signal on INT1 pin.
+ * 2 P1_WTM: Watermark Signal on INT1 pin.
+ * 1 P1_Overrunn:Overrun Signal on INT1 pin.
+ * 0 P1_DRDY: Data Ready Signal on INT1 pin.
+ * \endcode
+ */
+#define LPS25HB_CTRL_REG4       (uint8_t)0x23
+#define LPS25HB_P1_EMPTY_BIT    LPS25HB_BIT(3)
+#define LPS25HB_P1_WTM_BIT      LPS25HB_BIT(2)
+#define LPS25HB_P1_OVERRUN_BIT  LPS25HB_BIT(1)
+#define LPS25HB_P1_DRDY_BIT     LPS25HB_BIT(0)
+
+#define LPS25HB_P1_EMPTY_MASK    (uint8_t)0x08
+#define LPS25HB_P1_WTM_MASK      (uint8_t)0x04
+#define LPS25HB_P1_OVERRUN_MASK  (uint8_t)0x02
+#define LPS25HB_P1_DRDY_MASK     (uint8_t)0x01
+
+ /**
+ * @brief Interrupt Differential configuration Register
+ * \code
+ * Read/write
+ * Default value: 0x00.
+ * 7:3 Reserved.
+ * 2 LIR: Latch Interrupt request into INT_SOURCE register. 0 - interrupt request not latched; 1 - interrupt request latched
+ * 1 PL_E: Enable interrupt generation on differential pressure low event. 0 - disable; 1 - enable
+ * 0 PH_E: Enable interrupt generation on differential pressure high event. 0 - disable; 1 - enable
+ * \endcode
+ */
+#define LPS25HB_INTERRUPT_CFG_REG  (uint8_t)0x24
+#define LPS25HB_LIR_BIT            LPS25HB_BIT(2)
+#define LPS25HB_PL_E_BIT           LPS25HB_BIT(1)
+#define LPS25HB_PH_E_BIT           LPS25HB_BIT(0)
+
+#define LPS25HB_LIR_MASK           (uint8_t)0x04
+#define LPS25HB_PL_E_MASK          (uint8_t)0x02
+#define LPS25HB_PH_E_MASK          (uint8_t)0x01
+#define LPS25HB_PE_MASK          (uint8_t)0x03
+
+
+ /**
+ * @brief Interrupt source Register (It is cleared by reading it)
+ * \code
+ * Read
+ * Default value: 0x00.
+ * 7:3 Reserved: Keep these bits at 0
+ * 2 IA: Interrupt Active.0: no interrupt has been generated; 1: one or more interrupt events have been generated.
+ * 1 PL: Differential pressure Low. 0: no interrupt has been generated; 1: Low differential pressure event has occurred.
+ * 0 PH: Differential pressure High. 0: no interrupt has been generated; 1: High differential pressure event has occurred.
+ * \endcode
+ */
+#define LPS25HB_INTERRUPT_SOURCE_REG   (uint8_t)0x25
+#define LPS25HB_IA_BIT                 LPS25HB_BIT(2)
+#define LPS25HB_PL_BIT                 LPS25HB_BIT(1)
+#define LPS25HB_PH_BIT                 LPS25HB_BIT(0)
+
+#define LPS25HB_IA_MASK               (uint8_t)0x04
+#define LPS25HB_PL_MASK               (uint8_t)0x02
+#define LPS25HB_PH_MASK               (uint8_t)0x01
+
+/**
+ * @brief  Status Register
+ * \code
+ * Read
+ * Default value: 0x00
+ * 7:6 Reserved: 0
+ * 5 P_OR: Pressure data overrun. 0: no overrun has occurred; 1: new data for pressure has overwritten the previous one.
+ * 4 T_OR: Temperature data overrun. 0: no overrun has occurred; 1: a new data for temperature has overwritten the previous one.
+ * 3:2 Reserved: 0
+ * 1 P_DA: Pressure data available. 0: new data for pressure is not yet available; 1: new data for pressure is available.
+ * 0 T_DA: Temperature data available. 0: new data for temperature is not yet available; 1: new data for temperature is available.
+ * \endcode
+ */
+#define LPS25HB_STATUS_REG         (uint8_t)0x27
+#define LPS25HB_POR_BIT            LPS25HB_BIT(5)
+#define LPS25HB_TOR_BIT            LPS25HB_BIT(4)
+#define LPS25HB_PDA_BIT            LPS25HB_BIT(1)
+#define LPS25HB_TDA_BIT            LPS25HB_BIT(0)
+
+#define LPS25HB_POR_MASK           (uint8_t)0x20
+#define LPS25HB_TOR_MASK           (uint8_t)0x10
+#define LPS25HB_PDA_MASK           (uint8_t)0x02
+#define LPS25HB_TDA_MASK           (uint8_t)0x01
+
+/**
+* @brief  Pressure data (LSB) register.
+ * \code
+ * Read
+ * Default value: 0x00.(To be verified)
+ * POUT7 - POUT0: Pressure data LSB (2's complement).
+ * Pressure output data: Pout(hPA)=(PRESS_OUT_H & PRESS_OUT_L &
+ * PRESS_OUT_XL)[dec]/4096.
+ * \endcode
+ */
+
+#define LPS25HB_PRESS_OUT_XL_REG        (uint8_t)0x28
+/**
+* @brief  Pressure data (Middle part) register.
+ * \code
+ * Read
+ * Default value: 0x80.
+ * POUT15 - POUT8: Pressure data middle part (2's complement).
+ * Pressure output data: Pout(hPA)=(PRESS_OUT_H & PRESS_OUT_L &
+ * PRESS_OUT_XL)[dec]/4096.
+ * \endcode
+ */
+#define LPS25HB_PRESS_OUT_L_REG        (uint8_t)0x29
+
+/**
+* @brief  Pressure data (MSB) register.
+ * \code
+ * Read
+ * Default value: 0x2F.
+ * POUT23 - POUT16: Pressure data MSB (2's complement).
+ * Pressure output data: Pout(hPA)=(PRESS_OUT_H & PRESS_OUT_L &
+ * PRESS_OUT_XL)[dec]/4096.
+ * \endcode
+ */
+#define LPS25HB_PRESS_OUT_H_REG        (uint8_t)0x2A
+
+/**
+* @brief  Temperature data (LSB) register.
+ * \code
+ * Read
+ * Default value: 0x00.
+ * TOUT7 - TOUT0: temperature data LSB.
+ * T(degC) = 42.5 + (Temp_OUTH & TEMP_OUT_L)[dec]/480.
+ * \endcode
+ */
+#define LPS25HB_TEMP_OUT_L_REG         (uint8_t)0x2B
+
+/**
+* @brief  Temperature data (MSB) register.
+ * \code
+ * Read
+ * Default value: 0x00.
+ * TOUT15 - TOUT8: temperature data MSB.
+ * T(degC) = 42.5 + (Temp_OUTH & TEMP_OUT_L)[dec]/480.
+ * \endcode
+ */
+#define LPS25HB_TEMP_OUT_H_REG         (uint8_t)0x2C
+
+/**
+* @brief Threshold pressure (LSB) register.
+ * \code
+ * Read/write
+ * Default value: 0x00.
+ * 7:0 THS7-THS0: LSB Threshold pressure Low part of threshold value for pressure interrupt
+ * generation. The complete threshold value is given by THS_P_H & THS_P_L and is
+ * expressed as unsigned number. P_ths(hPA)=(THS_P_H & THS_P_L)[dec]/16.
+ * \endcode
+ */
+#define LPS25HB_THS_P_LOW_REG           (uint8_t)0x30
+
+/**
+ * @brief Threshold pressure (MSB)
+ * \code
+ * Read/write
+ * Default value: 0x00.
+ * 7:0 THS15-THS8: MSB Threshold pressure. High part of threshold value for pressure interrupt
+ * generation. The complete threshold value is given by THS_P_H & THS_P_L and is
+ * expressed as unsigned number. P_ths(mbar)=(THS_P_H & THS_P_L)[dec]/16.
+ * \endcode
+ */
+#define LPS25HB_THS_P_HIGH_REG         (uint8_t)0x31
+
+/**
+ * @brief FIFO control register
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:5 F_MODE2, F_MODE1, F_MODE0: FIFO mode selection.
+ *     FM2   | FM1   | FM0   |    FIFO MODE
+ *   ---------------------------------------------------
+ *      0    |  0    |  0    | BYPASS MODE
+ *      0    |  0    |  1    | FIFO MODE. Stops collecting data when full
+ *      0    |  1    |  0    | STREAM MODE: Keep the newest measurements in the FIFO
+ *      0    |  1    |  1    | STREAM MODE until trigger deasserted, then change to FIFO MODE
+ *      1    |  0    |  0    | BYPASS MODE until trigger deasserted, then STREAM MODE
+ *      1    |  0    |  1    | Reserved for future use
+ *      1    |  1    |  0    | FIFO_MEAN MODE: Fifo is used to generate a running average filtered pressure
+ *      1    |  1    |  1    | BYPASS mode until trigger deasserted, then FIFO MODE
+ *
+ * 4:0 WTM_POINT4-0 : FIFO threshold.Watermark level setting (0-31)
+ * 4:0 WTM_POINT4-0 is FIFO Mean Mode Sample size if FIFO_MEAN MODE is used
+ *     WTM_POINT4 | WTM_POINT4 | WTM_POINT4 |  WTM_POINT4 | WTM_POINT4 | Sample Size
+ *   ----------------------------------------------------------------------------------
+ *      0         |    0       |    0       |      0      |     1      |       2
+ *      0         |    0       |    0       |      1      |     1      |       4
+ *      0         |    0       |    1       |      1      |     1      |       8
+ *      0         |    1       |    1       |      1      |     1      |       16
+ *      1         |    1       |    1       |      1      |     1      |       32
+ * other values operation not guaranteed
+ * \endcode
+ */
+#define LPS25HB_CTRL_FIFO_REG          (uint8_t)0x2E
+#define LPS25HB_FMODE_BIT              LPS25HB_BIT(5)
+#define LPS25HB_WTM_POINT_BIT          LPS25HB_BIT(0)
+
+#define LPS25HB_FMODE_MASK             (uint8_t)0xE0
+#define LPS25HB_WTM_POINT_MASK         (uint8_t)0x1F
+
+/**
+ * @brief FIFO Status register
+ * \code
+ * Read
+ * Default value: 0x00
+ * 7 WTM_FIFO: Watermark status. 0:FIFO filling is lower than watermark level; 1: FIFO is equal or higher than watermark level.
+ * 6 FULL_FIFO: Overrun bit status. 0 - FIFO not full; 1 -FIFO is full.
+ * 5 EMPTY_FIFO: Empty FIFO bit. 0 - FIFO not empty; 1 -FIFO is empty.
+ * 4:0 DIFF_POINT4-0: FIFOsStored data level.
+ * \endcode
+ */
+#define LPS25HB_STATUS_FIFO_REG        (uint8_t)0x2F
+#define LPS25HB_WTM_FIFO_BIT           LPS25HB_BIT(7)
+#define LPS25HB_FULL_FIFO_BIT          LPS25HB_BIT(6)
+#define LPS25HB_EMPTY_FIFO_BIT         LPS25HB_BIT(5)
+#define LPS25HB_DIFF_POINT_BIT         LPS25HB_BIT(0)
+
+#define LPS25HB_WTM_FIFO_MASK          (uint8_t)0x80
+#define LPS25HB_FULL_FIFO_MASK         (uint8_t)0x40
+#define LPS25HB_EMPTY_FIFO_MASK        (uint8_t)0x20
+#define LPS25HB_DIFF_POINT_MASK        (uint8_t)0x1F
+
+/**
+ * @brief Pressure offset register  (LSB)
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:0 RPDS7-0:Pressure Offset for 1 point calibration after soldering.
+ * This register contains the low part of the pressure offset value after soldering,for
+ * differential pressure computing. The complete value is given by RPDS_L & RPDS_H
+ * and is expressed as signed 2 complement value.
+ * \endcode
+ */
+#define LPS25HB_RPDS_L_REG        (uint8_t)0x39
+
+/**
+ * @brief Pressure offset register (MSB)
+ * \code
+ * Read/write
+ * Default value: 0x00
+ * 7:0 RPDS15-8:Pressure Offset for 1 point calibration after soldering.
+ * This register contains the high part of the pressure offset value after soldering (see description RPDS_L)
+ * \endcode
+ */
+#define LPS25HB_RPDS_H_REG        (uint8_t)0x3A
+
+ /**
+  * @}
+  */
+
+
+  /**
+  * @}
+  */
+
+
+
+/* Exported Functions -------------------------------------------------------------*/
+/** @defgroup LPS25HB_Exported_Functions
+  * @{
+  */
+
+	/**
+* @brief  Init the HAL layer.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+#define LPS25HB_HalInit  HAL_Init_I2C
+
+/**
+* @brief  DeInit the HAL layer.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+#define LPS25HB_HalDeInit  HAL_DeInit_I2C
+
+/**
+* @brief  Read LPS25HB Registers
+* @param  uint32_t RegAddr:       address of the first register to read
+* @param  uint32_t NumByteToRead:   number of registers to read
+* @param  uint8_t *Data:          pointer to the destination data buffer
+* @retval LPS25HB_ERROR or LPS25HB_OK
+*/
+// the user must redefine the proper LPS25HB_ReadReg
+#define LPS25HB_ReadReg(RegAddr, NumByteToRead, Data)  Sensor_IO_Read(RegAddr, NumByteToRead, Data)
+
+/**
+* @brief  Write LPS25HB Registers
+* @param  uint32_t RegAddr:      address of the register to write
+* @param  uint8_t *Data:         pointer to the source data buffer
+* @param  uint32_t NumByteToWrite:           Number of bytes to write
+* @retval LPS25HB_ERROR or LPS25HB_OK
+*/
+// the user must redefine the proper LPS25HB_WriteReg
+#define LPS25HB_WriteReg(RegAddr, NumByteToWrite, Data)  Sensor_IO_Write(RegAddr, NumByteToWrite, Data)
+
+
+/**
+* @brief  Get the LPS25HB driver version.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_DriverVersion(LPS25HB_DriverVersion_st *Version);
+
+
+/**
+  * @brief  DeInit the LPS25HB driver.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+
+LPS25HB_Error_et LPS25HB_DeInit(void);
+
+/**
+  * @brief  Exit the shutdown mode for LPS25HB.
+  * @param  None
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+
+LPS25HB_Error_et LPS25HB_Activate(void);
+
+/**
+  * @brief  Enter the shutdown mode for LPS25HB.
+  * @param  None
+  * @retval  Status [LPS25HB_ERROR, LPS25HB_OK]
+  */
+  LPS25HB_Error_et LPS25HB_DeActivate(void);
+
+
+/**
+  * @brief  Check if the single measurement has completed.
+  * @param  value is set to 1, when the measure is completed
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+ LPS25HB_Error_et LPS25HB_IsMeasurementCompleted(uint8_t *Is_Measurement_Completed);
+
+/**
+  * @brief  Get the values of the last single measurement.
+  * @param  Pressure and temperature value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+ LPS25HB_Error_et LPS25HB_Get_Measurement(LPS25HB_MeasureTypeDef_st *Measurement_Value);
+
+
+/**
+  * @brief  Get the Reference Pressure value that is sum to the sensor output pressure
+  * @param  buffer to empty with reference pressure value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_ReferencePressure(int32_t *RefP);
+
+/*Sensor Configuration Functions*/
+/*CTRL_REG1*/
+/**
+  * @brief  Set LPS25HB Power Down Mode
+  * @param  BSET/BRESET bit in order to SET/RESET LPS25HB Power Down Mode bit
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+
+LPS25HB_Error_et LPS25HB_Set_PowerDownMode(LPS25HB_BitStatus_et powerdown);
+/**
+  * @brief  Sets LPS25HB Pressure and Temperature Resolution Mode
+  * @param  Pressure and Temperature Resolution Congiguration
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_Avg(LPS25HB_Avgp_et avgp,LPS25HB_Avgt_et avgt);
+
+/**
+  * @brief  Sets LPS25HB Pressure Resolution Mode
+  * @param  Pressure Resolution Congiguration
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_AvgP(LPS25HB_Avgp_et avgp);
+/**
+  * @brief  Sets LPS25HB  Temperature Resolution Mode
+  * @param  Temperature Resolution Congiguration
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_AvgT(LPS25HB_Avgt_et avgt);
+
+/**
+  * @brief  Gets LPS25HB Pressure Resolution Mode
+  * @param  value to empty
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_AvgP(LPS25HB_Avgp_et* avgpress);
+
+/**
+  * @brief  Gets LPS25HB Temperature Resolution Mode
+  * @param  value to empty
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_AvgT(LPS25HB_Avgt_et* avgtemp);
+
+/**
+  * @brief  Set the Output Data Rate
+  * @param  Output Data Rate Value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_Odr(LPS25HB_Odr_et odr);
+/**
+  * @brief  Get the Output Data Rate
+  * @param  Output Data Rate Value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_Odr(LPS25HB_Odr_et* odr);
+
+/**
+  * @brief  Enable/ Disable the Interrupt Circuit
+  * @param  LPS25HB_ENABLE,LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptCircuitEnable(LPS25HB_State_et diff_en) ;
+
+/**
+  * @brief  Get the DIFF_EN bit value
+  * @param  buffer
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_InterruptCircuitEnable(LPS25HB_State_et* diff_en);
+
+/**
+  * @brief  Set Block Data Update mode
+  * @param  LPS25HB_BDU_CONTINUOS_UPDATE/ LPS25HB_BDU_NO_UPDATE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_BDU(LPS25HB_Bdu_et bdu);
+
+
+/**
+  * @brief  Get Block Data Update mode
+  * @param
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_BDU(LPS25HB_Bdu_et* bdu);
+
+/**
+  * @brief  Reset the Auto ZeroFunc. The defualt RPDS value is copied in REF_P
+  * @param  void
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_ResetAZ(void);
+
+/**
+  * @brief  Set SPI mode: 3 Wire Interface OR 4 Wire Interface
+  * @param  LPS25HB_SPI_4_WIRE/LPS25HB_SPI_3_WIRE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_SpiInterface(LPS25HB_SPIMode_et spimode);
+
+/**
+  * @brief  Get SPI mode: 3 Wire Interface OR 4 Wire Interface
+  * @param  buffer to empty with SPI mode
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_SpiInterface(LPS25HB_SPIMode_et* spimode);
+
+
+/**
+  * @brief  Enable/Disable I2C
+  * @param  State. Enable (reset bit)/ Disable (set bit)
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_I2C(LPS25HB_State_et i2cstate);
+/**
+  * @brief  Set One Shot bit to start a new conversion (ODR mode has to be 000)
+  * @param  void
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_StartOneShotMeasurement(void);
+
+/**
+  * @brief Set AutoZero Function bit
+  * @param  Bit action: LPS25HB_BitRESET/LPS25HB_BitSET
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_AutoZeroFunction(LPS25HB_BitStatus_et autozero);
+
+/**
+  * @brief Software Reset
+  * @param  void
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_SwReset(void);
+
+/**
+  * @brief Reboot Memory Content.
+  * @param  void
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_MemoryBoot(void);
+
+/**
+  * @brief Software Reset ann BOOT
+  * @param  void
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_SwResetAndMemoryBoot(void);
+
+/**
+  * @brief  Enable or Disable FIFO
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoModeUse(LPS25HB_State_et status);
+
+/**
+  * @brief  Enable or Disable FIFO Watermark level use
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoWatermarkLevelUse(LPS25HB_State_et status);
+
+/**
+  * @brief  Enable or Disable 1 HZ ODR Decimation
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoMeanDecUse(LPS25HB_State_et status);
+
+/*CTRL_REG3 Interrupt Control*/
+/**
+  * @brief  Set Interrupt Active on High or Low Level
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptActiveLevel(LPS25HB_State_et status);
+
+/**
+  * @brief  Set Push-pull/open drain selection on interrupt pads.
+* @param  LPS25HB_PushPull/LPS25HB_OpenDrain
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptOutputType(LPS25HB_OutputType_et output);
+
+/**
+  * @brief  Set Data signal on INT1 pad control bits.
+  * @param  LPS25HB_DATA,LPS25HB_P_HIGH_LPS25HB_P_LOW,LPS25HB_P_LOW_HIGH
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptControlConfig(LPS25HB_OutputSignalConfig_et config);
+
+/**
+  * @brief  Set INT1 interrupt pins configuration.
+  * @param  LPS25HB_EMPTY,LPS25HB_WTM,LPS25HB_OVR,LPS25HB_DATA_READY
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptDataConfig(LPS25HB_DataSignalType_et signal);
+
+/**
+  * @brief  Enable\Disable Interrupt Generation on differential pressure low and/or high event
+  * @param  LPS25HB_DISABLE_INT, LPS25HB_PHE,LPS25HB_PLE,LPS25HB_PLE_PHE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptDifferentialConfig(LPS25HB_InterruptDiffConfig_et config);
+
+/**
+  * @brief  Latch Interrupt request into INT_SOURCE register.
+  * @param  LPS25HB_ENABLE/LPS25HB_DISABLE
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_LatchInterruptRequest(LPS25HB_State_et status);
+
+/**
+  * @brief  Get the Status of  low-high differential pressure event
+  * @param  Status Event Flag: PH,PL,IA
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_InterruptDifferentialEventStatus(LPS25HB_InterruptDiffStatus_st* interruptsource);
+
+/**
+  * @brief  Get the status of Pressure and Temperature data
+  * @param  Data Status Flag:  TempDataAvailable, TempDataOverrun, PressDataAvailable, PressDataOverrun
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_DataStatus(LPS25HB_DataStatus_st* datastatus);
+
+/**
+  * @brief  Read LPS25HB output register, and calculate the raw  pressure
+  * @param  The buffer to empty with the pressure raw value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_RawPressure(int32_t *raw_press);
+
+/**
+  * @brief  Read the Pressure value in mbar.
+* @param  The buffer to empty with the pressure value that must be divided by 100 to get the value in hPA
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_Pressure(int32_t* Pout);
+
+/**
+  * @brief  Read LPS25HB output register, and calculate the raw temperature.
+  * @param  The buffer to empty with the temperature raw value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_RawTemperature(int16_t *raw_data);
+
+/**
+  * @brief  Read the Temperature value in �C.
+* @param  The buffer to empty with the temperature value that must be divided by 10 to get the value in ['C]
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_Temperature(int16_t* Tout);
+
+/**
+  * @brief  Get the threshold value used for pressure interrupt generation.
+  * @param  The buffer to empty with the temperature value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_PressureThreshold(int16_t *P_ths);
+
+/**
+  * @brief  Set the threshold value used for pressure interrupt generation.
+  * @param  The buffer to empty with the temperature value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_PressureThreshold(int16_t P_ths);
+
+/**
+  * @brief  Set Fifo Mode.
+  * @param  FifoModee struct
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoMode(LPS25HB_FifoMode_et fifomode);
+/**
+  * @brief  Get Fifo Mode.
+  * @param  Buffer to empty with fifo mode value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_FifoMode(LPS25HB_FifoMode_et* fifomode);
+
+/**
+  * @brief  Get Fifo Status.
+  * @param  Buffer to empty with fifo mode value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_FifoStatus(LPS25HB_FifoStatus_st* status);
+
+/**
+  * @brief  Set Fifo Watermark Level.
+  * @param  Wtm level value [0 31]
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoWatermarkLevel(uint8_t wtmlevel);
+
+/**
+  * @brief  Get Fifo Watermark Level
+  * @param  Buffer to empty with wtm value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_FifoWatermarkLevel(uint8_t *wtmlevel);
+
+/**
+  * @brief  Set the number of sample to perform moving average when FIFO_MEAN_MODE is used
+  * @param  2,4,8,16 32 samples moving average value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoSampleSize(LPS25HB_FifoMeanModeSample_et samplesize);
+
+/**
+  * @brief  Get FiFo Sample size
+  * @param  2,4,8,16 32 samples moving average value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_FifoSampleSize(LPS25HB_FifoMeanModeSample_et* samplesize);
+
+/**
+  * @brief  Get Device ID
+  * @param  value to empty with Identification Device
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_DeviceID(uint8_t* deviceid);
+
+/**
+  * @brief  Get the reference pressure after soldering for computing differential pressure
+  * @param  buffer to empty with pressure value
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_PressureOffsetValue(int16_t *pressoffset);
+
+/**
+  * @brief  Set Generic configuration
+  * @param  Struct holding the configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_GenericConfig(LPS25HB_ConfigTypeDef_st* pxLPS25HBInit);
+
+/**
+  * @brief  Get Generic configuration
+  * @param  Struct to empty with configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_GenericConfig(LPS25HB_ConfigTypeDef_st* pxLPS25HBInit);
+
+/**
+  * @brief  Set Interrupt configuration
+  * @param  Struct holding the configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_InterruptConfig(LPS25HB_InterruptTypeDef_st* pLPS25HBInt);
+
+/**
+  * @brief 	LPS25HB_Get_InterruptConfig
+  * @param  Struct to empty with configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_InterruptConfig(LPS25HB_InterruptTypeDef_st* pLPS25HBInt);
+
+/**
+  * @brief  Set Fifo configuration
+  * @param  Struct holding the configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Set_FifoConfig(LPS25HB_FIFOTypeDef_st* pLPS25HBFIFO);
+
+/**
+  * @brief  Get Fifo configuration
+  * @param  Struct to empty with the configuration values
+  * @retval Status [LPS25HB_ERROR, LPS25HB_OK]
+*/
+LPS25HB_Error_et LPS25HB_Get_FifoConfig(LPS25HB_FIFOTypeDef_st* pLPS25HBFIFO);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#endif /* __LPS25HB_DRIVER__H */
+
+/******************* (C) COPYRIGHT 2013 STMicroelectronics *****END OF FILE****/

+ 269 - 0
include/hal/lsm6ds3.h

@@ -0,0 +1,269 @@
+#ifndef LSM6DS3_H_
+#define LSM6DS3_H_
+
+#include "ets_sys.h"
+#include "driver/spi_interface.h"
+
+/*------------------------------------------------------------------------------*/
+// Debugging Flag(s)
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_DEBUG	 1 // flag for printing data to aid debugging
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Debugging Function(s)
+/*------------------------------------------------------------------------------*/
+#if LSM6DS3_DEBUG
+void lsm6ds3_xl_print(void);
+#endif
+/*------------------------------------------------------------------------------*/
+
+#define LSM6DS3_BIT(x) 				((uint16_t)x)
+
+/*------------------------------------------------------------------------------*/
+// Device Registers
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FUNC_CFG_ACCESS         	0x01	// embedded functions config. reg.
+#define LSM6DS3_FUNC_CFG_EN					BIT7
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_SENSOR_SYNC_TIME_FRAME  	0x04	// sensor sync config. reg.
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FIFO_CTRL1              	0x06	// FIFO configuration regs.
+#define LSM6DS3_FIFO_CTRL2              	0x07
+#define LSM6DS3_FIFO_CTRL3              	0x08
+#define LSM6DS3_FIFO_CTRL4              	0x09
+#define LSM6DS3_FIFO_CTRL5              	0x0A
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_INT1_CTRL               	0x0D	// interrupt pin control regs.
+#define LSM6DS3_INT2_CTRL               	0x0E
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_WHO_AM_I                	0x0F	// who i am ID
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_CTRL1_XL                	0x10
+
+#define	LSM6DS3_ODR_XL_POWERDOWN			0x00
+#define	LSM6DS3_ODR_XL_13Hz					0x10
+#define	LSM6DS3_ODR_XL_26Hz					0x20
+#define	LSM6DS3_ODR_XL_52Hz					0x30
+#define	LSM6DS3_ODR_XL_104Hz				0x40
+#define	LSM6DS3_ODR_XL_208Hz				0x50
+#define	LSM6DS3_ODR_XL_416Hz				0x60
+#define	LSM6DS3_ODR_XL_833Hz				0x70
+#define	LSM6DS3_ODR_XL_1_66kHz				0x80
+#define	LSM6DS3_ODR_XL_3_33_kHz				0x90
+#define	LSM6DS3_ODR_XL_6_66_kHz				0xA0
+#define LSM6DS3_FS_XL_2G					0x00
+#define LSM6DS3_FS_XL_16G					0x04
+#define LSM6DS3_FS_XL_4G					0x08
+#define LSM6DS3_FS_XL_8G					0x0C
+#define LSM6DS3_BW_XL_400Hz					0x00
+#define LSM6DS3_BW_XL_200Hz					0x01
+#define LSM6DS3_BW_XL_100Hz					0x02
+#define LSM6DS3_BW_XL_50Hz					0x03
+
+#define LSM6DS3_CTRL2_G                 	0x11
+
+#define LSM6DS3_ODR_G_POWERDOWN				0x00
+#define LSM6DS3_ODR_G_13Hz					0x10
+#define LSM6DS3_ODR_G_26Hz					0x20
+#define LSM6DS3_ODR_G_52Hz					0x30
+#define LSM6DS3_ODR_G_104Hz					0x40
+#define LSM6DS3_ODR_G_208Hz					0x50
+#define LSM6DS3_ODR_G_416Hz					0x60
+#define LSM6DS3_ODR_G_833Hz					0x70
+#define LSM6DS3_ODR_G_1_66kHz				0x80
+#define LSM6DS3_FS_G_245DPS					0x00
+#define LSM6DS3_FS_G_500DPS					0x04
+#define LSM6DS3_FS_G_1000DPS				0x08
+#define LSM6DS3_FS_G_2000DPS				0x0C
+#define LSM6DS3_FS_125						0x02
+
+#define LSM6DS3_CTRL3_C                 	0x12
+
+#define LSM6DS3_BOOT 						BIT7
+#define LSM6DS3_BDU							BIT6
+#define LSM6DS3_H_LACTIVE					BIT5
+#define LSM6DS3_PP_OD						BIT4
+#define LSM6DS3_SIM							BIT3
+#define LSM6DS3_IF_INC						BIT2
+#define LSM6DS3_BLE							BIT1
+#define LSM6DS3_SW_RESET					BIT0
+
+#define LSM6DS3_CTRL4_C                 	0x13
+
+#define LSM6DS3_XL_SCAL_ODR					BIT7
+#define LSM6DS3_SLEEP_G						BIT6
+#define LSM6DS3_INT2_ON_INT1				BIT5
+#define LSM6DS3_FIFO_TEMP_EN				BIT4
+#define LSM6DS3_DRDY_MASK					BIT3
+#define LSM6DS3_I2C_DISABLE					BIT2
+#define	LSM6DS3_MODE3_EN					BIT1
+#define LSM6DS3_STOP_ON_FTH					BIT0
+
+#define LSM6DS3_CTRL5_C                 	0x14
+
+#define LSM6DS3_CTRL6_C                 	0x15
+
+#define LSM6DS3_TRIG_EN						BIT7
+#define LSM6DS3_LVLEN						BIT6
+#define LSM6DS3_LVL2_EN						BIT5
+#define LSM6DS3_XL_HM_MODE					BIT4
+
+#define LSM6DS3_CTRL7_G                 	0x16
+
+#define LSM6DS3_G_HM_MODE					BIT7
+#define LSM6DS3_HP_G_EN						BIT6
+#define LSM6DS3_HP_G_RST					BIT5
+#define LSM6DS3_ROUNDING_STATUS				BIT4
+#define LSM6DS3_HPCF_G_0_081Hz				0x00
+#define LSM6DS3_HPCF_G_0_324Hz				0x01
+#define LSM6DS3_HPCF_G_2_070Hz				0x02
+#define LSM6DS3_HPCF_G_1_632Hz				0x03
+
+#define LSM6DS3_CTRL8_XL                	0x17
+
+#define LSM6DS3_LPF2_XL_EN					BIT7
+#define LSM6DS3_HPCF_XL_SLOPE_D50			0x00
+#define LSM6DS3_HPCF_XL_HP_D100				0x20
+#define LSM6DS3_HPCF_XL_HP_D9				0x40
+#define LSM6DS3_HPCF_XL_HPD400				0x60
+
+#define LSM6DS3_CTRL9_XL                	0x18
+#define LSM6DS3_CTRL10_C                	0x19
+
+#define LSM6DS3_Z_EN_G						BIT5
+#define LSM6DS3_Y_EN_G						BIT4
+#define LSM6DS3_X_EN_G						BIT3
+#define LSM6DS3_FUNC_EN						BIT2
+#define LSM6DS3_PEDO_RST_STEP				BIT1
+#define LSM6DS3_SIGN_MOTION_EN				BIT0
+
+#define LSM6DS3_ORIENT_CFG_G            	0x0B
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_MASTER_CONFIG            	0x1A	// I2C master config. reg.
+
+#define LSM6DS3_DRDY_ON_INT1 				BIT7
+#define LSM6DS3_DATA_VALID_SEL_FIFO			BIT6
+#define LSM6DS3_START_CONIFG 				BIT4
+#define LSM6DS3_PULL_UP_EN					BIT3
+#define LSM6DS3_PASS_THROUGH_MODE			BIT2
+#define LSM6DS3_IRON_EN						BIT1
+#define LSM6DS3_MASTER_ON					BIT0
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_WAKE_UP_SRC             	0x1B	// interrupt regs.
+#define LSM6DS3_TAP_SRC                 	0x1C
+#define LSM6DS3_D6D_SRC                 	0x1D
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_STATUS_REG              	0x1E	// status reg.
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_OUT_TEMP_L 					0x20	// temp. output regs.
+#define LSM6DS3_OUT_TEMP_H              	0x21
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_OUTX_L_G 					0x22	// gyro. output regs.
+#define LSM6DS3_OUTX_H_G 					0x23
+#define LSM6DS3_OUTY_L_G					0x24
+#define LSM6DS3_OUTY_H_G					0x25
+#define LSM6DS3_OUTZ_L_G 					0x26
+#define LSM6DS3_OUTZ_H_G 					0x27
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_OUTX_L_XL					0x28	// acc. output regs.
+#define LSM6DS3_OUTX_H_XL					0x29
+#define LSM6DS3_OUTY_L_XL					0x2A
+#define LSM6DS3_OUTY_H_XL					0x2B
+#define LSM6DS3_OUTZ_L_XL 					0x2C
+#define LSM6DS3_OUTZ_H_XL 					0x2D
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_SENSORHUB1_REG 				0x2E	// sensor hub output regs.
+#define LSM6DS3_SENSORHUB2_REG				0x2F
+#define LSM6DS3_SENSORHUB3_REG 				0x30
+#define LSM6DS3_SENSORHUB4_REG 				0x31
+#define LSM6DS3_SENSORHUB5_REG 				0x32
+#define LSM6DS3_SENSORHUB6_REG				0x33
+#define LSM6DS3_SENSORHUB7_REG 				0x34
+#define LSM6DS3_SENSORHUB8_REG 				0x35
+#define LSM6DS3_SENSORHUB9_REG 				0x36
+#define LSM6DS3_SENSORHUB10_REG 			0x37
+#define LSM6DS3_SENSORHUB11_REG				0x38
+#define LSM6DS3_SENSORHUB12_REG 			0x39
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FIFO_STATUS1				0x3A	// FIFO status regs.
+#define LSM6DS3_FIFO_STATUS2				0x3B
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FIFO_EMPTY 			BIT4
+#define LSM6DS3_FIFO_FULL 			BIT5
+#define LSM6DS3_FIFO_OVER_RUN		BIT6
+#define LSM6DS3_FIFO_THRESHOLD		BIT7
+/*------------------------------------------------------------------------------*/
+
+
+#define LSM6DS3_FIFO_STATUS3				0x3C
+#define LSM6DS3_FIFO_STATUS4				0x3D
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FIFO_DATA_OUT_L				0x3E	// FIFO data output regs.
+#define LSM6DS3_FIFO_DATA_OUT_H 			0x3F
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_TIMESTAMP0_REG 				0x40	// time stamp output regs.
+#define LSM6DS3_TIMESTAMP1_REG 				0x41
+#define LSM6DS3_TIMESTAMP2_REG 				0x42
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_STEP_TIMESTAMP_L 			0x49	// step counter timestamp regs.
+#define LSM6DS3_STEP_TIMESTAMP_H 			0x4A
+#define LSM6DS3_STEP_COUNTER_L				0x4B	// step counter output regs.
+#define LSM6DS3_STEP_COUNTER_H 				0x4C
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_SENSORHUB13_REG 			0x4D	// sensor hub output regs.
+#define LSM6DS3_SENSORHUB14_REG				0x4E
+#define LSM6DS3_SENSORHUB15_REG 			0x4F
+#define LSM6DS3_SENSORHUB16_REG				0x50
+#define LSM6DS3_SENSORHUB17_REG 			0x51
+#define LSM6DS3_SENSORHUB18_REG				0x52
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_FUNC_SRC					0x53	// interrupt regs.
+#define LSM6DS3_TAP_CFG 					0x58
+
+#define LSM6DS3_TIMER_EN					BIT7
+#define LSM6DS3_PEDO_EN						BIT6
+#define LSM6DS3_TILT_EN						BIT5
+#define LSM6DS3_SLOPE_FDS					BIT4
+#define LSM6DS3_TAP_X_EN					BIT3
+#define LSM6DS3_TAP_Y_EN					BIT2
+#define	LSM6DS3_TAP_Z_EN					BIT1
+#define LSM6DS3_LIR 						BIT0
+
+#define LSM6DS3_TAP_THS_6D 					0x59
+#define LSM6DS3_INT_DUR2 					0x5A
+#define LSM6DS3_WAKE_UP_THS					0x5B
+
+#define LSM6DS3_SINGLE_DOUBLE_TAP			BIT7
+#define LSM6DS3_INACTIVITY					BIT6
+
+#define LSM6DS3_WAKE_UP_DUR					0x5C
+
+#define LSM6DS3_FF_DUR5						BIT7
+#define LSM6DS3_TIMER_HR					BIT4
+
+#define LSM6DS3_FREE_FALL					0x5D
+#define LSM6DS3_MD1_CFG 					0x5E
+
+#define LSM6DS3_INT1_WU						BIT5
+
+#define LSM6DS3_MD2_CFG 					0x5F
+
+#define LSM6DS3_INT2_WU						BIT5
+/*------------------------------------------------------------------------------*/
+#define LSM6DS3_OUT_MAG_RAW_X_L 			0x66	// external mag. raw data output regs.
+#define LSM6DS3_OUT_MAG_RAW_X_H				0x67
+#define LSM6DS3_OUT_MAG_RAW_Y_L 			0x68
+#define LSM6DS3_OUT_MAG_RAW_Y_H				0x69
+#define LSM6DS3_OUT_MAG_RAW_Z_L				0x6A
+#define LSM6DS3_OUT_MAG_RAW_Z_H				0x6B
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Function Prototypes
+/*------------------------------------------------------------------------------*/
+int32_t LSM6DS3_Enable_I2C_Bridge(uint8_t enable);
+int32_t LSM6DS3_Enable_I2C_Pullups(uint8_t enable);
+/*------------------------------------------------------------------------------*/
+
+#endif /* INCLUDE_DRIVER_LSM6DS3_H_ */

+ 58 - 0
include/hal/max17043.h

@@ -0,0 +1,58 @@
+#ifndef MAX17043_H_
+#define MAX17043_H_
+
+#include "ets_sys.h"
+
+
+/*------------------------------------------------------------------------------*/
+// Debug Flag(s)
+/*------------------------------------------------------------------------------*/
+#define MAX17043_DEBUG		0
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Device I2C ID
+/*------------------------------------------------------------------------------*/
+#define DEVICE_ADDRESS		0x36
+#define WRITE_ADDRESS		0x6C // develop macro
+#define READ_ADDRESS 		0x6D  // develop macro
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Device Registers
+/*------------------------------------------------------------------------------*/
+#define VCELL_H     		0x02    // 12-bit ADC battery voltage
+#define VCELL_L     		0x03
+/*------------------------------------------------------------------------------*/
+#define SOC_H       		0x04    // 16-bit capacity estimation
+#define SOC_L      			0x05
+/*------------------------------------------------------------------------------*/
+#define MODE_H      		0x06    // sends special commands to IC
+#define MODE_L      		0x07
+/*------------------------------------------------------------------------------*/
+#define VERISON_H   		0x08    // returns IC version
+#define VERSION_L   		0x09
+/*------------------------------------------------------------------------------*/
+#define CONFIG_H    		0x0C    // battery compensation parameters
+#define CONFIG_L    		0x0D
+/*------------------------------------------------------------------------------*/
+#define COMMAND_H   		0xFE    // sends special commands to IC
+#define COMMAND_L   		0xFF
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Function Prototypes
+/*------------------------------------------------------------------------------*/
+uint16_t max17043_getVoltage(void);
+uint16_t max17043_getSOC(void);
+bool max17043_sleep(uint8_t enable);
+bool max17043_quickStart(void);
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Macro Definitions
+/*------------------------------------------------------------------------------*/
+#define max17043_i2c_init()		i2c_master_gpio_init()
+/*------------------------------------------------------------------------------*/
+
+#endif

+ 35 - 0
include/hal/ws2812.h

@@ -0,0 +1,35 @@
+#ifndef _WS2812_H
+#define _WS2812_H
+
+#define WSGPIO 0
+
+#include "c_types.h"
+#include "user_interface.h"
+#include "ets_sys.h"
+#include "gpio.h"
+
+/*------------------------------------------------------------------------------*/
+// Configuration Parameters 
+/*------------------------------------------------------------------------------*/
+#define WS2811_COMPATIBLE 	0 	// set to make driver backwards compatable. 
+/*------------------------------------------------------------------------------*/
+//You will have to 	os_intr_lock();  	os_intr_unlock();
+
+
+/* 
+	NOTE: The first byte stored is the last byte sent. 50us is required for sent data to latch to all LEDS
+	Data is stored in the following format: 
+	[ byte1: green, byte2: red, byte3: blue]
+	NOTE: Every function except ws2812_outBuffer is stored in Flash. 
+*/
+/*------------------------------------------------------------------------------*/
+// Function Prototypes
+/*------------------------------------------------------------------------------*/
+void ws2812_outBuffer( uint8_t * buffer, uint16_t length );
+// void ws2812_green(void); 
+// void ws2812_red(void); 
+// void ws2812_blue(void); 
+// void ws2812_clear(void);
+/*------------------------------------------------------------------------------*/
+#endif
+

+ 10 - 0
include/interface/uart_interface.h

@@ -0,0 +1,10 @@
+#ifndef UART_INTERFACE_H
+#define UART_INTERFACE_H
+
+#include "esp_common.h"
+
+void process_command(uint8_t *str);
+void uart0_rx_intr_handler_ideasX(void *para);
+
+
+#endif

+ 90 - 0
include/log/esp_log.h

@@ -0,0 +1,90 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_LOG_H__
+#define __ESP_LOG_H__
+
+#include <stdint.h>
+#include <stdarg.h>
+#include "esp_common.h"
+//#include "ets_sys.h"
+
+
+#define CONFIG_LOG_COLORS 1
+#define CONFIG_LOG_DEFAULT_LEVEL 100
+#define CPU_CLK_FREQ 80000000
+
+/**
+ * @brief Log level
+ *
+ */
+typedef enum {
+    ESP_LOG_NONE,       /*!< No log output */
+    ESP_LOG_ERROR,      /*!< Critical errors, software module can not recover on its own */
+    ESP_LOG_WARN,       /*!< Error conditions from which recovery measures have been taken */
+    ESP_LOG_INFO,       /*!< Information messages which describe normal flow of events */
+    ESP_LOG_DEBUG,      /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
+    ESP_LOG_VERBOSE     /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
+} esp_log_level_t;
+
+
+/**
+ * @brief Function which returns timestamp to be used in log output
+ *
+ * This function is used in expansion of ESP_LOGx macros.
+ * In the 2nd stage bootloader, and at early application startup stage
+ * this function uses CPU cycle counter as time source. Later when
+ * FreeRTOS scheduler start running, it switches to FreeRTOS tick count.
+ *
+ * For now, we ignore millisecond counter overflow.
+ *
+ * @return timestamp, in milliseconds
+ */
+uint32_t esp_log_timestamp(void);
+
+#if CONFIG_LOG_COLORS
+#define LOG_COLOR_BLACK   "30"
+#define LOG_COLOR_RED     "31"
+#define LOG_COLOR_GREEN   "32"
+#define LOG_COLOR_BROWN   "33"
+#define LOG_COLOR_BLUE    "34"
+#define LOG_COLOR_PURPLE  "35"
+#define LOG_COLOR_CYAN    "36"
+#define LOG_COLOR(COLOR)  "\033[0;" COLOR "m"
+#define LOG_BOLD(COLOR)   "\033[1;" COLOR "m"
+#define LOG_RESET_COLOR   "\033[0m"
+#define LOG_COLOR_E       LOG_COLOR(LOG_COLOR_RED)
+#define LOG_COLOR_W       LOG_COLOR(LOG_COLOR_BROWN)
+#define LOG_COLOR_I       LOG_COLOR(LOG_COLOR_GREEN)
+#define LOG_COLOR_D
+#define LOG_COLOR_V
+#else //CONFIG_LOG_COLORS
+#define LOG_COLOR_E
+#define LOG_COLOR_W
+#define LOG_COLOR_I
+#define LOG_COLOR_D
+#define LOG_COLOR_V
+#define LOG_RESET_COLOR
+#endif //CONFIG_LOG_COLORS
+
+#define LOG_FORMAT(letter, format)  LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
+#define LOG_LOCAL_LEVEL  ((esp_log_level_t) CONFIG_LOG_DEFAULT_LEVEL)
+
+#define ESP_LOGE( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR)   { os_printf(LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGW( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN)    { os_printf(LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGI( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO)    { os_printf(LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGD( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG)   { os_printf(LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+#define ESP_LOGV( tag, format, ... )  if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { os_printf(LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
+
+#endif /* __ESP_LOG_H__ */

+ 60 - 0
include/user_config.h

@@ -0,0 +1,60 @@
+#ifndef __USER_CONFIG_H__
+#define __USER_CONFIG_H__
+
+#define USE_OPTIMIZE_PRINTF
+
+/* FLASH CONFIGURATION SETTINGS */
+#define CFG_HOLDER				0x4171134
+#define CFG_LOCATION			0x2				  // this needs to be relocated to end of flash
+
+/* DEFAULT Wi-Fi SETTINGS */
+#define STA_SSID_1 "SSID"
+#define STA_PASS_1 "PASS"
+#define STA_PASS_2 "SSID"
+#define STA_SSID_2 "PASS"
+#define MAX_APS 5 // number of stored Wi-Fi accesspoint credientials (1 - 5)
+#define STORED_APS 1;
+
+/* MQTT DEFAULT CONFIGURATIONS */
+#define MQTT_HOST               "192.168.0.101" //or "mqtt.yourdomain.com"
+#define MQTT_PORT               1883
+#define MQTT_BUF_SIZE           1024
+#define QUEUE_BUFFER_SIZE       2048
+#define MQTT_RECONNECT_TIMEOUT  5 /*second*/
+#define DEFAULT_SECURITY        0
+#define PROTOCOL_NAMEv31  //MQTT version 3.1 compatible with Mosquitto v0.15
+//PROTOCOL_NAMEv311       //MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/
+
+#define MQTT_SSL_ENABLE
+#define MQTT_CLIENT_ID        "CLIENT_1234"
+#define MQTT_USER             "USER"
+#define MQTT_PASS             "PASS"
+#define MQTT_CLEAN_SESSION    1
+
+/* OTA SETTINGS */
+#define OTA_HOST 	"fphx.duckdns.org"
+#define OTA_PORT 	2000
+#define OTA_ROM0 	"rom0.bin"
+#define OTA_ROM1 	"rom1.bin"
+// OTA_FILE is not required, but is part of the example
+// code for writing arbitrary files to flash
+#define OTA_FILE "file.bin"
+
+// general http header
+#define HTTP_HEADER "Connection: keep-alive\r\n\
+Cache-Control: no-cache\r\n\
+User-Agent: rBoot-Sample/1.0\r\n\
+Accept: */*\r\n\r\n"
+
+// timeout for the initial connect and each recv (in ms)
+#define OTA_NETWORK_TIMEOUT  10000
+
+
+
+// This needs to be changed to support a logging library
+#if defined(DEBUG_ON)
+#define INFO( format, ... ) os_printf( format, ## __VA_ARGS__ )
+#else
+#define INFO( format, ... )
+#endif
+#endif

+ 57 - 0
include/util/config.h

@@ -0,0 +1,57 @@
+/******************************************************************************
+ * 2016 IdeasX v0.3.1 Module Firmware
+ *
+ * File Name: config.h
+ * Author: Tyler Berezowsky
+ * Description: This file is going to need alot of help by a C wizard, but it currently works...I think.
+ *
+ *     2016/8/8, v1.0 created this file
+*******************************************************************************/
+#ifndef __CONFIG_H__
+#define ___CONFIG_H__
+
+#include "os_type.h"
+#include "user_config.h"
+
+typedef struct{
+	uint32_t cfg_holder;
+	uint8_t device_id[16];
+
+	uint8_t sta_ssid[STORED_WIFI_APS][64];
+	uint8_t sta_pwd[STORED_WIFI_APS][64];
+	AUTH_MODE sta_type[STORED_WIFI_APS];
+	uint32_t registered_stations;
+	uint32_t current_station;
+
+	uint8_t mqtt_host[64];
+	uint32_t mqtt_port;
+	uint8_t mqtt_user[32];
+	uint8_t mqtt_pass[32];
+	uint32_t mqtt_keepalive;
+	uint32_t security;
+
+	uint8_t ota_host[64];
+	uint32_t ota_port;
+
+} SYSCFG;
+/*------------------------------------------------------------------------------*/
+typedef struct {
+    uint8 flag;
+    uint8 pad[3];
+} SAVE_FLAG;
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Function Prototypes
+/*------------------------------------------------------------------------------*/
+void ICACHE_FLASH_ATTR cfg_save();
+void ICACHE_FLASH_ATTR cfg_load();
+/*------------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------*/
+// Allocate Space for System Configuration
+/*------------------------------------------------------------------------------*/
+extern SYSCFG sysCfg;
+/*------------------------------------------------------------------------------*/
+
+#endif /* USER_CONFIG_H_ */

+ 48 - 0
include/util/ideasX.h

@@ -0,0 +1,48 @@
+
+
+typedef struct {
+ uint8_t topic = "hw_ver";
+ uint8_t minor;
+ uint8_t major;
+} hw_ver_t;
+
+typedef struct {
+ uint8_t topic = "fw_ver";
+ uint8_t minor;
+ uint8_t major;
+} fw_ver_t;
+
+typedef struct {
+ uint8_t topic = "alive";
+ bool flag;
+} alive_t;
+
+typedef struct {
+ uint8_t topic = "vcell";
+ uint32_t vcell;
+} vcell_t;
+
+typedef struct {
+  uint8_t topic = "rom";
+  uint8_t rom;
+} rom_t;
+
+typedef struct {
+  uint8_t topic = "ota";
+  bool ota;
+} ota_t;
+
+
+
+typedef struct{
+  hw_ver_t hw_ver;
+  fw_ver_t fw_ver;
+  alive_t alive;
+  vcell_t vcell;
+  soc_t soc;
+  rom_t rom;
+  ota_t ota;
+  ssid_t ssid;
+  bssid_t bssid;
+  rssi_t rssi;
+} ideasX_topics_t;

+ 62 - 0
include/util/wifi.h

@@ -0,0 +1,62 @@
+// enum {
+// 	REASON_UNSPECIFIED              = 1,
+// 	REASON_AUTH_EXPIRE              = 2,
+// 	REASON_AUTH_LEAVE               = 3,
+// 	REASON_ASSOC_EXPIRE             = 4,
+// 	REASON_ASSOC_TOOMANY            = 5,
+// 	REASON_NOT_AUTHED               = 6,
+// 	REASON_NOT_ASSOCED              = 7,
+// 	REASON_ASSOC_LEAVE              = 8,
+// 	REASON_ASSOC_NOT_AUTHED         = 9,
+// 	REASON_DISASSOC_PWRCAP_BAD      = 10,  /* 11h */
+// 	REASON_DISASSOC_SUPCHAN_BAD     = 11,  /* 11h */
+// 	REASON_IE_INVALID               = 13,  /* 11i */
+// 	REASON_MIC_FAILURE              = 14,  /* 11i */
+// 	REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,  /* 11i */
+// 	REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,  /* 11i */
+// 	REASON_IE_IN_4WAY_DIFFERS       = 17,  /* 11i */
+// 	REASON_GROUP_CIPHER_INVALID     = 18,  /* 11i */
+// 	REASON_PAIRWISE_CIPHER_INVALID  = 19,  /* 11i */
+// 	REASON_AKMP_INVALID             = 20,  /* 11i */
+// 	REASON_UNSUPP_RSN_IE_VERSION    = 21,  /* 11i */
+// 	REASON_INVALID_RSN_IE_CAP       = 22,  /* 11i */
+// 	REASON_802_1X_AUTH_FAILED       = 23,  /* 11i */
+// 	REASON_CIPHER_SUITE_REJECTED    = 24,  /* 11i */
+
+// 	REASON_BEACON_TIMEOUT           = 200,
+// 	REASON_NO_AP_FOUND              = 201,
+// 	REASON_AUTH_FAIL				= 202,
+// 	REASON_ASSOC_FAIL				= 203,
+// 	REASON_HANDSHAKE_TIMEOUT		= 204,
+// };
+
+// enum {
+//     EVENT_STAMODE_CONNECTED = 0,
+//     EVENT_STAMODE_DISCONNECTED,
+//     EVENT_STAMODE_AUTHMODE_CHANGE,
+//     EVENT_STAMODE_GOT_IP,
+//     EVENT_STAMODE_DHCP_TIMEOUT,
+//     EVENT_SOFTAPMODE_STACONNECTED,
+// 	EVENT_SOFTAPMODE_STADISCONNECTED,
+// 	EVENT_SOFTAPMODE_PROBEREQRECVED,
+//     EVENT_MAX
+// };
+
+#ifndef USER_WIFI_H_
+#define USER_WIFI_H_
+#include "os_type.h"
+
+typedef struct{
+	bool 	ip_flag; 
+	bool 	wifi_flag;
+	uint8_t wifi_count; 
+	uint8_t process_count;
+} WIFI_PROCESS_FLAGS;
+
+void ICACHE_FLASH_ATTR wifi_set_station(uint8_t* ssid, uint8_t* pass);
+void ICACHE_FLASH_ATTR disable_wifi_reconnect(void);
+void ICACHE_FLASH_ATTR start_wifi_process(void);
+void ICACHE_FLASH_ATTR show_wifi_config(void);
+
+
+#endif /* USER_WIFI_H_ */

+ 61 - 0
interface/uart_interface.c

@@ -0,0 +1,61 @@
+/*
+ * IdeasX UART Interface
+ * Author: Tyler Berezowsky
+ * Date: 20170518
+ */
+
+#include "uart_interface.h"
+//#include "uart.h"
+
+static void show_info(void)
+{
+     printf("SDK: v%s\n", system_get_sdk_version());
+     printf("Free Heap: %d\n", system_get_free_heap_size());
+     printf("CPU Frequency: %d MHz\n", system_get_cpu_freq());
+     printf("System Chip ID: 0x%x\n", system_get_chip_id());
+     printf("SPI Flash ID: 0x%x\n", spi_flash_get_id());
+     printf("SPI Flash Size: %d\n", (1 << ((spi_flash_get_id() >> 16) & 0xff)));
+}
+
+static void show_IP(void)
+{
+ 	struct ip_info ipconfig;
+ 	wifi_get_ip_info(STATION_IF, &ipconfig);
+ 	if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0) {
+ 		printf("IP: %d.%d.%d.%d, MASK: %d.%d.%d.%d, GW: %d.%d.%d.%d\n",
+ 			IP2STR(&ipconfig.ip), IP2STR(&ipconfig.netmask), IP2STR(&ipconfig.gw));
+ 	} else {
+ 		printf("Network Status: %d\n", wifi_station_get_connect_status());
+ 	}
+}
+
+void process_command(uint8_t *str)
+{
+	if (!strcmp(str, "help"))
+    {
+		printf("available commands\n");
+		printf("  help - display this message\n");
+		printf("  ip - show current ip\n");
+		printf("  wifi - show current and stored configurations\n");
+		printf("  setup - add new wifi AP\n");
+		printf("  restart - restart the esp8266\n");
+		printf("  switch - switch to the other rom and reboot\n");
+		printf("  info - show device info\n");
+		printf("  ota - force ota update, switch rom and reboot\n");
+		printf("  shutdown - force shutdown of module\n");
+		printf("\n");
+	}
+    else if (!strcmp(str, "restart"))
+    {
+		printf("Restarting...\n");
+		system_restart();
+	}
+    else if (!strcmp(str, "info"))
+    {
+        show_info();
+    }
+    else if (!strcmp(str, "ip"))
+    {
+		show_IP();
+    }
+}

+ 42 - 0
log/Makefile

@@ -0,0 +1,42 @@
+
+#############################################################
+# 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 = liblog.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 +=
+
+#############################################################
+# 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
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile

+ 31 - 0
log/log.c

@@ -0,0 +1,31 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ * Log library — implementation notes.
+ *
+ * This was once an amazing logging library...which did many things I don't
+ * understand. I sorta got it to work with the ESP8266, but it was originally
+ * built for the ESP32 by Espressif. I gave up on that...and not it does pretty
+ * much nothing but print messages.
+ *
+ * Mangled by Tyler Berezowsky
+ */
+
+#include "log/esp_log.h"
+
+uint32_t esp_log_timestamp()
+{
+    return xthal_get_ccount() / (CPU_CLK_FREQ / 1000);
+}

+ 44 - 0
mqtt/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# 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 = libmqtt.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 += 
+
+#############################################################
+# 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
+INCLUDES += -I ./
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 19 - 0
mqtt/include/debug.h

@@ -0,0 +1,19 @@
+/*
+ * debug.h
+ *
+ *  Created on: Dec 4, 2014
+ *      Author: Minh
+ */
+
+#ifndef USER_DEBUG_H_
+#define USER_DEBUG_H_
+
+
+#if defined(MQTT_DEBUG_ON)
+#define MQTT_INFO( format, ... ) os_printf( format, ## __VA_ARGS__ )
+#else
+#define MQTT_INFO( format, ... )
+#endif
+
+
+#endif /* USER_DEBUG_H_ */

+ 148 - 0
mqtt/include/mqtt.h

@@ -0,0 +1,148 @@
+/* mqtt.h
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef USER_AT_MQTT_H_
+#define USER_AT_MQTT_H_
+#include "user_config.h"
+#include "mqtt_msg.h"
+#include "user_interface.h"
+
+#include "queue.h"
+typedef struct mqtt_event_data_t
+{
+  uint8_t type;
+  const char* topic;
+  const char* data;
+  uint16_t topic_length;
+  uint16_t data_length;
+  uint16_t data_offset;
+} mqtt_event_data_t;
+
+typedef struct mqtt_state_t
+{
+  uint16_t port;
+  int auto_reconnect;
+  mqtt_connect_info_t* connect_info;
+  uint8_t* in_buffer;
+  uint8_t* out_buffer;
+  int in_buffer_length;
+  int out_buffer_length;
+  uint16_t message_length;
+  uint16_t message_length_read;
+  mqtt_message_t* outbound_message;
+  mqtt_connection_t mqtt_connection;
+  uint16_t pending_msg_id;
+  int pending_msg_type;
+  int pending_publish_qos;
+} mqtt_state_t;
+
+typedef enum {
+  WIFI_INIT,
+  WIFI_CONNECTING,
+  WIFI_CONNECTING_ERROR,
+  WIFI_CONNECTED,
+  DNS_RESOLVE,
+  TCP_DISCONNECTING,
+  TCP_DISCONNECTED,
+  TCP_RECONNECT_DISCONNECTING,
+  TCP_RECONNECT_REQ,
+  TCP_RECONNECT,
+  TCP_CONNECTING,
+  TCP_CONNECTING_ERROR,
+  TCP_CONNECTED,
+  MQTT_CONNECT_SEND,
+  MQTT_CONNECT_SENDING,
+  MQTT_SUBSCIBE_SEND,
+  MQTT_SUBSCIBE_SENDING,
+  MQTT_DATA,
+  MQTT_KEEPALIVE_SEND,
+  MQTT_PUBLISH_RECV,
+  MQTT_PUBLISHING,
+  MQTT_DELETING,
+  MQTT_DELETED,
+} tConnState;
+
+typedef void (*MqttCallback)(uint32_t *args);
+typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh);
+
+typedef struct  {
+  struct espconn *pCon;
+  uint8_t security;
+  uint8_t* host;
+  uint32_t port;
+  ip_addr_t ip;
+  mqtt_state_t  mqtt_state;
+  mqtt_connect_info_t connect_info;
+  MqttCallback connectedCb;
+  MqttCallback disconnectedCb;
+  MqttCallback publishedCb;
+  MqttCallback timeoutCb;
+  MqttDataCallback dataCb;
+  ETSTimer mqttTimer;
+  uint32_t keepAliveTick;
+  uint32_t reconnectTick;
+  uint32_t sendTimeout;
+  tConnState connState;
+  QUEUE msgQueue;
+  void* user_data;
+} MQTT_Client;
+
+#define SEC_NONSSL 0
+#define SEC_SSL 1
+
+#define MQTT_FLAG_CONNECTED   1
+#define MQTT_FLAG_READY     2
+#define MQTT_FLAG_EXIT      4
+
+#define MQTT_EVENT_TYPE_NONE      0
+#define MQTT_EVENT_TYPE_CONNECTED     1
+#define MQTT_EVENT_TYPE_DISCONNECTED  2
+#define MQTT_EVENT_TYPE_SUBSCRIBED    3
+#define MQTT_EVENT_TYPE_UNSUBSCRIBED  4
+#define MQTT_EVENT_TYPE_PUBLISH     5
+#define MQTT_EVENT_TYPE_PUBLISHED     6
+#define MQTT_EVENT_TYPE_EXITED      7
+#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
+
+void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security);
+BOOL ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession);
+void ICACHE_FLASH_ATTR MQTT_DeleteClient(MQTT_Client *mqttClient);
+void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain);
+void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb);
+void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb);
+void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb);
+void ICACHE_FLASH_ATTR MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb);
+void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb);
+BOOL ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
+BOOL ICACHE_FLASH_ATTR MQTT_UnSubscribe(MQTT_Client *client, char* topic);
+void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient);
+void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient);
+BOOL ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
+
+#endif /* USER_AT_MQTT_H_ */

+ 141 - 0
mqtt/include/mqtt_msg.h

@@ -0,0 +1,141 @@
+/*
+ * File:   mqtt_msg.h
+ * Author: Minh Tuan
+ *
+ * Created on July 12, 2014, 1:05 PM
+ */
+
+#ifndef MQTT_MSG_H
+#define MQTT_MSG_H
+#include "user_config.h"
+#include "c_types.h"
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+* Copyright (c) 2014, Stephen Robinson
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+/* 7      6     5     4     3     2     1     0*/
+/*|      --- Message Type----     |  DUP Flag |    QoS Level    | Retain  |
+/*                    Remaining Length                 */
+
+
+enum mqtt_message_type
+{
+  MQTT_MSG_TYPE_CONNECT = 1,
+  MQTT_MSG_TYPE_CONNACK = 2,
+  MQTT_MSG_TYPE_PUBLISH = 3,
+  MQTT_MSG_TYPE_PUBACK = 4,
+  MQTT_MSG_TYPE_PUBREC = 5,
+  MQTT_MSG_TYPE_PUBREL = 6,
+  MQTT_MSG_TYPE_PUBCOMP = 7,
+  MQTT_MSG_TYPE_SUBSCRIBE = 8,
+  MQTT_MSG_TYPE_SUBACK = 9,
+  MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
+  MQTT_MSG_TYPE_UNSUBACK = 11,
+  MQTT_MSG_TYPE_PINGREQ = 12,
+  MQTT_MSG_TYPE_PINGRESP = 13,
+  MQTT_MSG_TYPE_DISCONNECT = 14
+};
+
+enum mqtt_connect_return_code
+{
+  CONNECTION_ACCEPTED = 0,
+  CONNECTION_REFUSE_PROTOCOL,
+  CONNECTION_REFUSE_ID_REJECTED,
+  CONNECTION_REFUSE_SERVER_UNAVAILABLE,
+  CONNECTION_REFUSE_BAD_USERNAME,
+  CONNECTION_REFUSE_NOT_AUTHORIZED
+};
+
+typedef struct mqtt_message
+{
+  uint8_t* data;
+  uint16_t length;
+
+} mqtt_message_t;
+
+typedef struct mqtt_connection
+{
+  mqtt_message_t message;
+
+  uint16_t message_id;
+  uint8_t* buffer;
+  uint16_t buffer_length;
+
+} mqtt_connection_t;
+
+typedef struct mqtt_connect_info
+{
+  char* client_id;
+  char* username;
+  char* password;
+  char* will_topic;
+  char* will_message;
+  uint32_t keepalive;
+  int will_qos;
+  int will_retain;
+  int clean_session;
+
+} mqtt_connect_info_t;
+
+
+static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
+static inline int ICACHE_FLASH_ATTR mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; }
+static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
+static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
+static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
+
+void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
+int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length);
+const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
+const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
+uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length);
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection);
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection);
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* MQTT_MSG_H */
+

+ 32 - 0
mqtt/include/proto.h

@@ -0,0 +1,32 @@
+/*
+ * File:   proto.h
+ * Author: ThuHien
+ *
+ * Created on November 23, 2012, 8:57 AM
+ */
+
+#ifndef _PROTO_H_
+#define _PROTO_H_
+#include <stdlib.h>
+#include "typedef.h"
+#include "ringbuf.h"
+
+typedef void(PROTO_PARSE_CALLBACK)();
+
+typedef struct {
+  U8 *buf;
+  U16 bufSize;
+  U16 dataLen;
+  U8 isEsc;
+  U8 isBegin;
+  PROTO_PARSE_CALLBACK* callback;
+} PROTO_PARSER;
+
+I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize);
+I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len);
+I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize);
+I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len);
+I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value);
+I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen);
+#endif
+

+ 44 - 0
mqtt/include/queue.h

@@ -0,0 +1,44 @@
+/* str_queue.h --
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef USER_QUEUE_H_
+#define USER_QUEUE_H_
+#include "os_type.h"
+#include "ringbuf.h"
+typedef struct {
+  uint8_t *buf;
+  RINGBUF rb;
+} QUEUE;
+
+void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize);
+int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len);
+int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
+BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue);
+#endif /* USER_QUEUE_H_ */

+ 19 - 0
mqtt/include/ringbuf.h

@@ -0,0 +1,19 @@
+#ifndef _RING_BUF_H_
+#define _RING_BUF_H_
+
+#include <os_type.h>
+#include <stdlib.h>
+#include "typedef.h"
+
+typedef struct {
+  U8* p_o;        /**< Original pointer */
+  U8* volatile p_r;   /**< Read pointer */
+  U8* volatile p_w;   /**< Write pointer */
+  volatile I32 fill_cnt;  /**< Number of filled slots */
+  I32 size;       /**< Buffer size */
+} RINGBUF;
+
+I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size);
+I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c);
+I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c);
+#endif

+ 17 - 0
mqtt/include/typedef.h

@@ -0,0 +1,17 @@
+/**
+* \file
+*   Standard Types definition
+*/
+
+#ifndef _TYPE_DEF_H_
+#define _TYPE_DEF_H_
+
+typedef char I8;
+typedef unsigned char U8;
+typedef short I16;
+typedef unsigned short U16;
+typedef long I32;
+typedef unsigned long U32;
+typedef unsigned long long U64;
+
+#endif

+ 9 - 0
mqtt/include/utils.h

@@ -0,0 +1,9 @@
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include "c_types.h"
+
+uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s);
+uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip);
+uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str);
+#endif

+ 995 - 0
mqtt/mqtt.c

@@ -0,0 +1,995 @@
+/* mqtt.c
+*  Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "user_interface.h"
+#include "osapi.h"
+#include "espconn.h"
+#include "os_type.h"
+#include "mem.h"
+#include "mqtt_msg.h"
+#include "debug.h"
+#include "user_config.h"
+#include "mqtt.h"
+#include "queue.h"
+
+#define MQTT_TASK_PRIO            2
+#define MQTT_TASK_QUEUE_SIZE      1
+#define MQTT_SEND_TIMOUT      5
+
+#ifndef MQTT_SSL_SIZE
+#define MQTT_SSL_SIZE         5120
+#endif
+
+#ifndef QUEUE_BUFFER_SIZE
+#define QUEUE_BUFFER_SIZE     2048
+#endif
+
+unsigned char *default_certificate;
+unsigned int default_certificate_len = 0;
+unsigned char *default_private_key;
+unsigned int default_private_key_len = 0;
+
+os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE];
+
+#ifdef PROTOCOL_NAMEv311
+LOCAL uint8_t zero_len_id[2] = { 0, 0 };
+#endif
+
+LOCAL void ICACHE_FLASH_ATTR
+mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
+{
+  struct espconn *pConn = (struct espconn *)arg;
+  MQTT_Client* client = (MQTT_Client *)pConn->reverse;
+
+
+  if (ipaddr == NULL)
+  {
+    MQTT_INFO("DNS: Found, but got no ip, try to reconnect\r\n");
+    client->connState = TCP_RECONNECT_REQ;
+    return;
+  }
+
+  MQTT_INFO("DNS: found ip %d.%d.%d.%d\n",
+            *((uint8 *) &ipaddr->addr),
+            *((uint8 *) &ipaddr->addr + 1),
+            *((uint8 *) &ipaddr->addr + 2),
+            *((uint8 *) &ipaddr->addr + 3));
+
+  if (client->ip.addr == 0 && ipaddr->addr != 0)
+  {
+    os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
+    if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+      espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE);
+      espconn_secure_connect(client->pCon);
+#else
+      MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+    }
+    else {
+      espconn_connect(client->pCon);
+    }
+
+    client->connState = TCP_CONNECTING;
+    MQTT_INFO("TCP: connecting...\r\n");
+  }
+
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+}
+
+
+
+LOCAL void ICACHE_FLASH_ATTR
+deliver_publish(MQTT_Client* client, uint8_t* message, int length)
+{
+  mqtt_event_data_t event_data;
+
+  event_data.topic_length = length;
+  event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
+  event_data.data_length = length;
+  event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
+
+  if (client->dataCb)
+    client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length);
+
+}
+
+void ICACHE_FLASH_ATTR
+mqtt_send_keepalive(MQTT_Client *client)
+{
+  MQTT_INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port);
+  client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
+  client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ;
+  client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+  client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+
+
+  client->sendTimeout = MQTT_SEND_TIMOUT;
+  MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
+  err_t result = ESPCONN_OK;
+  if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+    result = espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+#else
+    MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+  }
+  else {
+    result = espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+  }
+
+  client->mqtt_state.outbound_message = NULL;
+  if (ESPCONN_OK == result) {
+    client->keepAliveTick = 0;
+    client->connState = MQTT_DATA;
+    system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+  }
+  else {
+    client->connState = TCP_RECONNECT_DISCONNECTING;
+    system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+  }
+}
+
+/**
+  * @brief  Delete tcp client and free all memory
+  * @param  mqttClient: The mqtt client which contain TCP client
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_delete(MQTT_Client *mqttClient)
+{
+  if (mqttClient->pCon != NULL) {
+    MQTT_INFO("TCP: Free memory\r\n");
+    // Force abort connections
+    espconn_abort(mqttClient->pCon);
+    // Delete connections
+    espconn_delete(mqttClient->pCon);
+
+    if (mqttClient->pCon->proto.tcp) {
+      os_free(mqttClient->pCon->proto.tcp);
+      mqttClient->pCon->proto.tcp = NULL;
+    }
+    os_free(mqttClient->pCon);
+    mqttClient->pCon = NULL;
+  }
+}
+
+/**
+  * @brief  Delete MQTT client and free all memory
+  * @param  mqttClient: The mqtt client
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_client_delete(MQTT_Client *mqttClient)
+{
+  if (mqttClient == NULL)
+    return;
+
+  if (mqttClient->pCon != NULL) {
+    mqtt_tcpclient_delete(mqttClient);
+  }
+
+  if (mqttClient->host != NULL) {
+    os_free(mqttClient->host);
+    mqttClient->host = NULL;
+  }
+
+  if (mqttClient->user_data != NULL) {
+    os_free(mqttClient->user_data);
+    mqttClient->user_data = NULL;
+  }
+
+  if (mqttClient->mqtt_state.in_buffer != NULL) {
+    os_free(mqttClient->mqtt_state.in_buffer);
+    mqttClient->mqtt_state.in_buffer = NULL;
+  }
+
+  if (mqttClient->mqtt_state.out_buffer != NULL) {
+    os_free(mqttClient->mqtt_state.out_buffer);
+    mqttClient->mqtt_state.out_buffer = NULL;
+  }
+
+  if (mqttClient->mqtt_state.outbound_message != NULL) {
+    if (mqttClient->mqtt_state.outbound_message->data != NULL)
+    {
+      os_free(mqttClient->mqtt_state.outbound_message->data);
+      mqttClient->mqtt_state.outbound_message->data = NULL;
+    }
+  }
+
+  if (mqttClient->mqtt_state.mqtt_connection.buffer != NULL) {
+    // Already freed but not NULL
+    mqttClient->mqtt_state.mqtt_connection.buffer = NULL;
+  }
+
+  if (mqttClient->connect_info.client_id != NULL) {
+#ifdef PROTOCOL_NAMEv311
+    /* Don't attempt to free if it's the zero_len array */
+    if ( ((uint8_t*)mqttClient->connect_info.client_id) != zero_len_id )
+      os_free(mqttClient->connect_info.client_id);
+#else
+    os_free(mqttClient->connect_info.client_id);
+#endif
+    mqttClient->connect_info.client_id = NULL;
+  }
+
+  if (mqttClient->connect_info.username != NULL) {
+    os_free(mqttClient->connect_info.username);
+    mqttClient->connect_info.username = NULL;
+  }
+
+  if (mqttClient->connect_info.password != NULL) {
+    os_free(mqttClient->connect_info.password);
+    mqttClient->connect_info.password = NULL;
+  }
+
+  if (mqttClient->connect_info.will_topic != NULL) {
+    os_free(mqttClient->connect_info.will_topic);
+    mqttClient->connect_info.will_topic = NULL;
+  }
+
+  if (mqttClient->connect_info.will_message != NULL) {
+    os_free(mqttClient->connect_info.will_message);
+    mqttClient->connect_info.will_message = NULL;
+  }
+
+  if (mqttClient->msgQueue.buf != NULL) {
+    os_free(mqttClient->msgQueue.buf);
+    mqttClient->msgQueue.buf = NULL;
+  }
+
+  // Initialize state
+  mqttClient->connState = WIFI_INIT;
+  // Clear callback functions to avoid abnormal callback
+  mqttClient->connectedCb = NULL;
+  mqttClient->disconnectedCb = NULL;
+  mqttClient->publishedCb = NULL;
+  mqttClient->timeoutCb = NULL;
+  mqttClient->dataCb = NULL;
+
+  MQTT_INFO("MQTT: client already deleted\r\n");
+}
+
+
+/**
+  * @brief  Client received callback function.
+  * @param  arg: contain the ip link information
+  * @param  pdata: received data
+  * @param  len: the lenght of received data
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len)
+{
+  uint8_t msg_type;
+  uint8_t msg_qos;
+  uint16_t msg_id;
+  uint8_t msg_conn_ret;
+
+  struct espconn *pCon = (struct espconn*)arg;
+  MQTT_Client *client = (MQTT_Client *)pCon->reverse;
+
+READPACKET:
+  MQTT_INFO("TCP: data received %d bytes\r\n", len);
+  // MQTT_INFO("STATE: %d\r\n", client->connState);
+  if (len < MQTT_BUF_SIZE && len > 0) {
+    os_memcpy(client->mqtt_state.in_buffer, pdata, len);
+
+    msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
+    msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
+    msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
+    switch (client->connState) {
+      case MQTT_CONNECT_SENDING:
+        if (msg_type == MQTT_MSG_TYPE_CONNACK) {
+          if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT) {
+            MQTT_INFO("MQTT: Invalid packet\r\n");
+            if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+              espconn_secure_disconnect(client->pCon);
+#else
+              MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+            }
+            else {
+              espconn_disconnect(client->pCon);
+            }
+          } else {
+            msg_conn_ret = mqtt_get_connect_return_code(client->mqtt_state.in_buffer);
+            switch (msg_conn_ret) {
+              case CONNECTION_ACCEPTED:
+                MQTT_INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port);
+                client->connState = MQTT_DATA;
+                if (client->connectedCb)
+                  client->connectedCb((uint32_t*)client);
+                break;
+              case CONNECTION_REFUSE_PROTOCOL:
+              case CONNECTION_REFUSE_SERVER_UNAVAILABLE:
+              case CONNECTION_REFUSE_BAD_USERNAME:
+              case CONNECTION_REFUSE_NOT_AUTHORIZED:
+                MQTT_INFO("MQTT: Connection refuse, reason code: %d\r\n", msg_conn_ret);
+              default:
+                if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+                  espconn_secure_disconnect(client->pCon);
+#else
+                  MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+                }
+                else {
+                  espconn_disconnect(client->pCon);
+                }
+
+            }
+
+          }
+
+        }
+        break;
+      case MQTT_DATA:
+      case MQTT_KEEPALIVE_SEND:
+        client->mqtt_state.message_length_read = len;
+        client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
+
+
+        switch (msg_type)
+        {
+
+          case MQTT_MSG_TYPE_SUBACK:
+            if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
+              MQTT_INFO("MQTT: Subscribe successful\r\n");
+            break;
+          case MQTT_MSG_TYPE_UNSUBACK:
+            if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
+              MQTT_INFO("MQTT: UnSubscribe successful\r\n");
+            break;
+          case MQTT_MSG_TYPE_PUBLISH:
+            if (msg_qos == 1)
+              client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
+            else if (msg_qos == 2)
+              client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
+            if (msg_qos == 1 || msg_qos == 2) {
+              MQTT_INFO("MQTT: Queue response QoS: %d\r\n", msg_qos);
+              if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+                MQTT_INFO("MQTT: Queue full\r\n");
+              }
+            }
+
+            deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
+            break;
+          case MQTT_MSG_TYPE_PUBACK:
+            if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) {
+              MQTT_INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n");
+            }
+
+            break;
+          case MQTT_MSG_TYPE_PUBREC:
+            client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
+            if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+              MQTT_INFO("MQTT: Queue full\r\n");
+            }
+            break;
+          case MQTT_MSG_TYPE_PUBREL:
+            client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
+            if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+              MQTT_INFO("MQTT: Queue full\r\n");
+            }
+            break;
+          case MQTT_MSG_TYPE_PUBCOMP:
+            if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) {
+              MQTT_INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n");
+            }
+            break;
+          case MQTT_MSG_TYPE_PINGREQ:
+            client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
+            if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+              MQTT_INFO("MQTT: Queue full\r\n");
+            }
+            break;
+          case MQTT_MSG_TYPE_PINGRESP:
+            // Ignore
+            break;
+        }
+        // NOTE: this is done down here and not in the switch case above
+        // because the PSOCK_READBUF_LEN() won't work inside a switch
+        // statement due to the way protothreads resume.
+        if (msg_type == MQTT_MSG_TYPE_PUBLISH)
+        {
+          len = client->mqtt_state.message_length_read;
+
+          if (client->mqtt_state.message_length < client->mqtt_state.message_length_read)
+          {
+            //client->connState = MQTT_PUBLISH_RECV;
+            //Not Implement yet
+            len -= client->mqtt_state.message_length;
+            pdata += client->mqtt_state.message_length;
+
+            MQTT_INFO("Get another published message\r\n");
+            goto READPACKET;
+          }
+
+        }
+        break;
+    }
+  } else {
+    MQTT_INFO("ERROR: Message too long\r\n");
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+}
+
+/**
+  * @brief  Client send over callback function.
+  * @param  arg: contain the ip link information
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_sent_cb(void *arg)
+{
+  struct espconn *pCon = (struct espconn *)arg;
+  MQTT_Client* client = (MQTT_Client *)pCon->reverse;
+  MQTT_INFO("TCP: Sent\r\n");
+  client->sendTimeout = 0;
+  client->keepAliveTick = 0;
+
+  if ((client->connState == MQTT_DATA || client->connState == MQTT_KEEPALIVE_SEND)
+      && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) {
+    if (client->publishedCb)
+      client->publishedCb((uint32_t*)client);
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+}
+
+void ICACHE_FLASH_ATTR mqtt_timer(void *arg)
+{
+  MQTT_Client* client = (MQTT_Client*)arg;
+
+  if (client->connState == MQTT_DATA) {
+    client->keepAliveTick ++;
+    if (client->keepAliveTick > (client->mqtt_state.connect_info->keepalive / 2)) {
+      client->connState = MQTT_KEEPALIVE_SEND;
+      system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+    }
+
+  } else if (client->connState == TCP_RECONNECT_REQ) {
+    client->reconnectTick ++;
+    if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) {
+      client->reconnectTick = 0;
+      client->connState = TCP_RECONNECT;
+      system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+      if (client->timeoutCb)
+        client->timeoutCb((uint32_t*)client);
+    }
+  }
+  if (client->sendTimeout > 0)
+    client->sendTimeout --;
+}
+
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_discon_cb(void *arg)
+{
+
+  struct espconn *pespconn = (struct espconn *)arg;
+  MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
+  MQTT_INFO("TCP: Disconnected callback\r\n");
+  if (TCP_DISCONNECTING == client->connState) {
+    client->connState = TCP_DISCONNECTED;
+  }
+  else if (MQTT_DELETING == client->connState) {
+    client->connState = MQTT_DELETED;
+  }
+  else {
+    client->connState = TCP_RECONNECT_REQ;
+  }
+  if (client->disconnectedCb)
+    client->disconnectedCb((uint32_t*)client);
+
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+}
+
+
+
+/**
+  * @brief  Tcp client connect success callback function.
+  * @param  arg: contain the ip link information
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_connect_cb(void *arg)
+{
+  struct espconn *pCon = (struct espconn *)arg;
+  MQTT_Client* client = (MQTT_Client *)pCon->reverse;
+
+  espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb);
+  espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);////////
+  espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);///////
+  MQTT_INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port);
+
+  mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);
+  client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);
+  client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
+  client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+
+
+  client->sendTimeout = MQTT_SEND_TIMOUT;
+  MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
+  if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+    espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+#else
+    MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+  }
+  else {
+    espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
+  }
+
+  client->mqtt_state.outbound_message = NULL;
+  client->connState = MQTT_CONNECT_SENDING;
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+}
+
+/**
+  * @brief  Tcp client connect repeat callback function.
+  * @param  arg: contain the ip link information
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+mqtt_tcpclient_recon_cb(void *arg, sint8 errType)
+{
+  struct espconn *pCon = (struct espconn *)arg;
+  MQTT_Client* client = (MQTT_Client *)pCon->reverse;
+
+  MQTT_INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port);
+
+  client->connState = TCP_RECONNECT_REQ;
+
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+
+}
+
+/**
+  * @brief  MQTT publish function.
+  * @param  client:   MQTT_Client reference
+  * @param  topic:    string topic will publish to
+  * @param  data:     buffer data send point to
+  * @param  data_length: length of data
+  * @param  qos:    qos
+  * @param  retain:   retain
+  * @retval TRUE if success queue
+  */
+BOOL ICACHE_FLASH_ATTR
+MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain)
+{
+  uint8_t dataBuffer[MQTT_BUF_SIZE];
+  uint16_t dataLen;
+  client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
+                                        topic, data, data_length,
+                                        qos, retain,
+                                        &client->mqtt_state.pending_msg_id);
+  if (client->mqtt_state.outbound_message->length == 0) {
+    MQTT_INFO("MQTT: Queuing publish failed\r\n");
+    return FALSE;
+  }
+  MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);
+  while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+    MQTT_INFO("MQTT: Queue full\r\n");
+    if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
+      MQTT_INFO("MQTT: Serious buffer error\r\n");
+      return FALSE;
+    }
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+  return TRUE;
+}
+
+/**
+  * @brief  MQTT subscibe function.
+  * @param  client:   MQTT_Client reference
+  * @param  topic:    string topic will subscribe
+  * @param  qos:    qos
+  * @retval TRUE if success queue
+  */
+BOOL ICACHE_FLASH_ATTR
+MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos)
+{
+  uint8_t dataBuffer[MQTT_BUF_SIZE];
+  uint16_t dataLen;
+
+  client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
+                                        topic, qos,
+                                        &client->mqtt_state.pending_msg_id);
+  MQTT_INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id);
+  while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+    MQTT_INFO("MQTT: Queue full\r\n");
+    if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
+      MQTT_INFO("MQTT: Serious buffer error\r\n");
+      return FALSE;
+    }
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+
+  return TRUE;
+}
+
+/**
+  * @brief  MQTT un-subscibe function.
+  * @param  client:   MQTT_Client reference
+  * @param  topic:   String topic will un-subscribe
+  * @retval TRUE if success queue
+  */
+BOOL ICACHE_FLASH_ATTR
+MQTT_UnSubscribe(MQTT_Client *client, char* topic)
+{
+  uint8_t dataBuffer[MQTT_BUF_SIZE];
+  uint16_t dataLen;
+  client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection,
+                                        topic,
+                                        &client->mqtt_state.pending_msg_id);
+  MQTT_INFO("MQTT: queue un-subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id);
+  while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+    MQTT_INFO("MQTT: Queue full\r\n");
+    if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
+      MQTT_INFO("MQTT: Serious buffer error\r\n");
+      return FALSE;
+    }
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+  return TRUE;
+}
+
+/**
+  * @brief  MQTT ping function.
+  * @param  client:   MQTT_Client reference
+  * @retval TRUE if success queue
+  */
+BOOL ICACHE_FLASH_ATTR
+MQTT_Ping(MQTT_Client *client)
+{
+  uint8_t dataBuffer[MQTT_BUF_SIZE];
+  uint16_t dataLen;
+  client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
+  if (client->mqtt_state.outbound_message->length == 0) {
+    MQTT_INFO("MQTT: Queuing publish failed\r\n");
+    return FALSE;
+  }
+  MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);
+  while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
+    MQTT_INFO("MQTT: Queue full\r\n");
+    if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
+      MQTT_INFO("MQTT: Serious buffer error\r\n");
+      return FALSE;
+    }
+  }
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
+  return TRUE;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_Task(os_event_t *e)
+{
+  MQTT_Client* client = (MQTT_Client*)e->par;
+  uint8_t dataBuffer[MQTT_BUF_SIZE];
+  uint16_t dataLen;
+  if (e->par == 0)
+    return;
+  switch (client->connState) {
+
+    case TCP_RECONNECT_REQ:
+      break;
+    case TCP_RECONNECT:
+      mqtt_tcpclient_delete(client);
+      MQTT_Connect(client);
+      MQTT_INFO("TCP: Reconnect to: %s:%d\r\n", client->host, client->port);
+      client->connState = TCP_CONNECTING;
+      break;
+    case MQTT_DELETING:
+    case TCP_DISCONNECTING:
+    case TCP_RECONNECT_DISCONNECTING:
+      if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+        espconn_secure_disconnect(client->pCon);
+#else
+        MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+      }
+      else {
+        espconn_disconnect(client->pCon);
+      }
+      break;
+    case TCP_DISCONNECTED:
+      MQTT_INFO("MQTT: Disconnected\r\n");
+      mqtt_tcpclient_delete(client);
+      break;
+    case MQTT_DELETED:
+      MQTT_INFO("MQTT: Deleted client\r\n");
+      mqtt_client_delete(client);
+      break;
+    case MQTT_KEEPALIVE_SEND:
+      mqtt_send_keepalive(client);
+      break;
+    case MQTT_DATA:
+      if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) {
+        break;
+      }
+      if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0) {
+        client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer);
+        client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen);
+
+
+        client->sendTimeout = MQTT_SEND_TIMOUT;
+        MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
+        client->keepAliveTick = 0;
+        if (client->security) {
+#ifdef MQTT_SSL_ENABLE
+          espconn_secure_send(client->pCon, dataBuffer, dataLen);
+#else
+          MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+        }
+        else {
+          espconn_send(client->pCon, dataBuffer, dataLen);
+        }
+
+        client->mqtt_state.outbound_message = NULL;
+        break;
+      }
+      break;
+  }
+}
+
+/**
+  * @brief  MQTT initialization connection function
+  * @param  client:   MQTT_Client reference
+  * @param  host:   Domain or IP string
+  * @param  port:   Port to connect
+  * @param  security:   1 for ssl, 0 for none
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security)
+{
+  uint32_t temp;
+  MQTT_INFO("MQTT:InitConnection\r\n");
+  os_memset(mqttClient, 0, sizeof(MQTT_Client));
+  temp = os_strlen(host);
+  mqttClient->host = (uint8_t*)os_zalloc(temp + 1);
+  os_strcpy(mqttClient->host, host);
+  mqttClient->host[temp] = 0;
+  mqttClient->port = port;
+  mqttClient->security = security;
+
+}
+
+/**
+  * @brief  MQTT initialization mqtt client function
+  * @param  client:   MQTT_Client reference
+  * @param  clientid:   MQTT client id
+  * @param  client_user:MQTT client user
+  * @param  client_pass:MQTT client password
+  * @param  client_pass:MQTT keep alive timer, in second
+  * @retval None
+  */
+BOOL ICACHE_FLASH_ATTR
+MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)
+{
+  uint32_t temp;
+  MQTT_INFO("MQTT:InitClient\r\n");
+
+  os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
+
+  if ( !client_id )
+  {
+    /* Should be allowed by broker, but clean session flag must be set. */
+  #ifdef PROTOCOL_NAMEv311
+    if (cleanSession)
+    {
+      mqttClient->connect_info.client_id = zero_len_id;
+    } else {
+      MQTT_INFO("cleanSession must be set to use 0 length client_id\r\n");
+      return false;
+    }
+    /* Not supported. Return. */
+  #else
+    MQTT_INFO("Client ID required for MQTT < 3.1.1!\r\n");
+    return false;
+  #endif
+ }
+
+  /* If connect_info's client_id is still NULL and we get here, we can        *
+   * assume the passed client_id is non-NULL.                                 */
+  if ( !(mqttClient->connect_info.client_id) )
+  {
+    temp = os_strlen(client_id);
+    mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
+    os_strcpy(mqttClient->connect_info.client_id, client_id);
+    mqttClient->connect_info.client_id[temp] = 0;
+  }
+
+  if (client_user)
+  {
+    temp = os_strlen(client_user);
+    mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);
+    os_strcpy(mqttClient->connect_info.username, client_user);
+    mqttClient->connect_info.username[temp] = 0;
+  }
+
+  if (client_pass)
+  {
+    temp = os_strlen(client_pass);
+    mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);
+    os_strcpy(mqttClient->connect_info.password, client_pass);
+    mqttClient->connect_info.password[temp] = 0;
+  }
+
+
+  mqttClient->connect_info.keepalive = keepAliveTime;
+  mqttClient->connect_info.clean_session = cleanSession;
+
+  mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
+  mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
+  mqttClient->mqtt_state.out_buffer =  (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
+  mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
+  mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
+
+  mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);
+
+  QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);
+
+  system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
+  return true;
+}
+void ICACHE_FLASH_ATTR
+MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain)
+{
+  uint32_t temp;
+  temp = os_strlen(will_topic);
+  mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1);
+  os_strcpy(mqttClient->connect_info.will_topic, will_topic);
+  mqttClient->connect_info.will_topic[temp] = 0;
+
+  temp = os_strlen(will_msg);
+  mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1);
+  os_strcpy(mqttClient->connect_info.will_message, will_msg);
+  mqttClient->connect_info.will_message[temp] = 0;
+
+
+  mqttClient->connect_info.will_qos = will_qos;
+  mqttClient->connect_info.will_retain = will_retain;
+}
+/**
+  * @brief  Begin connect to MQTT broker
+  * @param  client: MQTT_Client reference
+  * @retval None
+  */
+void ICACHE_FLASH_ATTR
+MQTT_Connect(MQTT_Client *mqttClient)
+{
+  if (mqttClient->pCon) {
+    // Clean up the old connection forcefully - using MQTT_Disconnect
+    // does not actually release the old connection until the
+    // disconnection callback is invoked.
+    mqtt_tcpclient_delete(mqttClient);
+  }
+  mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
+  mqttClient->pCon->type = ESPCONN_TCP;
+  mqttClient->pCon->state = ESPCONN_NONE;
+  mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
+  mqttClient->pCon->proto.tcp->local_port = espconn_port();
+  mqttClient->pCon->proto.tcp->remote_port = mqttClient->port;
+  mqttClient->pCon->reverse = mqttClient;
+  espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb);
+  espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb);
+
+  mqttClient->keepAliveTick = 0;
+  mqttClient->reconnectTick = 0;
+
+
+  os_timer_disarm(&mqttClient->mqttTimer);
+  os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient);
+  os_timer_arm(&mqttClient->mqttTimer, 1000, 1);
+
+  if (UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) {
+    MQTT_INFO("TCP: Connect to ip  %s:%d\r\n", mqttClient->host, mqttClient->port);
+    if (mqttClient->security)
+    {
+#ifdef MQTT_SSL_ENABLE
+      espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE);
+      espconn_secure_connect(mqttClient->pCon);
+#else
+      MQTT_INFO("TCP: Do not support SSL\r\n");
+#endif
+    }
+    else
+    {
+      espconn_connect(mqttClient->pCon);
+    }
+  }
+  else {
+    MQTT_INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port);
+    espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found);
+  }
+  mqttClient->connState = TCP_CONNECTING;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_Disconnect(MQTT_Client *mqttClient)
+{
+  mqttClient->connState = TCP_DISCONNECTING;
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
+  os_timer_disarm(&mqttClient->mqttTimer);
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_DeleteClient(MQTT_Client *mqttClient)
+{
+  if (NULL == mqttClient)
+    return;
+
+  mqttClient->connState = MQTT_DELETED;
+  // if(TCP_DISCONNECTED == mqttClient->connState) {
+  //  mqttClient->connState = MQTT_DELETED;
+  // } else if(MQTT_DELETED != mqttClient->connState) {
+  //  mqttClient->connState = MQTT_DELETING;
+  // }
+
+  system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
+  os_timer_disarm(&mqttClient->mqttTimer);
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb)
+{
+  mqttClient->connectedCb = connectedCb;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb)
+{
+  mqttClient->disconnectedCb = disconnectedCb;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb)
+{
+  mqttClient->dataCb = dataCb;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb)
+{
+  mqttClient->publishedCb = publishedCb;
+}
+
+void ICACHE_FLASH_ATTR
+MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb)
+{
+  mqttClient->timeoutCb = timeoutCb;
+}

+ 487 - 0
mqtt/mqtt_msg.c

@@ -0,0 +1,487 @@
+/*
+* Copyright (c) 2014, Stephen Robinson
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include <string.h>
+#include "mqtt_msg.h"
+#include "user_config.h"
+#define MQTT_MAX_FIXED_HEADER_SIZE 3
+
+enum mqtt_connect_flag
+{
+  MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
+  MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
+  MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
+  MQTT_CONNECT_FLAG_WILL = 1 << 2,
+  MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
+};
+
+struct __attribute((__packed__)) mqtt_connect_variable_header
+{
+  uint8_t lengthMsb;
+  uint8_t lengthLsb;
+#if defined(PROTOCOL_NAMEv31)
+  uint8_t magic[6];
+#elif defined(PROTOCOL_NAMEv311)
+  uint8_t magic[4];
+#else
+#error "Please define protocol name"
+#endif
+  uint8_t version;
+  uint8_t flags;
+  uint8_t keepaliveMsb;
+  uint8_t keepaliveLsb;
+};
+
+static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len)
+{
+  if (connection->message.length + len + 2 > connection->buffer_length)
+    return -1;
+
+  connection->buffer[connection->message.length++] = len >> 8;
+  connection->buffer[connection->message.length++] = len & 0xff;
+  memcpy(connection->buffer + connection->message.length, string, len);
+  connection->message.length += len;
+
+  return len + 2;
+}
+
+static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id)
+{
+  // If message_id is zero then we should assign one, otherwise
+  // we'll use the one supplied by the caller
+  while (message_id == 0)
+    message_id = ++connection->message_id;
+
+  if (connection->message.length + 2 > connection->buffer_length)
+    return 0;
+
+  connection->buffer[connection->message.length++] = message_id >> 8;
+  connection->buffer[connection->message.length++] = message_id & 0xff;
+
+  return message_id;
+}
+
+static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection)
+{
+  connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
+  return MQTT_MAX_FIXED_HEADER_SIZE;
+}
+
+static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection)
+{
+  connection->message.data = connection->buffer;
+  connection->message.length = 0;
+  return &connection->message;
+}
+
+static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)
+{
+  int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
+
+  if (remaining_length > 127)
+  {
+    connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
+    connection->buffer[1] = 0x80 | (remaining_length % 128);
+    connection->buffer[2] = remaining_length / 128;
+    connection->message.length = remaining_length + 3;
+    connection->message.data = connection->buffer;
+  }
+  else
+  {
+    connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
+    connection->buffer[2] = remaining_length;
+    connection->message.length = remaining_length + 2;
+    connection->message.data = connection->buffer + 1;
+  }
+
+  return &connection->message;
+}
+
+void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
+{
+  memset(connection, 0, sizeof(mqtt_connection_t));
+  connection->buffer = buffer;
+  connection->buffer_length = buffer_length;
+}
+
+int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length)
+{
+  int i;
+  int totlen = 0;
+
+  for (i = 1; i < length; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
+    if ((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  return totlen;
+}
+
+const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
+{
+  int i;
+  int totlen = 0;
+  int topiclen;
+
+  for (i = 1; i < *length; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
+    if ((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  if (i + 2 >= *length)
+    return NULL;
+  topiclen = buffer[i++] << 8;
+  topiclen |= buffer[i++];
+
+  if (i + topiclen > *length)
+    return NULL;
+
+  *length = topiclen;
+  return (const char*)(buffer + i);
+}
+
+const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
+{
+  int i;
+  int totlen = 0;
+  int topiclen;
+  int blength = *length;
+  *length = 0;
+
+  for (i = 1; i < blength; ++i)
+  {
+    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
+    if ((buffer[i] & 0x80) == 0)
+    {
+      ++i;
+      break;
+    }
+  }
+  totlen += i;
+
+  if (i + 2 >= blength)
+    return NULL;
+  topiclen = buffer[i++] << 8;
+  topiclen |= buffer[i++];
+
+  if (i + topiclen >= blength)
+    return NULL;
+
+  i += topiclen;
+
+  if (mqtt_get_qos(buffer) > 0)
+  {
+    if (i + 2 >= blength)
+      return NULL;
+    i += 2;
+  }
+
+  if (totlen < i)
+    return NULL;
+
+  if (totlen <= blength)
+    *length = totlen - i;
+  else
+    *length = blength - i;
+  return (const char*)(buffer + i);
+}
+
+uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length)
+{
+  if (length < 1)
+    return 0;
+
+  switch (mqtt_get_type(buffer))
+  {
+    case MQTT_MSG_TYPE_PUBLISH:
+      {
+        int i;
+        int topiclen;
+
+        for (i = 1; i < length; ++i)
+        {
+          if ((buffer[i] & 0x80) == 0)
+          {
+            ++i;
+            break;
+          }
+        }
+
+        if (i + 2 >= length)
+          return 0;
+        topiclen = buffer[i++] << 8;
+        topiclen |= buffer[i++];
+
+        if (i + topiclen >= length)
+          return 0;
+        i += topiclen;
+
+        if (mqtt_get_qos(buffer) > 0)
+        {
+          if (i + 2 >= length)
+            return 0;
+          //i += 2;
+        } else {
+          return 0;
+        }
+
+        return (buffer[i] << 8) | buffer[i + 1];
+      }
+    case MQTT_MSG_TYPE_PUBACK:
+    case MQTT_MSG_TYPE_PUBREC:
+    case MQTT_MSG_TYPE_PUBREL:
+    case MQTT_MSG_TYPE_PUBCOMP:
+    case MQTT_MSG_TYPE_SUBACK:
+    case MQTT_MSG_TYPE_UNSUBACK:
+    case MQTT_MSG_TYPE_SUBSCRIBE:
+      {
+        // This requires the remaining length to be encoded in 1 byte,
+        // which it should be.
+        if (length >= 4 && (buffer[1] & 0x80) == 0)
+          return (buffer[2] << 8) | buffer[3];
+        else
+          return 0;
+      }
+
+    default:
+      return 0;
+  }
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)
+{
+  struct mqtt_connect_variable_header* variable_header;
+
+  init_message(connection);
+
+  if (connection->message.length + sizeof(*variable_header) > connection->buffer_length)
+    return fail_message(connection);
+  variable_header = (void*)(connection->buffer + connection->message.length);
+  connection->message.length += sizeof(*variable_header);
+
+  variable_header->lengthMsb = 0;
+#if defined(PROTOCOL_NAMEv31)
+  variable_header->lengthLsb = 6;
+  memcpy(variable_header->magic, "MQIsdp", 6);
+  variable_header->version = 3;
+#elif defined(PROTOCOL_NAMEv311)
+  variable_header->lengthLsb = 4;
+  memcpy(variable_header->magic, "MQTT", 4);
+  variable_header->version = 4;
+#else
+#error "Please define protocol name"
+#endif
+
+  variable_header->flags = 0;
+  variable_header->keepaliveMsb = info->keepalive >> 8;
+  variable_header->keepaliveLsb = info->keepalive & 0xff;
+
+  if (info->clean_session)
+    variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
+
+  if (info->client_id == NULL)
+  {
+    /* Never allowed */
+    return fail_message(connection);
+  }
+  else if (info->client_id[0] == '\0')
+  {
+#ifdef PROTOCOL_NAMEv311
+    /* Allowed. Format 0 Length ID */
+    append_string(connection, info->client_id, 2) ;
+#else
+    /* 0 Length not allowed */
+    return fail_message(connection);
+#endif
+  }
+  else
+  {
+    /* No 0 data and at least 1 long. Good to go. */
+    if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
+      return fail_message(connection);
+  }
+
+  if (info->will_topic != NULL && info->will_topic[0] != '\0')
+  {
+    if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
+      return fail_message(connection);
+
+    if (append_string(connection, info->will_message, strlen(info->will_message)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
+    if (info->will_retain)
+      variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
+    variable_header->flags |= (info->will_qos & 3) << 3;
+  }
+
+  if (info->username != NULL && info->username[0] != '\0')
+  {
+    if (append_string(connection, info->username, strlen(info->username)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
+  }
+
+  if (info->password != NULL && info->password[0] != '\0')
+  {
+    if (append_string(connection, info->password, strlen(info->password)) < 0)
+      return fail_message(connection);
+
+    variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
+  }
+
+  return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if (topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if (append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  if (qos > 0)
+  {
+    if ((*message_id = append_message_id(connection, 0)) == 0)
+      return fail_message(connection);
+  }
+  else
+    *message_id = 0;
+
+  if (connection->message.length + data_length > connection->buffer_length)
+    return fail_message(connection);
+  memcpy(connection->buffer + connection->message.length, data, data_length);
+  connection->message.length += data_length;
+
+  return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if (append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if (append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if (append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)
+{
+  init_message(connection);
+  if (append_message_id(connection, message_id) == 0)
+    return fail_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if (topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if ((*message_id = append_message_id(connection, 0)) == 0)
+    return fail_message(connection);
+
+  if (append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  if (connection->message.length + 1 > connection->buffer_length)
+    return fail_message(connection);
+  connection->buffer[connection->message.length++] = qos;
+
+  return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
+{
+  init_message(connection);
+
+  if (topic == NULL || topic[0] == '\0')
+    return fail_message(connection);
+
+  if ((*message_id = append_message_id(connection, 0)) == 0)
+    return fail_message(connection);
+
+  if (append_string(connection, topic, strlen(topic)) < 0)
+    return fail_message(connection);
+
+  return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
+}
+
+mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection)
+{
+  init_message(connection);
+  return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
+}

+ 129 - 0
mqtt/proto.c

@@ -0,0 +1,129 @@
+#include "proto.h"
+#include "ringbuf.h"
+I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize)
+{
+  parser->buf = buf;
+  parser->bufSize = bufSize;
+  parser->dataLen = 0;
+  parser->callback = completeCallback;
+  parser->isEsc = 0;
+  return 0;
+}
+
+I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value)
+{
+  switch (value) {
+    case 0x7D:
+      parser->isEsc = 1;
+      break;
+
+    case 0x7E:
+      parser->dataLen = 0;
+      parser->isEsc = 0;
+      parser->isBegin = 1;
+      break;
+
+    case 0x7F:
+      if (parser->callback != NULL)
+        parser->callback();
+      parser->isBegin = 0;
+      return 0;
+      break;
+
+    default:
+      if (parser->isBegin == 0) break;
+
+      if (parser->isEsc) {
+        value ^= 0x20;
+        parser->isEsc = 0;
+      }
+
+      if (parser->dataLen < parser->bufSize)
+        parser->buf[parser->dataLen++] = value;
+
+      break;
+  }
+  return -1;
+}
+
+I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len)
+{
+  while (len--)
+    PROTO_ParseByte(parser, *buf++);
+
+  return 0;
+}
+I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen)
+{
+  U8 c;
+
+  PROTO_PARSER proto;
+  PROTO_Init(&proto, NULL, bufOut, maxBufLen);
+  while (RINGBUF_Get(rb, &c) == 0) {
+    if (PROTO_ParseByte(&proto, c) == 0) {
+      *len = proto.dataLen;
+      return 0;
+    }
+  }
+  return -1;
+}
+I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize)
+{
+  U16 i = 2;
+  U16 len = *(U16*) packet;
+
+  if (bufSize < 1) return -1;
+
+  *buf++ = 0x7E;
+  bufSize--;
+
+  while (len--) {
+    switch (*packet) {
+      case 0x7D:
+      case 0x7E:
+      case 0x7F:
+        if (bufSize < 2) return -1;
+        *buf++ = 0x7D;
+        *buf++ = *packet++ ^ 0x20;
+        i += 2;
+        bufSize -= 2;
+        break;
+      default:
+        if (bufSize < 1) return -1;
+        *buf++ = *packet++;
+        i++;
+        bufSize--;
+        break;
+    }
+  }
+
+  if (bufSize < 1) return -1;
+  *buf++ = 0x7F;
+
+  return i;
+}
+
+I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len)
+{
+  U16 i = 2;
+  if (RINGBUF_Put(rb, 0x7E) == -1) return -1;
+  while (len--) {
+    switch (*packet) {
+      case 0x7D:
+      case 0x7E:
+      case 0x7F:
+        if (RINGBUF_Put(rb, 0x7D) == -1) return -1;
+        if (RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
+        i += 2;
+        break;
+      default:
+        if (RINGBUF_Put(rb, *packet++) == -1) return -1;
+        i++;
+        break;
+    }
+  }
+  if (RINGBUF_Put(rb, 0x7F) == -1) return -1;
+
+  return i;
+}
+

+ 75 - 0
mqtt/queue.c

@@ -0,0 +1,75 @@
+/* str_queue.c
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "queue.h"
+
+#include "user_interface.h"
+#include "osapi.h"
+#include "os_type.h"
+#include "mem.h"
+#include "proto.h"
+
+uint8_t *last_rb_p_r;
+uint8_t *last_rb_p_w;
+uint32_t last_fill_cnt;
+
+void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize)
+{
+  queue->buf = (uint8_t*)os_zalloc(bufferSize);
+  RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
+}
+int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len)
+{
+  uint32_t ret;
+  
+  last_rb_p_r = queue->rb.p_r;
+  last_rb_p_w = queue->rb.p_w;
+  last_fill_cnt = queue->rb.fill_cnt;
+
+  ret = PROTO_AddRb(&queue->rb, buffer, len);
+  if (ret == -1) {
+    // rolling ring buffer back
+    queue->rb.p_r = last_rb_p_r;
+    queue->rb.p_w = last_rb_p_w;
+    queue->rb.fill_cnt = last_fill_cnt;
+  }
+  return ret;
+}
+int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen)
+{
+
+  return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
+}
+
+BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue)
+{
+  if (queue->rb.fill_cnt <= 0)
+    return TRUE;
+  return FALSE;
+}

+ 67 - 0
mqtt/ringbuf.c

@@ -0,0 +1,67 @@
+/**
+* \file
+*   Ring Buffer library
+*/
+
+#include "ringbuf.h"
+
+
+/**
+* \brief init a RINGBUF object
+* \param r pointer to a RINGBUF object
+* \param buf pointer to a byte array
+* \param size size of buf
+* \return 0 if successfull, otherwise failed
+*/
+I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size)
+{
+  if (r == NULL || buf == NULL || size < 2) return -1;
+
+  r->p_o = r->p_r = r->p_w = buf;
+  r->fill_cnt = 0;
+  r->size = size;
+
+  return 0;
+}
+/**
+* \brief put a character into ring buffer
+* \param r pointer to a ringbuf object
+* \param c character to be put
+* \return 0 if successfull, otherwise failed
+*/
+I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c)
+{
+  if (r->fill_cnt >= r->size)return -1; // ring buffer is full, this should be atomic operation
+
+
+  r->fill_cnt++;              // increase filled slots count, this should be atomic operation
+
+
+  *r->p_w++ = c;              // put character into buffer
+
+  if (r->p_w >= r->p_o + r->size)     // rollback if write pointer go pass
+    r->p_w = r->p_o;          // the physical boundary
+
+  return 0;
+}
+/**
+* \brief get a character from ring buffer
+* \param r pointer to a ringbuf object
+* \param c read character
+* \return 0 if successfull, otherwise failed
+*/
+I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c)
+{
+  if (r->fill_cnt <= 0)return -1;     // ring buffer is empty, this should be atomic operation
+
+
+  r->fill_cnt--;                // decrease filled slots count
+
+
+  *c = *r->p_r++;               // get the character out
+
+  if (r->p_r >= r->p_o + r->size)       // rollback if write pointer go pass
+    r->p_r = r->p_o;            // the physical boundary
+
+  return 0;
+}

+ 149 - 0
mqtt/utils.c

@@ -0,0 +1,149 @@
+/*
+* Copyright (c) 2014, Tuan PM
+* Email: tuanpm@live.com
+*
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <stddef.h>
+#include "utils.h"
+
+
+uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str)
+{
+  uint8_t segs = 0;   /* Segment count. */
+  uint8_t chcnt = 0;  /* Character count within segment. */
+  uint8_t accum = 0;  /* Accumulator for segment. */
+  /* Catch NULL pointer. */
+  if (str == 0)
+    return 0;
+  /* Process every character in string. */
+
+  while (*str != '\0') {
+    /* Segment changeover. */
+
+    if (*str == '.') {
+      /* Must have some digits in segment. */
+      if (chcnt == 0)
+        return 0;
+      /* Limit number of segments. */
+      if (++segs == 4)
+        return 0;
+      /* Reset segment values and restart loop. */
+      chcnt = accum = 0;
+      str++;
+      continue;
+    }
+
+    /* Check numeric. */
+    if ((*str < '0') || (*str > '9'))
+      return 0;
+
+    /* Accumulate and check segment. */
+
+    if ((accum = accum * 10 + *str - '0') > 255)
+      return 0;
+    /* Advance other segment specific stuff and continue loop. */
+
+    chcnt++;
+    str++;
+  }
+
+  /* Check enough segments and enough characters in last segment. */
+
+  if (segs != 3)
+    return 0;
+  if (chcnt == 0)
+    return 0;
+  /* Address okay. */
+
+  return 1;
+}
+uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip)
+{
+
+  /* The count of the number of bytes processed. */
+  int i;
+  /* A pointer to the next digit to process. */
+  const char * start;
+
+  start = str;
+  for (i = 0; i < 4; i++) {
+    /* The digit being processed. */
+    char c;
+    /* The value of this byte. */
+    int n = 0;
+    while (1) {
+      c = * start;
+      start++;
+      if (c >= '0' && c <= '9') {
+        n *= 10;
+        n += c - '0';
+      }
+      /* We insist on stopping at "." if we are still parsing
+         the first, second, or third numbers. If we have reached
+         the end of the numbers, we will allow any character. */
+      else if ((i < 3 && c == '.') || i == 3) {
+        break;
+      }
+      else {
+        return 0;
+      }
+    }
+    if (n >= 256) {
+      return 0;
+    }
+    ((uint8_t*)ip)[i] = n;
+  }
+  return 1;
+
+}
+uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s)
+{
+  uint32_t value = 0, digit;
+  int8_t c;
+
+  while ((c = *s++)) {
+    if ('0' <= c && c <= '9')
+      digit = c - '0';
+    else if ('A' <= c && c <= 'F')
+      digit = c - 'A' + 10;
+    else if ('a' <= c && c <= 'f')
+      digit = c - 'a' + 10;
+    else break;
+
+    value = (value << 4) | digit;
+  }
+
+  return value;
+}
+

+ 44 - 0
user/Makefile

@@ -0,0 +1,44 @@
+
+#############################################################
+# 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 += 
+
+#############################################################
+# 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
+INCLUDES += -I ./
+PDIR := ../$(PDIR)
+sinclude $(PDIR)Makefile
+

+ 76 - 0
user/rfinit.c

@@ -0,0 +1,76 @@
+/******************************************************************************
+ * Copyright 2016 Vowstar
+ *
+ * FileName: init.c
+ *
+ * Description: System and user APP initialization.
+ *
+ * Modification history:
+ *     2016/03/24, v1.0 create this file.
+*******************************************************************************/
+
+#include "ets_sys.h"
+#include "osapi.h"
+#include "user_interface.h"
+
+/******************************************************************************
+* FunctionName : user_rf_cal_sector_set
+* Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
+*                We add this function to force users to set rf cal sector, since
+*                we don't know which sector is free in user's application.
+*                sector map for last several sectors : ABCCC
+*                A : rf cal
+*                B : rf init data
+*                C : sdk parameters
+* Parameters   : none
+* Returns      : rf cal sector
+*******************************************************************************/
+uint32 ICACHE_FLASH_ATTR __attribute__((weak))
+user_rf_cal_sector_set(void)
+{
+  enum flash_size_map size_map = system_get_flash_size_map();
+  uint32 rf_cal_sec = 0;
+
+  switch (size_map) {
+    case FLASH_SIZE_4M_MAP_256_256:
+      rf_cal_sec = 128 - 5;
+      break;
+
+    case FLASH_SIZE_8M_MAP_512_512:
+      rf_cal_sec = 256 - 5;
+      break;
+
+    case FLASH_SIZE_16M_MAP_512_512:
+    case FLASH_SIZE_16M_MAP_1024_1024:
+      rf_cal_sec = 512 - 5;
+      break;
+
+    case FLASH_SIZE_32M_MAP_512_512:
+    case FLASH_SIZE_32M_MAP_1024_1024:
+      rf_cal_sec = 1024 - 5;
+      break;
+
+    default:
+      rf_cal_sec = 0;
+      break;
+  }
+
+  return rf_cal_sec;
+}
+
+void __attribute__((weak))
+user_rf_pre_init(void)
+{
+  // Warning: IF YOU DON'T KNOW WHAT YOU ARE DOING, DON'T TOUCH THESE CODE
+
+  // Control RF_CAL by esp_init_data_default.bin(0~127byte) 108 byte when wakeup
+  // Will low current
+  // system_phy_set_rfoption(0);
+
+  // Process RF_CAL when wakeup.
+  // Will high current
+  system_phy_set_rfoption(1);
+
+  // Set Wi-Fi Tx Power, Unit: 0.25dBm, Range: [0, 82]
+  system_phy_set_max_tpw(82);
+}

+ 112 - 0
user/user_main.c

@@ -0,0 +1,112 @@
+/* main.c -- MQTT client example
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "esp_common.h"
+#include "driver/uart.h"
+#include "driver/spi_interface.h"
+#include "gpio.h"
+
+#include "log/esp_log.h"
+#include "gdbstub/gdbstub.h"
+
+#include "hal/lsm6ds3.h"
+#include "hal/max17043.h"
+#include "hal/lps25hb.h"
+
+#include "user_config.h"
+
+static const char* TAG = "main.c";
+
+void wifi_handle_event_cb(System_Event_t *evt)
+{
+    switch(evt->event)
+    {
+      case EVENT_STAMODE_CONNECTED:
+        break;
+      case EVENT_STAMODE_DISCONNECTED:
+        break;
+      case EVENT_STAMODE_AUTHMODE_CHANGE:
+        break;
+      case EVENT_STAMODE_GOT_IP:
+        break;
+      case EVENT_SOFTAPMODE_PROBEREQRECVED:
+        break;
+      case EVENT_SOFTAPMODE_STACONNECTED:
+        break;
+      case EVENT_SOFTAPMODE_STADISCONNECTED:
+        break;
+      default:
+        break;
+    }
+}
+
+ void ICACHE_FLASH_ATTR app_init(void)
+{
+    uart_init(BIT_RATE_115200, BIT_RATE_115200);
+    ESP_LOGI(TAG, "Starting LSM6DS3 Demo\n");
+
+
+    while(true)
+    {
+        LSM6DS3_Enable_I2C_Bridge(1);
+        uint16_t x = max17043_getVoltage();
+        ESP_LOGI(TAG, "MAX17043 Voltage %d", x);
+        uint8_t y;
+        LPS25HB_Get_DeviceID(&y);
+        ESP_LOGI(TAG, "DEVICEID %x", y);
+        // uint8_t i;
+        // for(i=0;i<8;i++)
+        //     ESP_LOGI(TAG, "RX SPI Value: %x", data[i]);
+        os_delay_us(1000000);
+        system_soft_wdt_feed();
+    }
+
+
+
+  // wifi_set_opmode(STATION_MODE);
+  // wifi_station_ap_number_set(MAX_APS);
+  // wifi_station_set_auto_connect(true);
+  //
+  // wifi_station_get_ap_info()
+  // wifi_station_ap_change()
+  // wifi_staiton_get_current_ap_id()
+  // wifi_set_sleep_type(MODEM_SLEEP_T);
+  // wifi_enable_gpio_wakeup()
+  //
+  // if (wifi_station_get_config())
+  //   os_printf("zero wifi_config\n");
+  // else
+  //   os_printf("there is a stored config");
+}
+
+void user_init(void)
+{
+  system_init_done_cb(app_init);
+}

+ 140 - 0
util/config.c

@@ -0,0 +1,140 @@
+/******************************************************************************
+ * 2016 ideasX (Tyler Berezowsky)
+ *
+ * FileName: config.c
+ *
+ * Description: This file is going to need alot of help by a C wizard, but it currently works...I think.
+ *
+ *     2016/8/8, v1.0 created this file
+*******************************************************************************
+*
+* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* * Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Redis nor the names of its contributors may be used
+* to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "ets_sys.h"
+#include "os_type.h"
+#include "mem.h"
+#include "osapi.h"
+#include "user_interface.h"
+
+#include "mqtt/mqtt.h"
+#include "modules/config.h"
+#include "user_config.h"
+#include "driver/uart.h"
+
+/* CFG_LOCATION: 0x2
+ * (CFG_LOCATION + 0)*0x1000 = 0x2000
+ * (CFG_LOCATION + 1)*0x1000 = 0x3000
+ * (CFG_LOCATION + 2)*0x1000 = 0x4000
+ * (CFG_LOCATOIN + 3)*0x1000 = 0x5000
+ *
+ */
+
+
+
+SYSCFG sysCfg;
+SAVE_FLAG saveFlag;
+MQTT_TOPICS mqttTopics;
+
+void ICACHE_FLASH_ATTR cfg_save()
+{
+    #if CONFIG_DEBUG
+    uart0_sendStr("Writing New Default Module Configuration\r\n");
+    #endif
+    spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,		    // read config sector 3 for
+                       (uint32 *)&saveFlag, sizeof(SAVE_FLAG));		// saveFlag
+
+    if (saveFlag.flag == 0) {
+    spi_flash_erase_sector(CFG_LOCATION + 1); 					// erase config sector 1
+    spi_flash_write((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,	// write sysCfg in config sector 1
+    (uint32 *)&sysCfg, sizeof(SYSCFG));
+    saveFlag.flag = 1;											// set saveFlag.flag
+    spi_flash_erase_sector(CFG_LOCATION + 3);					// erase config sector 3
+    spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,	// write saveFlag to config sector 3
+    (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
+    }
+    else {
+    spi_flash_erase_sector(CFG_LOCATION + 0);					// erase config sector 0 for sysCfg
+    spi_flash_write((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,			// write sysCfg to config sector 0
+    (uint32 *)&sysCfg, sizeof(SYSCFG));
+    saveFlag.flag = 0;								// clear saveFlag.flag
+    spi_flash_erase_sector(CFG_LOCATION + 3);					// erase config sector 3
+    spi_flash_write((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,			// write saveFlag to config sector 3
+    (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
+    }
+}
+
+void ICACHE_FLASH_ATTR cfg_load()
+{
+    #if CONFIG_DEBUG
+    uart0_sendStr("Loading Default Module Configuration...\r\n");
+    #endif
+    spi_flash_read((CFG_LOCATION + 3) * SPI_FLASH_SEC_SIZE,			// read save Flag to config sector 3
+       (uint32 *)&saveFlag, sizeof(SAVE_FLAG));
+    if (saveFlag.flag == 0) {						// if saveFlag.flag == 0
+    spi_flash_read((CFG_LOCATION + 0) * SPI_FLASH_SEC_SIZE,		// write sysCfg to config sector 0
+       (uint32 *)&sysCfg, sizeof(SYSCFG));
+    } else {								// if saveFlag.flag == 1
+    spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE,		// write sysCfg to config sector 1
+       (uint32 *)&sysCfg, sizeof(SYSCFG));
+    }
+    if(sysCfg.cfg_holder != CFG_HOLDER){			// if sysCfg doesn't contain the proper check value
+    os_memset(&sysCfg, 0x00, sizeof sysCfg);	// clear sysCfg
+
+
+    sysCfg.cfg_holder = CFG_HOLDER;
+
+    os_sprintf(sysCfg.sta_ssid[0], "%s", STA_SSID);				// load STA_SSID into sysCfg
+    os_sprintf(sysCfg.sta_pwd[0], "%s", STA_PASS);				// load STA_PASS into sysCfg
+    sysCfg.sta_type[0] = STA_TYPE;								// load STA_TYPE into sysCfg
+    sysCfg.registered_stations = 1;
+    sysCfg.current_station = 0;
+
+    wifi_get_macaddr(STATION_IF, sysCfg.device_id);
+    os_sprintf(sysCfg.mqtt_host, "%s", MQTT_HOST);							// load MQTT_HOST
+    sysCfg.mqtt_port = MQTT_PORT;											// load MQTT_PORT
+    os_sprintf(sysCfg.mqtt_user, "%s", MQTT_USER);							// load MQTT_USER
+    os_sprintf(sysCfg.mqtt_pass, "%s", MQTT_PASS);							// load MQTT_PASS
+
+    sysCfg.security = DEFAULT_SECURITY;										/* default non ssl */
+    sysCfg.mqtt_keepalive = MQTT_KEEPALIVE;									// load MQTT_KEEPALIVE
+
+    os_sprintf(sysCfg.ota_host, "%s", OTA_HOST);
+    sysCfg.ota_port = OTA_PORT;
+
+    cfg_save();
+    }
+
+    sysCfg.module_state.all_flags = 0U; 					// clear all flags
+    sysCfg.uart_state = 0;
+    sysCfg.module_state.alive = true;
+
+    os_sprintf(mqttTopics.data, "/encoder/" MACSTR "/data", MAC2STR(sysCfg.device_id));
+    os_sprintf(mqttTopics.command, "/encoder/" MACSTR "/command", MAC2STR(sysCfg.device_id));
+    os_sprintf(mqttTopics.health, "/encoder/" MACSTR "/health", MAC2STR(sysCfg.device_id));
+
+}

+ 485 - 0
util/wifi.c

@@ -0,0 +1,485 @@
+/******************************************************************************
+ * 2016 IdeasX v0.3.1 Module Firmware
+ *
+ * File Name: wifi.c
+ * Author: Tyler Berezowsky
+ * Description: This file is going to need alot of help by a C wizard, but it currently works...I think.
+ *
+ *     2016/8/8, v1.0 created this file
+*******************************************************************************/
+#include "util/wifi.h"
+#include "esp_common.h"
+
+#define WIFI_TIMEOUT 30*1000 		// time waited before swiping left in seconds
+#define WIFI_RECONNECT_LIMIT 5		// number of times connection to AP is attempted before moving on
+
+MQTT_Client mqttClient;	//  setup in user_main.c
+
+static struct station_config stationConf;
+static WIFI_PROCESS_FLAGS wifi_process_flags;
+static ETSTimer wifi_process_timer;
+static struct bss_info  *bss_link, *head_bss_link;
+
+static void ICACHE_FLASH_ATTR wifi_process(void);
+static void ICACHE_FLASH_ATTR wifi_process_timer_cb(void);
+
+
+/******************************************************************************
+ * FunctionName : destory_linked_list
+ * Description  :
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static bool ICACHE_FLASH_ATTR destory_linked_list(void)
+{
+	if(head_bss_link != NULL)
+	{
+		while(head_bss_link != NULL)
+		{
+			bss_link = head_bss_link;
+			head_bss_link = head_bss_link->next.stqe_next;
+			os_free(bss_link);
+		}
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+/******************************************************************************
+ * FunctionName : copy_linked_list
+ * Description  :
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static struct bss_info* ICACHE_FLASH_ATTR copy_linked_list(struct bss_info *ptr_original_node)
+{
+	struct bss_info *ptr_new_head, *ptr_new_node;
+
+	if(ptr_original_node != NULL)
+	{
+		ptr_new_head = (struct bss_info *)os_malloc(sizeof(struct bss_info));
+		if (ptr_new_head == NULL)
+		{
+			os_printf("WIFI PROCESS: No RAM!\r\n");
+			return NULL;
+		}
+	}
+	else
+		return NULL;
+
+	os_memcpy(ptr_new_head, ptr_original_node, sizeof(struct bss_info));
+	ptr_original_node = ptr_original_node->next.stqe_next;
+
+	ptr_new_node = ptr_new_head;
+
+	while(ptr_original_node != NULL)
+	{
+		ptr_new_node->next.stqe_next = (struct bss_info *)os_malloc(sizeof(struct bss_info));
+		ptr_new_node = ptr_new_node->next.stqe_next;
+		os_memcpy(ptr_new_node, ptr_original_node, sizeof(struct bss_info));
+		if (ptr_new_node == NULL)
+		{
+			os_printf("WIFI PROCESS: No RAM!\r\n");
+			while(ptr_new_head != NULL)
+			{
+				ptr_new_node = ptr_new_head;
+				ptr_new_head = ptr_new_head->next.stqe_next;
+				os_free(ptr_new_node);
+			}
+			os_printf("WIFI PROCESS: Cleaned up list\r\n");
+			return NULL;
+		}
+		ptr_original_node = ptr_original_node->next.stqe_next;
+
+	}
+	return ptr_new_head;
+}
+/******************************************************************************
+ * FunctionName : wifi_set_station
+ * Description  :
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR wifi_set_station(uint8_t* ssid, uint8_t* pass)
+{
+	bss_link = NULL;
+
+	os_sprintf(stationConf.ssid, "%s", ssid);			// load ssid into stationConf.ssid
+	os_sprintf(stationConf.password, "%s", pass);		// load pass into stationConf.password
+
+	wifi_station_set_config_current(&stationConf);				// connect to AP specified in stationConf
+	wifi_station_set_auto_connect(TRUE);
+	wifi_station_connect();
+}
+/******************************************************************************
+ * FunctionName : disable_wifi_reconnect
+ * Description  :
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR disable_wifi_reconnect(void)
+{
+	wifi_station_disconnect();
+	wifi_station_set_auto_connect(FALSE);
+}
+/******************************************************************************
+ * FunctionName : show_wifi_config
+ * Description  : print current wifi configurations
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR show_wifi_config(void)
+{
+	uint8_t i, j;
+	j = sysCfg.registered_stations;
+
+	os_printf("Number of APs stored: %d\r\n", j);
+	for (i=0;i<j;i++)
+		os_printf("AP: %d\n\tSSID: %s\n\tPASS: %s\n", i, sysCfg.sta_ssid[i], sysCfg.sta_pwd[i]);
+	/* This is not accurate. If the module is not connected to an AP it should display unconnected for
+		current station
+	*/
+	i = sysCfg.current_station;
+	j = wifi_station_get_connect_status();
+	os_printf("Current AP: %d\r\nWiFi Status %d\r\n", i, j);
+}
+/******************************************************************************
+ * FunctionName : wifi_process_timer_cb
+ * Description  :
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static void ICACHE_FLASH_ATTR wifi_process_timer_cb()
+{
+	os_printf("WIFI PROCESS: Wi-Fi connection timed out.\r\n");
+	wifi_process_flags.wifi_flag = FALSE;
+
+
+	wifi_station_set_auto_connect(FALSE);
+	wifi_station_disconnect();
+	wifi_process();
+}
+/******************************************************************************
+ * FunctionName : wifi_process
+ * Description  : Looks for AP stored in bss_link
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static void ICACHE_FLASH_ATTR wifi_process(void)
+{
+	uint8_t ssid[33];
+	uint8_t i;
+
+	os_timer_disarm(&wifi_process_timer);								// disarm timeout timer
+
+	if ((wifi_process_flags.wifi_flag == FALSE) && (bss_link != NULL)) // if AP connection failed and bss_link is not empty
+	{
+		while(bss_link != NULL)	// do this until bss_link is empty or break
+		{
+
+			// ssid could be missing null character
+			os_memset(ssid, 0, 33);
+			if (os_strlen(bss_link->ssid) <= 32)
+			{
+				os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
+			}
+			else
+			{
+				os_memcpy(ssid, bss_link->ssid, 32);
+			}
+
+			// compare current ssid from bss_link to registered stations
+			for(i=0;i<sysCfg.registered_stations;i++)
+			{
+				//os_printf("Comparing %s and %s\r\n", ssid, sysCfg.sta_ssid[i]);
+				if (!strcmp(ssid, sysCfg.sta_ssid[i]))
+				{
+					wifi_process_flags.wifi_flag = TRUE; 	// set connect attempt flag
+					wifi_process_flags.wifi_count = 0; 		// rst connect attempt count
+
+					os_sprintf(stationConf.ssid, "%s", sysCfg.sta_ssid[i]);
+					os_sprintf(stationConf.password, "%s", sysCfg.sta_pwd[i]);	// if AUTH_OPEN pwd should be NULL
+					sysCfg.current_station = i;									// store current station number for sysCfg save and UART operations
+					wifi_station_set_config_current(&stationConf); 				// load stationConf into SDK, but don't save in SDK flash
+					wifi_station_set_auto_connect(TRUE);
+					wifi_station_connect();
+
+					bss_link = bss_link->next.stqe_next; 						// inc to next station in case process fails
+
+					//set wifi_process_timer for timeout.
+					os_timer_setfn(&wifi_process_timer, (os_timer_func_t *)wifi_process_timer_cb, NULL);
+					os_timer_arm(&wifi_process_timer, WIFI_TIMEOUT, 0); 		// arm timeout timer
+					break; // break for loop
+				}
+
+			}
+
+			// break while if station found, otherwise look for another station.
+			if (wifi_process_flags.wifi_flag == TRUE)
+			{
+				break;	// break while loop
+			}
+			else
+			{
+				bss_link = bss_link->next.stqe_next;
+			}
+		}
+
+	}
+	if ((wifi_process_flags.wifi_flag == FALSE) && (bss_link == NULL))
+	{
+		// this is called twice...which could be a problem.
+		sysCfg.module_state.searching = FALSE;
+		sysCfg.module_state.asleep = FALSE;
+		destory_linked_list();
+		os_printf("WIFI PROCESS: Station list removed\r\n");
+		os_printf("WIFI PROCESS: No Wi-Fi APs available.\r\n");
+		// try again in a second....three times...if motion flag is set keep trying otherwise you should goto sleep.
+
+		if (lsm6ds3_read_motion())		// change this to a poll on the LSM6DS3 line.
+			start_wifi_process();
+		else
+		{
+			GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 0xFFFFFFFF);	// clear pending interrupts
+			sysCfg.module_state.asleep = TRUE;
+			ETS_GPIO_INTR_ENABLE(); 								// enable interrupts to permit PB and LSM6DS3 to wake ESP from sleep.
+			/*
+
+			 *	The ESP8266 should be placed into light sleep or modem sleep here
+
+			 */
+		}
+	}
+
+}
+/******************************************************************************
+ * FunctionName : wifi_handle_event_cb
+ * Description  : callback function for wifi events.
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static void ICACHE_FLASH_ATTR wifi_handle_event_cb(System_Event_t *evt)
+{
+	switch (evt->event)
+ 	{
+		case EVENT_STAMODE_CONNECTED:
+		{
+			wifi_process_flags.wifi_count = 0;	// rst wifi connection cnt
+
+			os_printf("WIFI PROCESS: connect to ssid %s, channel %d\n",
+			evt->event_info.connected.ssid,
+			evt->event_info.connected.channel);
+			break;
+		}
+		case EVENT_STAMODE_DISCONNECTED:
+		{
+			/*
+				There is an issue where if the module is connected to an AP and then loses it, it continously scans for the
+				last access point it attempted to connect to.
+			*/
+			sysCfg.module_state.connected = FALSE;	// set global connected flag false
+			sysCfg.module_state.searching = TRUE;
+			/*
+				The only way to cancel the auto-connect functionaity of the SDK's OS is to
+				send the command wifi_station_disconnect(), this ALWAYS calles the wifi event
+				handler. Checking for this flag lets us ignore it.
+			*/
+			if (wifi_process_flags.wifi_flag == TRUE)
+			{
+				MQTT_Disconnect(&mqttClient);
+				wifi_process_flags.wifi_count++;
+
+				os_printf("WIFI PROCESS: disconnect from ssid %s, reason %d, attempt %d/%d\r\n",
+				evt->event_info.disconnected.ssid,
+				evt->event_info.disconnected.reason,
+				wifi_process_flags.wifi_count,
+				WIFI_RECONNECT_LIMIT);
+
+				if (wifi_process_flags.wifi_count >= WIFI_RECONNECT_LIMIT)	// allow WIFI_RECONNECT_LIMIT for reconnect and 1st attempts
+				{
+					if (wifi_process_flags.ip_flag == TRUE)	// if was connected, but then lost connection
+					{
+						start_wifi_process();				// rst apd mode process, flags will automatically be reset
+					}
+					else									// if never got a connection finish looking at all the available stations.
+					{
+						wifi_process_flags.wifi_flag = FALSE;
+						wifi_station_set_auto_connect(FALSE);
+						wifi_station_disconnect();
+						wifi_process();
+					}
+				}
+			}
+			break;
+		}
+		case EVENT_STAMODE_AUTHMODE_CHANGE:
+		{
+			os_printf("WIFI PROCESS: mode: %d -> %d\n",
+			evt->event_info.auth_change.old_mode,
+			evt->event_info.auth_change.new_mode);
+			break;
+		}
+		case EVENT_STAMODE_GOT_IP:
+		{
+			os_timer_disarm(&wifi_process_timer);								// disarm timeout timer
+			wifi_process_flags.ip_flag = TRUE;
+
+			sysCfg.module_state.connected = TRUE;								// set global connected flag
+			sysCfg.module_state.searching = FALSE;								// set global searching flag false
+
+			os_printf("WIFI PROCESS: ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR,
+			IP2STR(&evt->event_info.got_ip.ip),
+			IP2STR(&evt->event_info.got_ip.mask),
+			IP2STR(&evt->event_info.got_ip.gw));
+
+			destory_linked_list();
+			os_printf("\r\nWIFI PROCESS: Station list removed\r\n");
+
+			lsm6ds3_motion_disable(); 											// disable LSM6DS3 significant motion functionality
+			MQTT_Connect(&mqttClient); 											// start MQTT client
+
+			break;
+		}
+		default:
+		{
+			os_printf("WIFI PROCESS: Oh, crap. I have no idea what is going on,\r\n");
+			break;
+		}
+	}
+}
+/******************************************************************************
+ * FunctionName : wifi_station_scan_done
+ * Description  : Cb function of scan, organizes a linked list of stations
+ 	from scan function. Make sure to free linked list when done.
+ * Parameters   :
+ * Returns      :
+*******************************************************************************/
+static void ICACHE_FLASH_ATTR wifi_station_scan_done(void *arg, STATUS status)
+{
+
+ 	uint8_t ssid[33];
+ 	uint8_t bssid[6];
+
+ 	if (status == OK)	// if the scan was sucessful
+ 	{
+    	bss_link = (struct bss_info *)arg;
+    	struct bss_info *bss_link_next, *bss_link_curr, *bss_link_prev, *bss_link_head;
+    	uint32_t i,numAP,j;
+
+    	bss_link = copy_linked_list(bss_link);	// SDK provived linked list will be destroyed automatically
+
+    	bss_link_head = bss_link;				// store head for traversing list
+
+		// get len of linked list
+		numAP=0;
+		while(bss_link != NULL) {
+			numAP++;
+			bss_link = bss_link->next.stqe_next;
+		}
+		os_printf("Number of APs found: %d\r\n", numAP);
+
+    	bss_link = bss_link_head;	// reset to head
+
+    	// sort linked list by rssi
+    	for(i=0;i<numAP-1;i++)
+    	{
+
+	    	bss_link_prev = NULL;
+	    	bss_link_curr = bss_link;
+	    	bss_link_next = bss_link->next.stqe_next;
+
+	 		for(j=0; j<numAP-1-i; j++)
+	 		{
+	 			system_soft_wdt_feed(); 												// reset sw watchdog timer
+				if (bss_link_next->rssi > bss_link_curr->rssi) {
+					if (bss_link_prev == NULL) {
+						// swap node position and head position
+						bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next;
+						bss_link_next->next.stqe_next = bss_link_curr;
+						bss_link = bss_link_next; // store new head
+
+						bss_link_prev = bss_link_next;
+						bss_link_next = bss_link_curr->next.stqe_next;
+					} else {
+						// swap node positions
+						bss_link_prev->next.stqe_next = bss_link_next;
+						bss_link_curr->next.stqe_next = bss_link_next->next.stqe_next; // could be null
+						bss_link_next->next.stqe_next = bss_link_curr;
+
+						bss_link_prev = bss_link_next;
+						bss_link_next = bss_link_curr->next.stqe_next;
+					}
+				} else {
+					// move along like nothing happened
+					bss_link_prev = bss_link_curr;
+					bss_link_curr = bss_link_next;
+					bss_link_next = bss_link_next->next.stqe_next;
+				}
+			}
+		}
+
+		bss_link_head = bss_link; // store head
+
+		// print sorted list of stations
+    	while (bss_link != NULL) {
+      		os_memset(ssid, 0, 33);
+      		os_memset(bssid, 0, 6);
+
+      		if (os_strlen(bss_link->ssid) <= 32) {
+        		os_memcpy(ssid, bss_link->ssid, os_strlen(bss_link->ssid));
+      		} else {
+        		os_memcpy(ssid, bss_link->ssid, 32);
+      		}
+
+      		os_printf("WiFi Scan: (%d,\"%s\",%x, %d)\n", bss_link->authmode, ssid, bssid, bss_link->rssi);
+      		bss_link = bss_link->next.stqe_next;
+  		}
+  		bss_link = bss_link_head;		// reset to head
+  		head_bss_link = bss_link_head;	// ahhh, this is lazy.
+
+  		os_printf("Activating event handler\r\n");
+		wifi_set_event_handler_cb(wifi_handle_event_cb);
+  		os_printf("Analysis scan results\r\n");
+  		wifi_process();
+  	}
+  	else // if scan was unsuccessful
+  	{
+  		sysCfg.module_state.searching = FALSE;
+  		os_printf("Scan Failed\r\n");
+  		GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 0xFFFFFFFF);	// clear pending interrupts
+		sysCfg.module_state.asleep = TRUE;
+		ETS_GPIO_INTR_ENABLE(); 								// enable interrupts to permit PB and LSM6DS3 to wake ESP from sleep.
+
+  	}
+}
+/******************************************************************************
+ * FunctionName : start_wifi_process
+ * Description  : scans for available AP and attempts to connect to the AP with
+ 	the highest RSSI.
+ * Parameters   :  restart - resets wifi_process_count
+ * Returns      :
+*******************************************************************************/
+void ICACHE_FLASH_ATTR start_wifi_process(void)
+{
+
+	ETS_GPIO_INTR_DISABLE(); 					// disable I/O interrupts
+	lsm6ds3_motion_enable();					// enable LSM6DS3 Significant Motion Process
+
+	wifi_process_flags.process_count = 0;
+	wifi_process_flags.wifi_flag = FALSE; 		// clear wifi_process_flags
+	wifi_process_flags.ip_flag = FALSE;
+	wifi_process_flags.wifi_count = 0;
+
+	sysCfg.module_state.searching = TRUE;		// setup global flags for searching
+	sysCfg.module_state.connected = FALSE;
+	sysCfg.module_state.broker = FALSE;
+
+	wifi_station_set_auto_connect(FALSE);	// disable wifi auto connect
+	wifi_station_ap_number_set(0);			// don't store Wi-Fi configurations in SDK flash
+
+	os_printf("Start Wi-Fi Scan\r\n");
+	wifi_set_opmode(STATION_MODE);
+	wifi_station_scan(NULL, wifi_station_scan_done);				// start Wi-Fi scan.
+}