├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── driver ├── Makefile └── uart.c ├── include ├── driver │ ├── uart.h │ └── uart_register.h └── user_config.h ├── modules ├── Makefile ├── cmd.c ├── crc16.c ├── include │ ├── cmd.h │ ├── crc16.h │ ├── rest.h │ └── wifi.h ├── mqtt_app.c ├── mqtt_app.h ├── rest.c └── wifi.c ├── tools ├── .gitattributes ├── esptool.py ├── makefile.sh └── xxd.exe └── user ├── Makefile └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | .cproject 2 | .project 3 | build/ 4 | firmware/ 5 | .settings/ 6 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/mqtt"] 2 | path = modules/mqtt 3 | url = https://github.com/tuanpmt/esp_mqtt 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Tuan PM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Changelog 2 | # Changed the variables to include the header file directory 3 | # Added global var for the XTENSA tool root 4 | # 5 | # This make file still needs some work. 6 | # 7 | # 8 | # Output directors to store intermediate compiled files 9 | # relative to the project directory 10 | BUILD_BASE = build 11 | FW_BASE = firmware 12 | ESPTOOL = tools/esptool.py 13 | 14 | 15 | # name for the target project 16 | TARGET = app 17 | 18 | # linker script used for the above linkier step 19 | LD_SCRIPT = eagle.app.v6.ld 20 | 21 | # we create two different files for uploading into the flash 22 | # these are the names and options to generate them 23 | FW_1 = 0x00000 24 | FW_2 = 0x40000 25 | 26 | ifndef FLAVOR 27 | FLAVOR = release 28 | else 29 | FLAVOR = $(FLAVOR) 30 | endif 31 | 32 | 33 | ############################################################# 34 | # Select compile 35 | # 36 | ifeq ($(OS),Windows_NT) 37 | # WIN32 38 | # We are under windows. 39 | ifeq ($(XTENSA_CORE),lx106) 40 | # It is xcc 41 | AR = xt-ar 42 | CC = xt-xcc 43 | LD = xt-xcc 44 | NM = xt-nm 45 | CPP = xt-cpp 46 | OBJCOPY = xt-objcopy 47 | #MAKE = xt-make 48 | CCFLAGS += -Os --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal 49 | else 50 | # It is gcc, may be cygwin 51 | # Can we use -fdata-sections? 52 | CCFLAGS += -Os -ffunction-sections -fno-jump-tables 53 | AR = xtensa-lx106-elf-ar 54 | CC = xtensa-lx106-elf-gcc 55 | LD = xtensa-lx106-elf-gcc 56 | NM = xtensa-lx106-elf-nm 57 | CPP = xtensa-lx106-elf-cpp 58 | OBJCOPY = xtensa-lx106-elf-objcopy 59 | endif 60 | 61 | ESPPORT ?= com1 62 | SDK_BASE ?= c:/Espressif/ESP8266_SDK 63 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) 64 | # ->AMD64 65 | endif 66 | ifeq ($(PROCESSOR_ARCHITECTURE),x86) 67 | # ->IA32 68 | endif 69 | else 70 | # We are under other system, may be Linux. Assume using gcc. 71 | 72 | ESPPORT ?= /dev/ttyUSB0 73 | SDK_BASE ?= /esptools/esp-open-sdk/sdk 74 | 75 | CCFLAGS += -Os -ffunction-sections -fno-jump-tables 76 | AR = xtensa-lx106-elf-ar 77 | CC = xtensa-lx106-elf-gcc 78 | LD = xtensa-lx106-elf-gcc 79 | NM = xtensa-lx106-elf-nm 80 | CPP = xtensa-lx106-elf-cpp 81 | OBJCOPY = xtensa-lx106-elf-objcopy 82 | UNAME_S := $(shell uname -s) 83 | 84 | ifeq ($(UNAME_S),Linux) 85 | # LINUX 86 | endif 87 | ifeq ($(UNAME_S),Darwin) 88 | # OSX 89 | endif 90 | UNAME_P := $(shell uname -p) 91 | ifeq ($(UNAME_P),x86_64) 92 | # ->AMD64 93 | endif 94 | ifneq ($(filter %86,$(UNAME_P)),) 95 | # ->IA32 96 | endif 97 | ifneq ($(filter arm%,$(UNAME_P)),) 98 | # ->ARM 99 | endif 100 | endif 101 | ############################################################# 102 | 103 | 104 | # which modules (subdirectories) of the project to include in compiling 105 | MODULES = driver modules/mqtt/mqtt user modules 106 | EXTRA_INCDIR = include $(SDK_BASE)/../include 107 | 108 | # libraries used in this project, mainly provided by the SDK 109 | LIBS = c gcc hal phy pp net80211 lwip wpa main ssl 110 | 111 | # compiler flags using during compilation of source files 112 | CFLAGS = -Os -Wpointer-arith -Wundef -Werror -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH 113 | 114 | # linker flags used to generate the main object file 115 | LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static 116 | 117 | ifeq ($(FLAVOR),debug) 118 | CFLAGS += -g -O0 119 | LDFLAGS += -g -O0 120 | endif 121 | 122 | ifeq ($(FLAVOR),release) 123 | CFLAGS += -g -O2 124 | LDFLAGS += -g -O2 125 | endif 126 | 127 | 128 | 129 | # various paths from the SDK used in this project 130 | SDK_LIBDIR = lib 131 | SDK_LDDIR = ld 132 | SDK_INCDIR = include include/json 133 | 134 | #### 135 | #### no user configurable options below here 136 | #### 137 | FW_TOOL ?= $(ESPTOOL) 138 | SRC_DIR := $(MODULES) 139 | BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) 140 | 141 | SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR)) 142 | SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR)) 143 | 144 | SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) 145 | OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) 146 | LIBS := $(addprefix -l,$(LIBS)) 147 | APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a) 148 | TARGET_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).out) 149 | 150 | LD_SCRIPT := $(addprefix -T$(SDK_BASE)/$(SDK_LDDIR)/,$(LD_SCRIPT)) 151 | 152 | INCDIR := $(addprefix -I,$(SRC_DIR)) 153 | EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR)) 154 | MODULE_INCDIR := $(addsuffix /include,$(INCDIR)) 155 | 156 | FW_FILE_1 := $(addprefix $(FW_BASE)/,$(FW_1).bin) 157 | FW_FILE_2 := $(addprefix $(FW_BASE)/,$(FW_2).bin) 158 | 159 | V ?= $(VERBOSE) 160 | ifeq ("$(V)","1") 161 | Q := 162 | vecho := @true 163 | else 164 | Q := @ 165 | vecho := @echo 166 | endif 167 | 168 | vpath %.c $(SRC_DIR) 169 | 170 | define compile-objects 171 | $1/%.o: %.c 172 | $(vecho) "CC $$<" 173 | $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ 174 | endef 175 | 176 | .PHONY: all checkdirs clean 177 | 178 | all: checkdirs $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2) 179 | 180 | $(FW_FILE_1): $(TARGET_OUT) 181 | $(vecho) "FW $@" 182 | $(ESPTOOL) elf2image $< -o $(FW_BASE)/ 183 | 184 | $(FW_FILE_2): $(TARGET_OUT) 185 | $(vecho) "FW $@" 186 | $(ESPTOOL) elf2image $< -o $(FW_BASE)/ 187 | 188 | $(TARGET_OUT): $(APP_AR) 189 | $(vecho) "LD $@" 190 | $(Q) $(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ 191 | 192 | $(APP_AR): $(OBJ) 193 | $(vecho) "AR $@" 194 | $(Q) $(AR) cru $@ $^ 195 | 196 | checkdirs: $(BUILD_DIR) $(FW_BASE) 197 | 198 | $(BUILD_DIR): 199 | $(Q) mkdir -p $@ 200 | 201 | firmware: 202 | $(Q) mkdir -p $@ 203 | 204 | flash: $(FW_FILE_1) $(FW_FILE_2) 205 | $(ESPTOOL) -p $(ESPPORT) write_flash $(FW_1) $(FW_FILE_1) $(FW_2) $(FW_FILE_2) 206 | 207 | test: flash 208 | screen $(ESPPORT) 115200 209 | 210 | rebuild: clean all 211 | 212 | clean: 213 | $(Q) rm -f $(APP_AR) 214 | $(Q) rm -f $(TARGET_OUT) 215 | $(Q) rm -rf $(BUILD_DIR) 216 | $(Q) rm -rf $(BUILD_BASE) 217 | $(Q) rm -f $(FW_FILE_1) 218 | $(Q) rm -f $(FW_FILE_2) 219 | $(Q) rm -rf $(FW_BASE) 220 | 221 | $(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) 222 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | esp_bridge 2 | ================ 3 | 4 | This is source code for esp8266 support bridge for arduino or any MCU using SLIP protocol via Serial port. 5 | ###Library for arduino: [https://github.com/tuanpmt/espduino](https://github.com/tuanpmt/espduino) 6 | 7 | If you want using only ESP8266, you can find the **Native MQTT client** library for ESP8266 work well here: 8 | [https://github.com/tuanpmt/esp_mqtt](https://github.com/tuanpmt/esp_mqtt) 9 | 10 | Warning 11 | ============== 12 | This project **only execute commands from other MCU** via Serial port (like arduino). 13 | 14 | Features 15 | ======== 16 | - Rock Solid wifi network client for Arduino (of course need to test more and resolve more issues :v) 17 | - **More reliable** than AT COMMAND library (Personal comments) 18 | - **Firmware applications written on ESP8266 can be read out completely. For security applications, sometimes you should use it as a Wifi client (network client) and other MCU with Readout protection.** 19 | - It can be combined to work in parallel with the AT-COMMAND library 20 | - MQTT module: 21 | + MQTT client run stable as Native MQTT client (esp_mqtt) 22 | + Support subscribing, publishing, authentication, will messages, keep alive pings and all 3 QoS levels (it should be a fully functional client). 23 | + **Support multiple connection (to multiple hosts).** 24 | + Support SSL 25 | + Easy to setup and use 26 | - REST module: 27 | + Support method GET, POST, PUT, DELETE 28 | + setContent type, set header, set User Agent 29 | + Easy to used API 30 | + Support SSL 31 | - WIFI module: 32 | 33 | 34 | Installations 35 | ======== 36 | 37 | You can found here for instructions: [https://github.com/tuanpmt/espduino](https://github.com/tuanpmt/espduino) 38 | 39 | Compile 40 | ======= 41 | 42 | ```bash 43 | git clone --recursive https://github.com/tuanpmt/esp_bridge 44 | cd esp_bridge 45 | make all 46 | ``` 47 | 48 | Limited 49 | ======== 50 | It is not completely tested. Welcome your submitting issues. 51 | 52 | Contributing 53 | ========== 54 | There is very much needed module for this library, welcome your pull request: 55 | 56 | Donations 57 | ================== 58 | Invite me to a coffee 59 | [![Donate](https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JR9RVLFC4GE6J) 60 | 61 | Authors: 62 | ===== 63 | [Tuan PM](https://twitter.com/tuanpmt) 64 | 65 | 66 | **LICENSE - "MIT License"** 67 | 68 | Copyright (c) 2014-2015 Tuan PM, [https://twitter.com/tuanpmt](https://twitter.com/tuanpmt) 69 | 70 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 71 | 72 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 73 | 74 | 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. -------------------------------------------------------------------------------- /driver/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ############################################################# 3 | # Required variables for each makefile 4 | # Discard this section from all parent makefiles 5 | # Expected variables (with automatic defaults): 6 | # CSRCS (all "C" files in the dir) 7 | # SUBDIRS (all subdirs with a Makefile) 8 | # GEN_LIBS - list of libs to be generated () 9 | # GEN_IMAGES - list of images to be generated () 10 | # COMPONENTS_xxx - a list of libs/objs in the form 11 | # subdir/lib to be extracted and rolled up into 12 | # a generated lib/image xxx.a () 13 | # 14 | ifndef PDIR 15 | GEN_LIBS = libuser.a 16 | endif 17 | 18 | 19 | ############################################################# 20 | # Configuration i.e. compile options etc. 21 | # Target specific stuff (defines etc.) goes in here! 22 | # Generally values applying to a tree are captured in the 23 | # makefile at its root level - these are then overridden 24 | # for a subtree within the makefile rooted therein 25 | # 26 | #DEFINES += 27 | 28 | ############################################################# 29 | # Recursion Magic - Don't touch this!! 30 | # 31 | # Each subtree potentially has an include directory 32 | # corresponding to the common APIs applicable to modules 33 | # rooted at that subtree. Accordingly, the INCLUDE PATH 34 | # of a module can only contain the include directories up 35 | # its parent path, and not its siblings 36 | # 37 | # Required for each makefile to inherit from the parent 38 | # 39 | 40 | INCLUDES := $(INCLUDES) -I $(PDIR)include 41 | INCLUDES += -I ./ 42 | INCLUDES += -I ../../rom/include 43 | INCLUDES += -I ../../include/ets 44 | PDIR := ../$(PDIR) 45 | sinclude $(PDIR)Makefile 46 | 47 | -------------------------------------------------------------------------------- /driver/uart.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2013-2014 Espressif Systems (Wuxi) 3 | * 4 | * FileName: uart.c 5 | * 6 | * Description: Two UART mode configration and interrupt handler. 7 | * Check your hardware connection while use this mode. 8 | * 9 | * Modification history: 10 | * 2014/3/12, v1.0 create this file. 11 | *******************************************************************************/ 12 | #include "ets_sys.h" 13 | #include "osapi.h" 14 | #include "driver/uart.h" 15 | #include "osapi.h" 16 | #include "driver/uart_register.h" 17 | #include "cmd.h" 18 | 19 | 20 | // UartDev is defined and initialized in rom code. 21 | extern UartDevice UartDev; 22 | //extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen]; 23 | 24 | LOCAL void uart0_rx_intr_handler(void *para); 25 | 26 | /****************************************************************************** 27 | * FunctionName : uart_config 28 | * Description : Internal used function 29 | * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled 30 | * UART1 just used for debug output 31 | * Parameters : uart_no, use UART0 or UART1 defined ahead 32 | * Returns : NONE 33 | *******************************************************************************/ 34 | LOCAL void ICACHE_FLASH_ATTR 35 | uart_config(uint8 uart_no) 36 | { 37 | if (uart_no == UART1) 38 | { 39 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); 40 | } 41 | else 42 | { 43 | /* rcv_buff size if 0x100 */ 44 | ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); 45 | PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); 46 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); 47 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); 48 | } 49 | 50 | uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); 51 | 52 | WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity 53 | | UartDev.parity 54 | | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) 55 | | (UartDev.data_bits << UART_BIT_NUM_S)); 56 | 57 | //clear rx and tx fifo,not ready 58 | SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); 59 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); 60 | 61 | //set rx fifo trigger 62 | // WRITE_PERI_REG(UART_CONF1(uart_no), 63 | // ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | 64 | // ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) | 65 | // UART_RX_FLOW_EN); 66 | if (uart_no == UART0) 67 | { 68 | //set rx fifo trigger 69 | WRITE_PERI_REG(UART_CONF1(uart_no), 70 | ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | 71 | ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | 72 | UART_RX_FLOW_EN | 73 | (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | 74 | UART_RX_TOUT_EN); 75 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA | 76 | UART_FRM_ERR_INT_ENA); 77 | } 78 | else 79 | { 80 | WRITE_PERI_REG(UART_CONF1(uart_no), 81 | ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); 82 | } 83 | 84 | //clear all interrupt 85 | WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); 86 | //enable rx_interrupt 87 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); 88 | } 89 | 90 | /****************************************************************************** 91 | * FunctionName : uart1_tx_one_char 92 | * Description : Internal used function 93 | * Use uart1 interface to transfer one char 94 | * Parameters : uint8 TxChar - character to tx 95 | * Returns : OK 96 | *******************************************************************************/ 97 | LOCAL STATUS 98 | uart_tx_one_char(uint8 uart, uint8 TxChar) 99 | { 100 | while (true) 101 | { 102 | uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { 104 | break; 105 | } 106 | } 107 | 108 | WRITE_PERI_REG(UART_FIFO(uart) , TxChar); 109 | return OK; 110 | } 111 | void ICACHE_FLASH_ATTR 112 | uart0_write(char c) 113 | { 114 | while (true) 115 | { 116 | uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(0)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { 118 | break; 119 | } 120 | } 121 | 122 | WRITE_PERI_REG(UART_FIFO(0) , c); 123 | } 124 | 125 | /****************************************************************************** 126 | * FunctionName : uart1_write_char 127 | * Description : Internal used function 128 | * Do some special deal while tx char is '\r' or '\n' 129 | * Parameters : char c - character to tx 130 | * Returns : NONE 131 | *******************************************************************************/ 132 | void ICACHE_FLASH_ATTR 133 | uart1_write_char(char c) 134 | { 135 | if (c == '\n') 136 | { 137 | uart_tx_one_char(UART1, '\r'); 138 | uart_tx_one_char(UART1, '\n'); 139 | } 140 | else if (c == '\r') 141 | { 142 | } 143 | else 144 | { 145 | uart_tx_one_char(UART1, c); 146 | } 147 | } 148 | 149 | void ICACHE_FLASH_ATTR 150 | uart0_write_char(char c) 151 | { 152 | if (c == '\n') 153 | { 154 | uart_tx_one_char(UART0, '\r'); 155 | uart_tx_one_char(UART0, '\n'); 156 | } 157 | else if (c == '\r') 158 | { 159 | } 160 | else 161 | { 162 | uart_tx_one_char(UART0, c); 163 | } 164 | } 165 | /****************************************************************************** 166 | * FunctionName : uart0_tx_buffer 167 | * Description : use uart0 to transfer buffer 168 | * Parameters : uint8 *buf - point to send buffer 169 | * uint16 len - buffer len 170 | * Returns : 171 | *******************************************************************************/ 172 | void ICACHE_FLASH_ATTR 173 | uart0_tx_buffer(uint8 *buf, uint16 len) 174 | { 175 | uint16 i; 176 | 177 | for (i = 0; i < len; i++) 178 | { 179 | uart_tx_one_char(UART0, buf[i]); 180 | } 181 | } 182 | 183 | /****************************************************************************** 184 | * FunctionName : uart0_sendStr 185 | * Description : use uart0 to transfer buffer 186 | * Parameters : uint8 *buf - point to send buffer 187 | * uint16 len - buffer len 188 | * Returns : 189 | *******************************************************************************/ 190 | void ICACHE_FLASH_ATTR 191 | uart0_sendStr(const char *str) 192 | { 193 | while(*str) 194 | { 195 | uart_tx_one_char(UART0, *str++); 196 | } 197 | } 198 | 199 | /****************************************************************************** 200 | * FunctionName : uart0_rx_intr_handler 201 | * Description : Internal used function 202 | * UART0 interrupt handler, add self handle code inside 203 | * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg 204 | * Returns : NONE 205 | *******************************************************************************/ 206 | //extern void at_recvTask(void); 207 | 208 | LOCAL void 209 | uart0_rx_intr_handler(void *para) 210 | { 211 | 212 | uint8 RcvChar; 213 | uint8 uart_no = UART0;//UartDev.buff_uart_no; 214 | 215 | 216 | if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) 217 | { 218 | //os_printf("FRM_ERR\r\n"); 219 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); 220 | } 221 | 222 | if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) 223 | { 224 | ETS_UART_INTR_DISABLE();///////// 225 | 226 | while(READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) 227 | { 228 | WRITE_PERI_REG(0X60000914, 0x73); //WTD 229 | RcvChar = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; 230 | CMD_Input(RcvChar); 231 | } 232 | 233 | } 234 | else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) 235 | { 236 | ETS_UART_INTR_DISABLE();///////// 237 | while(READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) 238 | { 239 | WRITE_PERI_REG(0X60000914, 0x73); //WTD 240 | RcvChar = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; 241 | CMD_Input(RcvChar); 242 | } 243 | 244 | } 245 | 246 | if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(UART0)) & UART_RXFIFO_FULL_INT_ST)) 247 | { 248 | WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR); 249 | } 250 | else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(UART0)) & UART_RXFIFO_TOUT_INT_ST)) 251 | { 252 | WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR); 253 | } 254 | ETS_UART_INTR_ENABLE(); 255 | 256 | 257 | } 258 | 259 | /****************************************************************************** 260 | * FunctionName : uart_init 261 | * Description : user interface for init uart 262 | * Parameters : UartBautRate uart0_br - uart0 bautrate 263 | * UartBautRate uart1_br - uart1 bautrate 264 | * Returns : NONE 265 | *******************************************************************************/ 266 | void ICACHE_FLASH_ATTR 267 | uart_init(UartBautRate uart0_br, UartBautRate uart1_br) 268 | { 269 | // rom use 74880 baut_rate, here reinitialize 270 | UartDev.baut_rate = uart0_br; 271 | uart_config(UART0); 272 | UartDev.baut_rate = uart1_br; 273 | uart_config(UART1); 274 | ETS_UART_INTR_ENABLE(); 275 | 276 | // install uart1 putc callback 277 | os_install_putc1((void *)uart0_write_char); 278 | } 279 | 280 | void ICACHE_FLASH_ATTR 281 | uart_reattach() 282 | { 283 | uart_init(BIT_RATE_74880, BIT_RATE_74880); 284 | // ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff)); 285 | // ETS_UART_INTR_ENABLE(); 286 | } 287 | -------------------------------------------------------------------------------- /include/driver/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef UART_APP_H 2 | #define UART_APP_H 3 | 4 | #include "uart_register.h" 5 | #include "eagle_soc.h" 6 | #include "c_types.h" 7 | 8 | #define RX_BUFF_SIZE 256 9 | #define TX_BUFF_SIZE 100 10 | #define UART0 0 11 | #define UART1 1 12 | 13 | typedef enum { 14 | FIVE_BITS = 0x0, 15 | SIX_BITS = 0x1, 16 | SEVEN_BITS = 0x2, 17 | EIGHT_BITS = 0x3 18 | } UartBitsNum4Char; 19 | 20 | typedef enum { 21 | ONE_STOP_BIT = 0, 22 | ONE_HALF_STOP_BIT = BIT2, 23 | TWO_STOP_BIT = BIT2 24 | } UartStopBitsNum; 25 | 26 | typedef enum { 27 | NONE_BITS = 0, 28 | ODD_BITS = 0, 29 | EVEN_BITS = BIT4 30 | } UartParityMode; 31 | 32 | typedef enum { 33 | STICK_PARITY_DIS = 0, 34 | STICK_PARITY_EN = BIT3 | BIT5 35 | } UartExistParity; 36 | 37 | typedef enum { 38 | BIT_RATE_9600 = 9600, 39 | BIT_RATE_19200 = 19200, 40 | BIT_RATE_38400 = 38400, 41 | BIT_RATE_57600 = 57600, 42 | BIT_RATE_74880 = 74880, 43 | BIT_RATE_115200 = 115200, 44 | BIT_RATE_230400 = 230400, 45 | BIT_RATE_256000 = 256000, 46 | BIT_RATE_460800 = 460800, 47 | BIT_RATE_921600 = 921600 48 | } UartBautRate; 49 | 50 | typedef enum { 51 | NONE_CTRL, 52 | HARDWARE_CTRL, 53 | XON_XOFF_CTRL 54 | } UartFlowCtrl; 55 | 56 | typedef enum { 57 | EMPTY, 58 | UNDER_WRITE, 59 | WRITE_OVER 60 | } RcvMsgBuffState; 61 | 62 | typedef struct { 63 | uint32 RcvBuffSize; 64 | uint8 *pRcvMsgBuff; 65 | uint8 *pWritePos; 66 | uint8 *pReadPos; 67 | uint8 TrigLvl; //JLU: may need to pad 68 | RcvMsgBuffState BuffState; 69 | } RcvMsgBuff; 70 | 71 | typedef struct { 72 | uint32 TrxBuffSize; 73 | uint8 *pTrxBuff; 74 | } TrxMsgBuff; 75 | 76 | typedef enum { 77 | BAUD_RATE_DET, 78 | WAIT_SYNC_FRM, 79 | SRCH_MSG_HEAD, 80 | RCV_MSG_BODY, 81 | RCV_ESC_CHAR, 82 | } RcvMsgState; 83 | 84 | typedef struct { 85 | UartBautRate baut_rate; 86 | UartBitsNum4Char data_bits; 87 | UartExistParity exist_parity; 88 | UartParityMode parity; // chip size in byte 89 | UartStopBitsNum stop_bits; 90 | UartFlowCtrl flow_ctrl; 91 | RcvMsgBuff rcv_buff; 92 | TrxMsgBuff trx_buff; 93 | RcvMsgState rcv_state; 94 | int received; 95 | int buff_uart_no; //indicate which uart use tx/rx buffer 96 | } UartDevice; 97 | 98 | void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); 99 | void uart0_sendStr(const char *str); 100 | void uart0_write(char c); 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /include/driver/uart_register.h: -------------------------------------------------------------------------------- 1 | //Generated at 2012-07-03 18:44:06 2 | /* 3 | * Copyright (c) 2010 - 2011 Espressif System 4 | * 5 | */ 6 | 7 | #ifndef UART_REGISTER_H_INCLUDED 8 | #define UART_REGISTER_H_INCLUDED 9 | #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) 10 | //version value:32'h062000 11 | 12 | #define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) 13 | #define UART_RXFIFO_RD_BYTE 0x000000FF 14 | #define UART_RXFIFO_RD_BYTE_S 0 15 | 16 | #define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) 17 | #define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) 18 | #define UART_BRK_DET_INT_RAW (BIT(7)) 19 | #define UART_CTS_CHG_INT_RAW (BIT(6)) 20 | #define UART_DSR_CHG_INT_RAW (BIT(5)) 21 | #define UART_RXFIFO_OVF_INT_RAW (BIT(4)) 22 | #define UART_FRM_ERR_INT_RAW (BIT(3)) 23 | #define UART_PARITY_ERR_INT_RAW (BIT(2)) 24 | #define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) 25 | #define UART_RXFIFO_FULL_INT_RAW (BIT(0)) 26 | 27 | #define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) 28 | #define UART_RXFIFO_TOUT_INT_ST (BIT(8)) 29 | #define UART_BRK_DET_INT_ST (BIT(7)) 30 | #define UART_CTS_CHG_INT_ST (BIT(6)) 31 | #define UART_DSR_CHG_INT_ST (BIT(5)) 32 | #define UART_RXFIFO_OVF_INT_ST (BIT(4)) 33 | #define UART_FRM_ERR_INT_ST (BIT(3)) 34 | #define UART_PARITY_ERR_INT_ST (BIT(2)) 35 | #define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) 36 | #define UART_RXFIFO_FULL_INT_ST (BIT(0)) 37 | 38 | #define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) 39 | #define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) 40 | #define UART_BRK_DET_INT_ENA (BIT(7)) 41 | #define UART_CTS_CHG_INT_ENA (BIT(6)) 42 | #define UART_DSR_CHG_INT_ENA (BIT(5)) 43 | #define UART_RXFIFO_OVF_INT_ENA (BIT(4)) 44 | #define UART_FRM_ERR_INT_ENA (BIT(3)) 45 | #define UART_PARITY_ERR_INT_ENA (BIT(2)) 46 | #define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) 47 | #define UART_RXFIFO_FULL_INT_ENA (BIT(0)) 48 | 49 | #define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) 50 | #define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) 51 | #define UART_BRK_DET_INT_CLR (BIT(7)) 52 | #define UART_CTS_CHG_INT_CLR (BIT(6)) 53 | #define UART_DSR_CHG_INT_CLR (BIT(5)) 54 | #define UART_RXFIFO_OVF_INT_CLR (BIT(4)) 55 | #define UART_FRM_ERR_INT_CLR (BIT(3)) 56 | #define UART_PARITY_ERR_INT_CLR (BIT(2)) 57 | #define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) 58 | #define UART_RXFIFO_FULL_INT_CLR (BIT(0)) 59 | 60 | #define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) 61 | #define UART_CLKDIV_CNT 0x000FFFFF 62 | #define UART_CLKDIV_S 0 63 | 64 | #define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) 65 | #define UART_GLITCH_FILT 0x000000FF 66 | #define UART_GLITCH_FILT_S 8 67 | #define UART_AUTOBAUD_EN (BIT(0)) 68 | 69 | #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) 70 | #define UART_TXD (BIT(31)) 71 | #define UART_RTSN (BIT(30)) 72 | #define UART_DTRN (BIT(29)) 73 | #define UART_TXFIFO_CNT 0x000000FF 74 | #define UART_TXFIFO_CNT_S 16 75 | #define UART_RXD (BIT(15)) 76 | #define UART_CTSN (BIT(14)) 77 | #define UART_DSRN (BIT(13)) 78 | #define UART_RXFIFO_CNT 0x000000FF 79 | #define UART_RXFIFO_CNT_S 0 80 | 81 | #define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) 82 | #define UART_TXFIFO_RST (BIT(18)) 83 | #define UART_RXFIFO_RST (BIT(17)) 84 | #define UART_IRDA_EN (BIT(16)) 85 | #define UART_TX_FLOW_EN (BIT(15)) 86 | #define UART_LOOPBACK (BIT(14)) 87 | #define UART_IRDA_RX_INV (BIT(13)) 88 | #define UART_IRDA_TX_INV (BIT(12)) 89 | #define UART_IRDA_WCTL (BIT(11)) 90 | #define UART_IRDA_TX_EN (BIT(10)) 91 | #define UART_IRDA_DPLX (BIT(9)) 92 | #define UART_TXD_BRK (BIT(8)) 93 | #define UART_SW_DTR (BIT(7)) 94 | #define UART_SW_RTS (BIT(6)) 95 | #define UART_STOP_BIT_NUM 0x00000003 96 | #define UART_STOP_BIT_NUM_S 4 97 | #define UART_BIT_NUM 0x00000003 98 | #define UART_BIT_NUM_S 2 99 | #define UART_PARITY_EN (BIT(1)) 100 | #define UART_PARITY (BIT(0)) 101 | 102 | #define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) 103 | #define UART_RX_TOUT_EN (BIT(31)) 104 | #define UART_RX_TOUT_THRHD 0x0000007F 105 | #define UART_RX_TOUT_THRHD_S 24 106 | #define UART_RX_FLOW_EN (BIT(23)) 107 | #define UART_RX_FLOW_THRHD 0x0000007F 108 | #define UART_RX_FLOW_THRHD_S 16 109 | #define UART_TXFIFO_EMPTY_THRHD 0x0000007F 110 | #define UART_TXFIFO_EMPTY_THRHD_S 8 111 | #define UART_RXFIFO_FULL_THRHD 0x0000007F 112 | #define UART_RXFIFO_FULL_THRHD_S 0 113 | 114 | #define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) 115 | #define UART_LOWPULSE_MIN_CNT 0x000FFFFF 116 | #define UART_LOWPULSE_MIN_CNT_S 0 117 | 118 | #define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) 119 | #define UART_HIGHPULSE_MIN_CNT 0x000FFFFF 120 | #define UART_HIGHPULSE_MIN_CNT_S 0 121 | 122 | #define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) 123 | #define UART_PULSE_NUM_CNT 0x0003FF 124 | #define UART_PULSE_NUM_CNT_S 0 125 | 126 | #define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) 127 | #define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) 128 | #endif // UART_REGISTER_H_INCLUDED 129 | -------------------------------------------------------------------------------- /include/user_config.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_CONFIG_H_ 2 | #define _USER_CONFIG_H_ 3 | 4 | #define CFG_HOLDER 0x00FF55A4 /* Change this value to load default configurations */ 5 | #define CFG_LOCATION 0x3C /* Please don't change or if you know what you doing */ 6 | #define CLIENT_SSL_ENABLE 7 | 8 | /*DEFAULT CONFIGURATIONS*/ 9 | 10 | #define MQTT_HOST "192.168.11.122" //or "mqtt.yourdomain.com" 11 | #define MQTT_PORT 1880 12 | #define MQTT_BUF_SIZE 1024 13 | #define MQTT_KEEPALIVE 120 /*second*/ 14 | 15 | #define MQTT_CLIENT_ID "DVES_%08X" 16 | #define MQTT_USER "DVES_USER" 17 | #define MQTT_PASS "DVES_PASS" 18 | 19 | #define STA_SSID "DVES_HOME" 20 | #define STA_PASS "yourpassword" 21 | #define STA_TYPE AUTH_WPA2_PSK 22 | 23 | #define MQTT_RECONNECT_TIMEOUT 5 /*second*/ 24 | 25 | #define DEFAULT_SECURITY 0 26 | #define QUEUE_BUFFER_SIZE 2048 27 | 28 | #define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/ 29 | //PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/ 30 | //#define INFO 31 | #endif 32 | -------------------------------------------------------------------------------- /modules/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ############################################################# 3 | # Required variables for each makefile 4 | # Discard this section from all parent makefiles 5 | # Expected variables (with automatic defaults): 6 | # CSRCS (all "C" files in the dir) 7 | # SUBDIRS (all subdirs with a Makefile) 8 | # GEN_LIBS - list of libs to be generated () 9 | # GEN_IMAGES - list of images to be generated () 10 | # COMPONENTS_xxx - a list of libs/objs in the form 11 | # subdir/lib to be extracted and rolled up into 12 | # a generated lib/image xxx.a () 13 | # 14 | ifndef PDIR 15 | GEN_LIBS = libuser.a 16 | endif 17 | 18 | 19 | ############################################################# 20 | # Configuration i.e. compile options etc. 21 | # Target specific stuff (defines etc.) goes in here! 22 | # Generally values applying to a tree are captured in the 23 | # makefile at its root level - these are then overridden 24 | # for a subtree within the makefile rooted therein 25 | # 26 | #DEFINES += 27 | 28 | ############################################################# 29 | # Recursion Magic - Don't touch this!! 30 | # 31 | # Each subtree potentially has an include directory 32 | # corresponding to the common APIs applicable to modules 33 | # rooted at that subtree. Accordingly, the INCLUDE PATH 34 | # of a module can only contain the include directories up 35 | # its parent path, and not its siblings 36 | # 37 | # Required for each makefile to inherit from the parent 38 | # 39 | 40 | INCLUDES := $(INCLUDES) -I $(PDIR)include 41 | INCLUDES += -I ./ 42 | PDIR := ../$(PDIR) 43 | sinclude $(PDIR)Makefile 44 | 45 | -------------------------------------------------------------------------------- /modules/cmd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cmd.c 3 | * 4 | * Created on: Jan 9, 2015 5 | * Author: Minh 6 | */ 7 | #include "user_interface.h" 8 | #include "osapi.h" 9 | #include "mem.h" 10 | #include "driver/uart.h" 11 | #include "cmd.h" 12 | #include "user_config.h" 13 | #include "wifi.h" 14 | #include "mqtt.h" 15 | #include "ringbuf.h" 16 | #include "proto.h" 17 | #include "debug.h" 18 | #include "crc16.h" 19 | #include "mqtt_app.h" 20 | #include "rest.h" 21 | 22 | #define SLIP_START 0x7E 23 | #define SLIP_END 0x7F 24 | #define SLIP_REPL 0x7D 25 | #define SLIP_ESC(x) (x ^ 0x20) 26 | 27 | static void ICACHE_FLASH_ATTR 28 | CMD_Task(os_event_t *events); 29 | uint32_t ICACHE_FLASH_ATTR CMD_Reset(PACKET_CMD *cmd); 30 | uint32_t ICACHE_FLASH_ATTR CMD_IsReady(PACKET_CMD *cmd); 31 | const CMD_LIST commands[] = 32 | { 33 | {CMD_RESET, CMD_Reset}, 34 | {CMD_IS_READY, CMD_IsReady}, 35 | {CMD_WIFI_CONNECT, WIFI_Connect}, 36 | {CMD_MQTT_SETUP, MQTTAPP_Setup}, 37 | {CMD_MQTT_CONNECT, MQTTAPP_Connect}, 38 | {CMD_MQTT_DISCONNECT, MQTTAPP_Disconnect}, 39 | {CMD_MQTT_PUBLISH, MQTTAPP_Publish}, 40 | {CMD_MQTT_SUBSCRIBE, MQTTAPP_Subscribe}, 41 | {CMD_MQTT_LWT, MQTTAPP_Lwt}, 42 | 43 | {CMD_REST_SETUP, REST_Setup}, 44 | {CMD_REST_REQUEST, REST_Request}, 45 | {CMD_REST_SETHEADER, REST_SetHeader}, 46 | {CMD_NULL, NULL} 47 | }; 48 | 49 | os_event_t cmdRecvQueue[CMD_TASK_QUEUE_SIZE]; 50 | RINGBUF rxRb; 51 | uint8_t rxBuf[256]; 52 | 53 | PROTO_PARSER rxProto; 54 | uint8_t protoRxBuf[2048]; 55 | 56 | 57 | 58 | uint32_t ICACHE_FLASH_ATTR CMD_Reset(PACKET_CMD *cmd) 59 | { 60 | INFO("CMD: RESET\r\n"); 61 | system_restart(); 62 | return 1; 63 | } 64 | uint32_t ICACHE_FLASH_ATTR CMD_IsReady(PACKET_CMD *cmd) 65 | { 66 | INFO("CMD: Check ready\r\n"); 67 | return 1; 68 | } 69 | 70 | 71 | ICACHE_FLASH_ATTR 72 | void CMD_ProtoWrite(uint8_t data) 73 | { 74 | switch(data){ 75 | case SLIP_START: 76 | case SLIP_END: 77 | case SLIP_REPL: 78 | uart0_write(SLIP_REPL); 79 | uart0_write(SLIP_ESC(data)); 80 | break; 81 | default: 82 | uart0_write(data); 83 | } 84 | } 85 | ICACHE_FLASH_ATTR 86 | void CMD_ProtoWriteBuf(uint8_t *data, uint32_t len) 87 | { 88 | uint8_t* data_send = data; 89 | while(len--){ 90 | CMD_ProtoWrite(*data_send++); 91 | } 92 | } 93 | ICACHE_FLASH_ATTR 94 | uint16_t CMD_ResponseStart(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc) 95 | { 96 | uint16_t crc = 0; 97 | uart0_write(SLIP_START); 98 | CMD_ProtoWriteBuf((uint8_t*)&cmd, 2); 99 | crc = crc16_data((uint8_t*)&cmd, 2, crc); 100 | CMD_ProtoWriteBuf((uint8_t*)&callback, 4); 101 | crc = crc16_data((uint8_t*)&callback, 4, crc); 102 | CMD_ProtoWriteBuf((uint8_t*)&_return, 4); 103 | crc = crc16_data((uint8_t*)&_return, 4, crc); 104 | CMD_ProtoWriteBuf((uint8_t*)&argc, 2); 105 | crc = crc16_data((uint8_t*)&argc, 2, crc); 106 | return crc; 107 | } 108 | ICACHE_FLASH_ATTR 109 | uint16 CMD_ResponseBody(uint16_t crc_in, uint8_t* data, uint16_t len) 110 | { 111 | uint8_t temp = 0; 112 | uint16_t pad_len = len; 113 | while(pad_len % 4 != 0) 114 | pad_len++; 115 | 116 | CMD_ProtoWriteBuf((uint8_t*)&pad_len, 2); 117 | crc_in = crc16_data((uint8_t*)&pad_len, 2, crc_in); 118 | while(len --){ 119 | CMD_ProtoWrite(*data); 120 | crc_in = crc16_data((uint8_t*)data, 1, crc_in); 121 | data ++; 122 | if(pad_len > 0) pad_len --; 123 | } 124 | 125 | while(pad_len --){ 126 | CMD_ProtoWrite(temp); 127 | crc_in = crc16_data((uint8_t*)&temp, 1, crc_in); 128 | } 129 | return crc_in; 130 | } 131 | ICACHE_FLASH_ATTR 132 | uint16_t CMD_ResponseEnd(uint16_t crc) 133 | { 134 | CMD_ProtoWriteBuf((uint8_t*)&crc, 2); 135 | uart0_write(SLIP_END); 136 | return 0; 137 | } 138 | 139 | LOCAL uint32_t ICACHE_FLASH_ATTR 140 | CMD_Exec(const CMD_LIST *scp, PACKET_CMD *packet) 141 | { 142 | uint32_t ret; 143 | uint16_t crc = 0; 144 | while (scp->sc_name != CMD_NULL){ 145 | if(scp->sc_name == packet->cmd) { 146 | ret = scp->sc_function(packet); 147 | if(packet->_return){ 148 | INFO("CMD: Response return value: %d, cmd: %d\r\n", ret, packet->cmd); 149 | crc = CMD_ResponseStart(packet->cmd, 0, ret, 0); 150 | CMD_ResponseEnd(crc); 151 | } 152 | 153 | return ret; 154 | } 155 | scp++; 156 | } 157 | return 0; 158 | } 159 | 160 | static void ICACHE_FLASH_ATTR 161 | protoCompletedCb() 162 | { 163 | uint16_t crc = 0, argc, len, resp_crc, argn = 0; 164 | uint8_t *data_ptr; 165 | PACKET_CMD *packet; 166 | packet = (PACKET_CMD*)protoRxBuf; 167 | 168 | data_ptr = (uint8_t*)&packet->args ; 169 | crc = crc16_data((uint8_t*)&packet->cmd, 12, crc); 170 | argc = packet->argc; 171 | 172 | INFO("CMD: %d, cb: %d, ret: %d, argc: %d\r\n", packet->cmd, packet->callback, packet->_return, packet->argc); 173 | 174 | while(argc--){ 175 | len = *((uint16_t*)data_ptr); 176 | INFO("Arg[%d], len: %d:", argn++, len); 177 | crc = crc16_data(data_ptr, 2, crc); 178 | data_ptr += 2; 179 | crc = crc16_data(data_ptr, len, crc); 180 | while(len --){ 181 | INFO("%02X-", *data_ptr); 182 | data_ptr ++; 183 | } 184 | INFO("\r\n\r\n"); 185 | } 186 | resp_crc = *(uint16_t*)data_ptr; 187 | INFO("Read CRC: %04X, calculated crc: %04X\r\n", resp_crc, crc); 188 | 189 | if(crc != resp_crc) { 190 | 191 | INFO("ESP: Invalid CRC\r\n"); 192 | 193 | INFO(""); 194 | return; 195 | } 196 | CMD_Exec(commands, packet); 197 | } 198 | 199 | void ICACHE_FLASH_ATTR 200 | CMD_Init() 201 | { 202 | RINGBUF_Init(&rxRb, rxBuf, sizeof(rxBuf)); 203 | PROTO_Init(&rxProto, protoCompletedCb, protoRxBuf, sizeof(protoRxBuf)); 204 | 205 | system_os_task(CMD_Task, CMD_TASK_PRIO, cmdRecvQueue, CMD_TASK_QUEUE_SIZE); 206 | system_os_post(CMD_TASK_PRIO, 0, 0); 207 | } 208 | 209 | void ICACHE_FLASH_ATTR 210 | CMD_Input(uint8_t data) 211 | { 212 | RINGBUF_Put(&rxRb, data); 213 | system_os_post(CMD_TASK_PRIO, 0, 0); 214 | } 215 | 216 | static void ICACHE_FLASH_ATTR 217 | CMD_Task(os_event_t *events) 218 | { 219 | uint8_t c; 220 | while(RINGBUF_Get(&rxRb, &c) == 0){ 221 | PROTO_ParseByte(&rxProto, c); 222 | } 223 | 224 | } 225 | void ICACHE_FLASH_ATTR CMD_Request(REQUEST *req, PACKET_CMD* cmd) 226 | { 227 | req->cmd = cmd; 228 | req->arg_num = 0; 229 | req->arg_ptr = (uint8_t*)&cmd->args; 230 | } 231 | uint32_t ICACHE_FLASH_ATTR CMD_GetArgc(REQUEST *req) 232 | { 233 | return req->cmd->argc; 234 | } 235 | int32_t ICACHE_FLASH_ATTR CMD_PopArgs(REQUEST *req, uint8_t *data) 236 | { 237 | uint16_t length; 238 | 239 | if(req->arg_num >= req->cmd->argc) 240 | return -1; 241 | 242 | length = *(uint16_t*)req->arg_ptr; 243 | 244 | req->arg_ptr += 2; 245 | 246 | while(length --){ 247 | *data ++ = *req->arg_ptr ++; 248 | } 249 | 250 | req->arg_num ++; 251 | return 0; 252 | } 253 | uint16_t CMD_ArgLen(REQUEST *req) 254 | { 255 | return *(uint16_t*)req->arg_ptr; 256 | } 257 | -------------------------------------------------------------------------------- /modules/crc16.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005, Swedish Institute of Computer Science 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the Contiki operating system. 30 | * 31 | */ 32 | 33 | /** \addtogroup crc16 34 | * @{ */ 35 | 36 | /** 37 | * \file 38 | * Implementation of the CRC16 calculcation 39 | * \author 40 | * Adam Dunkels 41 | * 42 | */ 43 | 44 | /* CITT CRC16 polynomial ^16 + ^12 + ^5 + 1 */ 45 | /*---------------------------------------------------------------------------*/ 46 | unsigned short 47 | crc16_add(unsigned char b, unsigned short acc) 48 | { 49 | /* 50 | acc = (unsigned char)(acc >> 8) | (acc << 8); 51 | acc ^= b; 52 | acc ^= (unsigned char)(acc & 0xff) >> 4; 53 | acc ^= (acc << 8) << 4; 54 | acc ^= ((acc & 0xff) << 4) << 1; 55 | */ 56 | 57 | acc ^= b; 58 | acc = (acc >> 8) | (acc << 8); 59 | acc ^= (acc & 0xff00) << 4; 60 | acc ^= (acc >> 8) >> 4; 61 | acc ^= (acc & 0xff00) >> 5; 62 | return acc; 63 | } 64 | /*---------------------------------------------------------------------------*/ 65 | unsigned short 66 | crc16_data(const unsigned char *data, int len, unsigned short acc) 67 | { 68 | int i; 69 | 70 | for(i = 0; i < len; ++i) { 71 | acc = crc16_add(*data, acc); 72 | ++data; 73 | } 74 | return acc; 75 | } 76 | /*---------------------------------------------------------------------------*/ 77 | 78 | /** @} */ 79 | -------------------------------------------------------------------------------- /modules/include/cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cmd.h 3 | * 4 | * Created on: Jan 9, 2015 5 | * Author: Minh 6 | */ 7 | 8 | #ifndef USER_CMD_H_ 9 | #define USER_CMD_H_ 10 | 11 | 12 | #define CMD_TASK_QUEUE_SIZE 1 13 | #define CMD_TASK_PRIO 1 14 | 15 | typedef struct __attribute((__packed__)) { 16 | uint16_t len; 17 | uint8_t data; 18 | } ARGS; 19 | 20 | typedef struct __attribute((__packed__)) { 21 | uint16_t cmd; 22 | uint32_t callback; 23 | uint32_t _return; 24 | uint16_t argc; 25 | ARGS args; 26 | }PACKET_CMD; 27 | 28 | typedef struct { 29 | PACKET_CMD *cmd; 30 | uint32_t arg_num; 31 | uint8_t *arg_ptr; 32 | }REQUEST; 33 | 34 | typedef enum 35 | { 36 | CMD_NULL = 0, 37 | CMD_RESET, 38 | CMD_IS_READY, 39 | CMD_WIFI_CONNECT, 40 | CMD_MQTT_SETUP, 41 | CMD_MQTT_CONNECT, 42 | CMD_MQTT_DISCONNECT, 43 | CMD_MQTT_PUBLISH, 44 | CMD_MQTT_SUBSCRIBE, 45 | CMD_MQTT_LWT, 46 | CMD_MQTT_EVENTS, 47 | CMD_REST_SETUP, 48 | CMD_REST_REQUEST, 49 | CMD_REST_SETHEADER, 50 | CMD_REST_EVENTS 51 | }CMD_NAME; 52 | 53 | typedef uint32_t (*cmdfunc_t)(PACKET_CMD *cmd); 54 | 55 | typedef struct { 56 | CMD_NAME sc_name; 57 | cmdfunc_t sc_function; 58 | } CMD_LIST; 59 | 60 | 61 | void CMD_Init(); 62 | void CMD_Input(uint8_t data); 63 | 64 | uint16_t CMD_ResponseStart(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc); 65 | uint16 CMD_ResponseBody(uint16_t crc_in, uint8_t* data, uint16_t len); 66 | uint16_t CMD_ResponseEnd(uint16_t crc); 67 | 68 | void CMD_Response(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc, ARGS* args[]); 69 | void CMD_Request(REQUEST *req, PACKET_CMD* cmd); 70 | uint32_t CMD_GetArgc(REQUEST *req); 71 | int32_t CMD_PopArgs(REQUEST *req, uint8_t *data); 72 | uint16_t CMD_ArgLen(REQUEST *req); 73 | #endif /* USER_CMD_H_ */ 74 | -------------------------------------------------------------------------------- /modules/include/crc16.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2005, Swedish Institute of Computer Science 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the Contiki operating system. 30 | * 31 | */ 32 | 33 | /** 34 | * \file 35 | * Header file for the CRC16 calculcation 36 | * \author 37 | * Adam Dunkels 38 | * 39 | */ 40 | 41 | /** \addtogroup lib 42 | * @{ */ 43 | 44 | /** 45 | * \defgroup crc16 Cyclic Redundancy Check 16 (CRC16) calculation 46 | * 47 | * The Cyclic Redundancy Check 16 is a hash function that produces a 48 | * checksum that is used to detect errors in transmissions. The CRC16 49 | * calculation module is an iterative CRC calculator that can be used 50 | * to cumulatively update a CRC checksum for every incoming byte. 51 | * 52 | * @{ 53 | */ 54 | 55 | #ifndef CRC16_H_ 56 | #define CRC16_H_ 57 | 58 | /** 59 | * \brief Update an accumulated CRC16 checksum with one byte. 60 | * \param b The byte to be added to the checksum 61 | * \param crc The accumulated CRC that is to be updated. 62 | * \return The updated CRC checksum. 63 | * 64 | * This function updates an accumulated CRC16 checksum 65 | * with one byte. It can be used as a running checksum, or 66 | * to checksum an entire data block. 67 | * 68 | * \note The algorithm used in this implementation is 69 | * tailored for a running checksum and does not perform as 70 | * well as a table-driven algorithm when checksumming an 71 | * entire data block. 72 | * 73 | */ 74 | unsigned short crc16_add(unsigned char b, unsigned short crc); 75 | 76 | /** 77 | * \brief Calculate the CRC16 over a data area 78 | * \param data Pointer to the data 79 | * \param datalen The length of the data 80 | * \param acc The accumulated CRC that is to be updated (or zero). 81 | * \return The CRC16 checksum. 82 | * 83 | * This function calculates the CRC16 checksum of a data area. 84 | * 85 | * \note The algorithm used in this implementation is 86 | * tailored for a running checksum and does not perform as 87 | * well as a table-driven algorithm when checksumming an 88 | * entire data block. 89 | */ 90 | unsigned short crc16_data(const unsigned char *data, int datalen, 91 | unsigned short acc); 92 | 93 | #endif /* CRC16_H_ */ 94 | 95 | /** @} */ 96 | /** @} */ 97 | -------------------------------------------------------------------------------- /modules/include/rest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * api.h 3 | * 4 | * Created on: Mar 4, 2015 5 | * Author: Minh 6 | */ 7 | 8 | #ifndef MODULES_API_H_ 9 | #define MODULES_API_H_ 10 | #include "c_types.h" 11 | #include "ip_addr.h" 12 | #include "cmd.h" 13 | typedef enum { 14 | HEADER_GENERIC = 0, 15 | HEADER_CONTENT_TYPE, 16 | HEADER_USER_AGENT 17 | } HEADER_TYPE; 18 | 19 | 20 | typedef struct { 21 | uint8_t* host; 22 | uint32_t port; 23 | uint32_t security; 24 | ip_addr_t ip; 25 | struct espconn *pCon; 26 | uint8_t* header; 27 | uint8_t* data; 28 | uint32_t data_len; 29 | uint8_t* content_type; 30 | uint8_t* user_agent; 31 | uint32_t resp_cb; 32 | } REST_CLIENT; 33 | 34 | uint32_t REST_Setup(PACKET_CMD *cmd); 35 | uint32_t REST_Request(PACKET_CMD *cmd); 36 | uint32_t REST_SetHeader(PACKET_CMD *cmd); 37 | #endif /* MODULES_INCLUDE_API_H_ */ 38 | -------------------------------------------------------------------------------- /modules/include/wifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wifi.h 3 | * 4 | * Created on: Dec 30, 2014 5 | * Author: Minh 6 | */ 7 | 8 | #ifndef USER_WIFI_H_ 9 | #define USER_WIFI_H_ 10 | #include "os_type.h" 11 | #include "cmd.h" 12 | typedef void (*WifiCallback)(uint8_t); 13 | uint32_t ICACHE_FLASH_ATTR 14 | WIFI_Connect(PACKET_CMD *cmd); 15 | 16 | 17 | #endif /* USER_WIFI_H_ */ 18 | -------------------------------------------------------------------------------- /modules/mqtt_app.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_app.c 3 | * 4 | * Created on: Feb 28, 2015 5 | * Author: Minh 6 | */ 7 | 8 | #include "mqtt_app.h" 9 | #include "osapi.h" 10 | #include "mem.h" 11 | #include "debug.h" 12 | uint32_t connectedCb = 0, disconnectCb = 0, publishedCb = 0, dataCb = 0; 13 | 14 | void mqttConnectedCb(uint32_t *args) 15 | { 16 | MQTT_Client* client = (MQTT_Client*)args; 17 | MQTT_CALLBACK *callback = (MQTT_CALLBACK*)client->user_data; 18 | INFO("MQTT: Connected\r\n"); 19 | INFO("Callback data: %d, %d, %d, %d\r\n", 20 | callback->connectedCb, 21 | callback->disconnectedCb, 22 | callback->publishedCb, 23 | callback->dataCb); 24 | uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, callback->connectedCb, 0, 0); 25 | CMD_ResponseEnd(crc); 26 | } 27 | 28 | void mqttDisconnectedCb(uint32_t *args) 29 | { 30 | MQTT_Client* client = (MQTT_Client*)args; 31 | MQTT_CALLBACK *cb = (MQTT_CALLBACK*)client->user_data; 32 | INFO("MQTT: Disconnected\r\n"); 33 | uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); 34 | CMD_ResponseEnd(crc); 35 | } 36 | 37 | void mqttPublishedCb(uint32_t *args) 38 | { 39 | MQTT_Client* client = (MQTT_Client*)args; 40 | MQTT_CALLBACK *cb = (MQTT_CALLBACK*)client->user_data; 41 | INFO("MQTT: Published\r\n"); 42 | uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); 43 | CMD_ResponseEnd(crc); 44 | } 45 | 46 | void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) 47 | { 48 | uint16_t crc = 0; 49 | 50 | 51 | MQTT_Client* client = (MQTT_Client*)args; 52 | MQTT_CALLBACK *cb = (MQTT_CALLBACK*)client->user_data; 53 | 54 | crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->dataCb, 0, 2); 55 | crc = CMD_ResponseBody(crc, (uint8_t*)topic, topic_len); 56 | crc = CMD_ResponseBody(crc, (uint8_t*)data, data_len); 57 | CMD_ResponseEnd(crc); 58 | 59 | } 60 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Setup(PACKET_CMD *cmd) 61 | { 62 | REQUEST req; 63 | MQTT_Client *client; 64 | uint8_t *client_id, *user_data, *pass_data; 65 | uint16_t len; 66 | uint32_t keepalive, clean_seasion, cb_data; 67 | MQTT_CALLBACK *callback; 68 | 69 | 70 | CMD_Request(&req, cmd); 71 | if(CMD_GetArgc(&req) != 9) 72 | return 0; 73 | 74 | client = (MQTT_Client*)os_zalloc(sizeof(MQTT_Client)); 75 | 76 | if(client == NULL) 77 | return 0; 78 | 79 | os_memset(client, 0, sizeof(MQTT_Client)); 80 | 81 | /*Get client id*/ 82 | len = CMD_ArgLen(&req); 83 | client_id = (uint8_t*)os_zalloc(len + 1); 84 | CMD_PopArgs(&req, client_id); 85 | client_id[len] = 0; 86 | 87 | /*Get username*/ 88 | len = CMD_ArgLen(&req); 89 | user_data = (uint8_t*)os_zalloc(len + 1); 90 | CMD_PopArgs(&req, user_data); 91 | user_data[len] = 0; 92 | 93 | /*Get password*/ 94 | len = CMD_ArgLen(&req); 95 | pass_data = (uint8_t*)os_zalloc(len + 1); 96 | CMD_PopArgs(&req, pass_data); 97 | pass_data[len] = 0; 98 | 99 | CMD_PopArgs(&req, (uint8_t*)&keepalive); 100 | CMD_PopArgs(&req, (uint8_t*)&clean_seasion); 101 | 102 | 103 | /*init client*/ 104 | INFO("MQTT: clientid = %s, user = %s, pass = %s, keepalive = %d, session = %d\r\n", client_id, user_data, pass_data, keepalive, clean_seasion); 105 | MQTT_InitClient(client, client_id, user_data, pass_data, keepalive, clean_seasion); 106 | 107 | callback = (MQTT_CALLBACK*)os_zalloc(sizeof(MQTT_CALLBACK)); 108 | 109 | 110 | CMD_PopArgs(&req, (uint8_t*)&cb_data); 111 | callback->connectedCb = cb_data; 112 | CMD_PopArgs(&req, (uint8_t*)&cb_data); 113 | callback->disconnectedCb = cb_data; 114 | CMD_PopArgs(&req, (uint8_t*)&cb_data); 115 | callback->publishedCb = cb_data; 116 | CMD_PopArgs(&req, (uint8_t*)&cb_data); 117 | callback->dataCb = cb_data; 118 | 119 | 120 | client->user_data = callback; 121 | 122 | client->connectedCb = mqttConnectedCb; 123 | client->disconnectedCb = mqttDisconnectedCb; 124 | client->publishedCb = mqttPublishedCb; 125 | client->dataCb = mqttDataCb; 126 | 127 | os_free(client_id); 128 | os_free(user_data); 129 | os_free(pass_data); 130 | 131 | return (uint32_t)client; 132 | } 133 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Lwt(PACKET_CMD *cmd) 134 | { 135 | REQUEST req; 136 | MQTT_Client *client; 137 | CMD_Request(&req, cmd); 138 | uint16_t len; 139 | uint8_t *topic, *message; 140 | uint32_t qos, retain, client_ptr; 141 | if(CMD_GetArgc(&req) != 5) 142 | return 0; 143 | 144 | /* Get client*/ 145 | CMD_PopArgs(&req, (uint8_t*)&client_ptr); 146 | client = (MQTT_Client*)client_ptr; 147 | INFO("MQTT: lwt client addr = %d\r\n", client_ptr); 148 | 149 | /*Get topic*/ 150 | if(client->connect_info.will_topic) 151 | os_free(client->connect_info.will_topic); 152 | len = CMD_ArgLen(&req); 153 | client->connect_info.will_topic = (uint8_t*)os_zalloc(len + 1); 154 | CMD_PopArgs(&req, client->connect_info.will_topic); 155 | client->connect_info.will_topic[len] = 0; 156 | 157 | /*Get message*/ 158 | if(client->connect_info.will_message) 159 | os_free(client->connect_info.will_message); 160 | len = CMD_ArgLen(&req); 161 | client->connect_info.will_message = (uint8_t*)os_zalloc(len + 1); 162 | CMD_PopArgs(&req, client->connect_info.will_message); 163 | client->connect_info.will_message[len] = 0; 164 | 165 | CMD_PopArgs(&req, (uint8_t*)&qos); 166 | CMD_PopArgs(&req, (uint8_t*)&retain); 167 | client->connect_info.will_qos = qos; 168 | client->connect_info.will_retain = retain; 169 | INFO("MQTT: lwt topic = %s, message = %s, qos = %d, retain = %d\r\n", 170 | client->connect_info.will_topic, 171 | client->connect_info.will_message, 172 | client->connect_info.will_qos, 173 | client->connect_info.will_retain); 174 | return 1; 175 | 176 | } 177 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Connect(PACKET_CMD *cmd) 178 | { 179 | MQTT_Client *client; 180 | REQUEST req; 181 | uint16_t len; 182 | uint32_t security; 183 | 184 | CMD_Request(&req, cmd); 185 | if(CMD_GetArgc(&req) != 4) 186 | return 0; 187 | 188 | CMD_PopArgs(&req, (uint8_t*)&client); 189 | 190 | /*Get host name*/ 191 | len = CMD_ArgLen(&req); 192 | 193 | if(client->host) 194 | os_free(client->host); 195 | client->host = (uint8_t*)os_zalloc(len + 1); 196 | CMD_PopArgs(&req, client->host); 197 | client->host[len] = 0; 198 | 199 | CMD_PopArgs(&req, (uint8_t*)&client->port); 200 | CMD_PopArgs(&req, (uint8_t*)&security); 201 | client->security = security; 202 | MQTT_Connect(client); 203 | return 1; 204 | } 205 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Disconnect(PACKET_CMD *cmd) 206 | { 207 | MQTT_Client *client; 208 | REQUEST req; 209 | uint16_t len; 210 | 211 | 212 | CMD_Request(&req, cmd); 213 | if(CMD_GetArgc(&req) != 1) 214 | return 0; 215 | CMD_PopArgs(&req, (uint8_t*)&client); 216 | 217 | MQTT_Disconnect(client); 218 | return 1; 219 | } 220 | 221 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Publish(PACKET_CMD *cmd) 222 | { 223 | MQTT_Client *client; 224 | REQUEST req; 225 | uint16_t len; 226 | uint8_t *topic, *data; 227 | uint32_t qos = 0, retain = 0, data_len; 228 | 229 | CMD_Request(&req, cmd); 230 | if(CMD_GetArgc(&req) != 6) 231 | return 0; 232 | CMD_PopArgs(&req, (uint8_t*)&client); 233 | 234 | /*Get topic*/ 235 | len = CMD_ArgLen(&req); 236 | 237 | topic = (uint8_t*)os_zalloc(len + 1); 238 | CMD_PopArgs(&req, topic); 239 | topic[len] = 0; 240 | 241 | 242 | /*Get data*/ 243 | len = CMD_ArgLen(&req); 244 | 245 | data = (uint8_t*)os_zalloc(len); 246 | CMD_PopArgs(&req, data); 247 | 248 | /*Get data length*/ 249 | CMD_PopArgs(&req, (uint8_t*)&data_len); 250 | 251 | CMD_PopArgs(&req, (uint8_t*)&qos); 252 | CMD_PopArgs(&req, (uint8_t*)&retain); 253 | 254 | MQTT_Publish(client, topic, data, data_len, qos, retain); 255 | os_free(topic); 256 | os_free(data); 257 | return 1; 258 | 259 | } 260 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Subscribe(PACKET_CMD *cmd) 261 | { 262 | MQTT_Client *client; 263 | REQUEST req; 264 | uint16_t len; 265 | uint8_t *topic; 266 | uint32_t qos = 0; 267 | 268 | CMD_Request(&req, cmd); 269 | if(CMD_GetArgc(&req) != 3) 270 | return 0; 271 | CMD_PopArgs(&req, (uint8_t*)&client); 272 | 273 | /*Get topic*/ 274 | len = CMD_ArgLen(&req); 275 | 276 | topic = (uint8_t*)os_zalloc(len + 1); 277 | CMD_PopArgs(&req, topic); 278 | topic[len] = 0; 279 | CMD_PopArgs(&req, (uint8_t*)&qos); 280 | 281 | INFO("MQTT: topic = %s, qos = %d \r\n", topic, qos); 282 | MQTT_Subscribe(client, topic, qos); 283 | os_free(topic); 284 | return 1; 285 | } 286 | 287 | -------------------------------------------------------------------------------- /modules/mqtt_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mqtt_app.h 3 | * 4 | * Created on: Feb 28, 2015 5 | * Author: Minh 6 | */ 7 | 8 | #ifndef MODULES_MQTT_APP_H_ 9 | #define MODULES_MQTT_APP_H_ 10 | 11 | #include "mqtt.h" 12 | #include "cmd.h" 13 | typedef struct { 14 | uint32_t connectedCb; 15 | uint32_t disconnectedCb; 16 | uint32_t publishedCb; 17 | uint32_t dataCb; 18 | }MQTT_CALLBACK; 19 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Connect(PACKET_CMD *cmd); 20 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Disconnect(PACKET_CMD *cmd); 21 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Setup(PACKET_CMD *cmd); 22 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Publish(PACKET_CMD *cmd); 23 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Subscribe(PACKET_CMD *cmd); 24 | uint32_t ICACHE_FLASH_ATTR MQTTAPP_Lwt(PACKET_CMD *cmd); 25 | 26 | #endif /* MODULES_MQTT_APP_H_ */ 27 | -------------------------------------------------------------------------------- /modules/rest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * api.c 3 | * 4 | * Created on: Mar 4, 2015 5 | * Author: Minh 6 | */ 7 | #include "rest.h" 8 | 9 | #include "user_interface.h" 10 | #include "osapi.h" 11 | #include "mem.h" 12 | #include "driver/uart.h" 13 | #include "cmd.h" 14 | #include "user_config.h" 15 | #include "espconn.h" 16 | #include "os_type.h" 17 | #include "debug.h" 18 | 19 | void ICACHE_FLASH_ATTR 20 | tcpclient_discon_cb(void *arg) 21 | { 22 | 23 | struct espconn *pespconn = (struct espconn *)arg; 24 | REST_CLIENT* client = (REST_CLIENT *)pespconn->reverse; 25 | 26 | 27 | } 28 | 29 | 30 | void ICACHE_FLASH_ATTR 31 | tcpclient_recv(void *arg, char *pdata, unsigned short len) 32 | { 33 | uint8_t currentLineIsBlank = 0; 34 | uint8_t httpBody = 0; 35 | uint8_t inStatus = 0; 36 | char statusCode[4]; 37 | int i = 0, j; 38 | uint32_t code = 0; 39 | uint16_t crc; 40 | 41 | struct espconn *pCon = (struct espconn*)arg; 42 | REST_CLIENT *client = (REST_CLIENT *)pCon->reverse; 43 | 44 | for(j=0 ;jresp_cb, code, 0); 64 | } else { 65 | crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); 66 | crc = CMD_ResponseBody(crc, &pdata[j], body_len); 67 | } 68 | CMD_ResponseEnd(crc); 69 | break; 70 | } 71 | else 72 | { 73 | if (c == '\n' && currentLineIsBlank) { 74 | httpBody = true; 75 | } 76 | if (c == '\n') { 77 | // you're starting a new line 78 | currentLineIsBlank = true; 79 | } 80 | else if (c != '\r') { 81 | // you've gotten a character on the current line 82 | currentLineIsBlank = false; 83 | } 84 | } 85 | } 86 | if(client->security) 87 | espconn_secure_disconnect(client->pCon); 88 | else 89 | espconn_disconnect(client->pCon); 90 | 91 | } 92 | void ICACHE_FLASH_ATTR 93 | tcpclient_sent_cb(void *arg) 94 | { 95 | struct espconn *pCon = (struct espconn *)arg; 96 | REST_CLIENT* client = (REST_CLIENT *)pCon->reverse; 97 | INFO("REST: Sent\r\n"); 98 | } 99 | 100 | void ICACHE_FLASH_ATTR 101 | tcpclient_connect_cb(void *arg) 102 | { 103 | struct espconn *pCon = (struct espconn *)arg; 104 | REST_CLIENT* client = (REST_CLIENT *)pCon->reverse; 105 | 106 | espconn_regist_disconcb(client->pCon, tcpclient_discon_cb); 107 | espconn_regist_recvcb(client->pCon, tcpclient_recv);//////// 108 | espconn_regist_sentcb(client->pCon, tcpclient_sent_cb);/////// 109 | 110 | if(client->security){ 111 | espconn_secure_sent(client->pCon, client->data, client->data_len); 112 | } 113 | else{ 114 | espconn_sent(client->pCon, client->data, client->data_len); 115 | } 116 | } 117 | void ICACHE_FLASH_ATTR 118 | tcpclient_recon_cb(void *arg, sint8 errType) 119 | { 120 | struct espconn *pCon = (struct espconn *)arg; 121 | REST_CLIENT* client = (REST_CLIENT *)pCon->reverse; 122 | 123 | } 124 | LOCAL void ICACHE_FLASH_ATTR 125 | rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) 126 | { 127 | struct espconn *pConn = (struct espconn *)arg; 128 | REST_CLIENT* client = (REST_CLIENT *)pConn->reverse; 129 | if(ipaddr == NULL) 130 | { 131 | INFO("REST DNS: Found, but got no ip, try to reconnect\r\n"); 132 | return; 133 | } 134 | 135 | INFO("REST DNS: found ip %d.%d.%d.%d\n", 136 | *((uint8 *) &ipaddr->addr), 137 | *((uint8 *) &ipaddr->addr + 1), 138 | *((uint8 *) &ipaddr->addr + 2), 139 | *((uint8 *) &ipaddr->addr + 3)); 140 | 141 | if(client->ip.addr == 0 && ipaddr->addr != 0) 142 | { 143 | os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); 144 | if(client->security){ 145 | espconn_secure_connect(client->pCon); 146 | } 147 | else { 148 | espconn_connect(client->pCon); 149 | } 150 | INFO("REST: connecting...\r\n"); 151 | } 152 | } 153 | uint32_t ICACHE_FLASH_ATTR REST_Setup(PACKET_CMD *cmd) 154 | { 155 | REQUEST req; 156 | REST_CLIENT *client; 157 | uint8_t *rest_host; 158 | uint16_t len; 159 | uint32_t port, security; 160 | 161 | CMD_Request(&req, cmd); 162 | if(CMD_GetArgc(&req) != 3) 163 | return 0; 164 | 165 | len = CMD_ArgLen(&req); 166 | rest_host = (uint8_t*)os_zalloc(len + 1); 167 | CMD_PopArgs(&req, rest_host); 168 | rest_host[len] = 0; 169 | 170 | client = (REST_CLIENT*)os_zalloc(sizeof(REST_CLIENT)); 171 | os_memset(client, 0, sizeof(REST_CLIENT)); 172 | if(client == NULL) 173 | return 0; 174 | 175 | CMD_PopArgs(&req, (uint8_t*)&port); 176 | 177 | CMD_PopArgs(&req, (uint8_t*)&security); 178 | 179 | client->resp_cb = cmd->callback; 180 | 181 | client->host = rest_host; 182 | client->port = port; 183 | client->security = security; 184 | client->ip.addr = 0; 185 | 186 | client->data = (uint8_t*)os_zalloc(1024); 187 | 188 | client->header = (uint8_t*)os_zalloc(4); 189 | client->header[0] = 0; 190 | 191 | client->content_type = (uint8_t*)os_zalloc(22); 192 | os_sprintf(client->content_type, "x-www-form-urlencoded"); 193 | client->content_type[21] = 0; 194 | 195 | client->user_agent = (uint8_t*)os_zalloc(17); 196 | os_sprintf(client->user_agent, "ESPDRUINO@tuanpmt"); 197 | client->user_agent[16] = 0; 198 | 199 | client->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn)); 200 | client->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); 201 | 202 | client->pCon->type = ESPCONN_TCP; 203 | client->pCon->state = ESPCONN_NONE; 204 | client->pCon->proto.tcp->local_port = espconn_port(); 205 | client->pCon->proto.tcp->remote_port = client->port; 206 | 207 | client->pCon->reverse = client; 208 | 209 | return (uint32_t)client; 210 | } 211 | uint32_t ICACHE_FLASH_ATTR REST_SetHeader(PACKET_CMD *cmd) 212 | { 213 | REQUEST req; 214 | REST_CLIENT *client; 215 | uint16_t len; 216 | uint32_t header_index, client_ptr = 0; 217 | 218 | CMD_Request(&req, cmd); 219 | 220 | if(CMD_GetArgc(&req) != 3) 221 | return 0; 222 | 223 | /* Get client*/ 224 | CMD_PopArgs(&req, (uint8_t*)&client_ptr); 225 | client = (REST_CLIENT*)client_ptr; 226 | 227 | CMD_PopArgs(&req, (uint8_t*)&header_index); 228 | len = CMD_ArgLen(&req); 229 | 230 | switch(header_index) { 231 | case HEADER_GENERIC: 232 | if(client->header) 233 | os_free(client->header); 234 | client->header = (uint8_t*)os_zalloc(len + 1); 235 | CMD_PopArgs(&req, (uint8_t*)client->header); 236 | client->header[len] = 0; 237 | INFO("Set header: %s\r\n", client->header); 238 | break; 239 | case HEADER_CONTENT_TYPE: 240 | if(client->content_type) 241 | os_free(client->content_type); 242 | client->content_type = (uint8_t*)os_zalloc(len + 1); 243 | CMD_PopArgs(&req, (uint8_t*)client->content_type); 244 | client->content_type[len] = 0; 245 | INFO("Set content_type: %s\r\n", client->content_type); 246 | break; 247 | case HEADER_USER_AGENT: 248 | if(client->user_agent) 249 | os_free(client->user_agent); 250 | client->user_agent = (uint8_t*)os_zalloc(len + 1); 251 | CMD_PopArgs(&req, (uint8_t*)client->user_agent); 252 | client->user_agent[len] = 0; 253 | INFO("Set user_agent: %s\r\n", client->user_agent); 254 | break; 255 | } 256 | return 1; 257 | 258 | } 259 | uint32_t ICACHE_FLASH_ATTR REST_Request(PACKET_CMD *cmd) 260 | { 261 | 262 | REQUEST req; 263 | REST_CLIENT *client; 264 | uint16_t len, realLen = 0; 265 | uint32_t client_ptr; 266 | uint8_t *method, *path, *body = NULL; 267 | 268 | CMD_Request(&req, cmd); 269 | 270 | if(CMD_GetArgc(&req) <3) 271 | return 0; 272 | 273 | /* Get client*/ 274 | CMD_PopArgs(&req, (uint8_t*)&client_ptr); 275 | client = (REST_CLIENT*)client_ptr; 276 | 277 | //method 278 | len = CMD_ArgLen(&req); 279 | method = (uint8_t*)os_zalloc(len + 1); 280 | CMD_PopArgs(&req, method); 281 | method[len] = 0; 282 | 283 | 284 | //path 285 | len = CMD_ArgLen(&req); 286 | path = (uint8_t*)os_zalloc(len + 1); 287 | CMD_PopArgs(&req, path); 288 | path[len] = 0; 289 | 290 | //body 291 | if(CMD_GetArgc(&req) == 3){ 292 | realLen = 0; 293 | len = 0; 294 | } else { 295 | CMD_PopArgs(&req, (uint8_t*)&realLen); 296 | 297 | len = CMD_ArgLen(&req); 298 | body = (uint8_t*)os_zalloc(len + 1); 299 | CMD_PopArgs(&req, body); 300 | body[len] = 0; 301 | } 302 | 303 | client->pCon->state = ESPCONN_NONE; 304 | 305 | INFO("REQ: method: %s, path: %s\r\n", method, path); 306 | 307 | client->data_len = os_sprintf(client->data, "%s %s HTTP/1.1\r\n" 308 | "Host: %s\r\n" 309 | "%s" 310 | "Content-Length: %d\r\n" 311 | "Connection: close\r\n" 312 | "Content-Type: %s\r\n" 313 | "User-Agent: %s\r\n\r\n", 314 | method, path, 315 | client->host, 316 | client->header, 317 | realLen, 318 | client->content_type, 319 | client->user_agent); 320 | 321 | if(realLen > 0){ 322 | os_memcpy(client->data + client->data_len, body, realLen); 323 | client->data_len += realLen; 324 | os_sprintf(client->data + client->data_len, "\r\n\r\n"); 325 | client->data_len += 4; 326 | } 327 | 328 | client->pCon->state = ESPCONN_NONE; 329 | espconn_regist_connectcb(client->pCon, tcpclient_connect_cb); 330 | espconn_regist_reconcb(client->pCon, tcpclient_recon_cb); 331 | 332 | if(UTILS_StrToIP(client->host, &client->pCon->proto.tcp->remote_ip)) { 333 | INFO("REST: Connect to ip %s:%d\r\n",client->host, client->port); 334 | if(client->security){ 335 | espconn_secure_connect(client->pCon); 336 | } 337 | else { 338 | espconn_connect(client->pCon); 339 | } 340 | } 341 | else { 342 | INFO("REST: Connect to domain %s:%d\r\n", client->host, client->port); 343 | espconn_gethostbyname(client->pCon, client->host, &client->ip, rest_dns_found); 344 | } 345 | os_free(method); 346 | os_free(path); 347 | if(body) os_free(body); 348 | return 1; 349 | } 350 | -------------------------------------------------------------------------------- /modules/wifi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wifi.c 3 | * 4 | * Created on: Dec 30, 2014 5 | * Author: Minh 6 | */ 7 | #include "wifi.h" 8 | #include "user_interface.h" 9 | #include "osapi.h" 10 | #include "espconn.h" 11 | #include "os_type.h" 12 | #include "mem.h" 13 | 14 | #include "user_config.h" 15 | #include "cmd.h" 16 | #include "debug.h" 17 | 18 | static ETSTimer WiFiLinker; 19 | uint32_t wifiCb = NULL; 20 | static uint8_t wifiStatus = STATION_IDLE, lastWifiStatus = STATION_IDLE; 21 | static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg) 22 | { 23 | struct ip_info ipConfig; 24 | 25 | os_timer_disarm(&WiFiLinker); 26 | wifi_get_ip_info(STATION_IF, &ipConfig); 27 | wifiStatus = wifi_station_get_connect_status(); 28 | if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0) 29 | { 30 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); 31 | os_timer_arm(&WiFiLinker, 2000, 0); 32 | } 33 | else 34 | { 35 | if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD) 36 | { 37 | INFO("STATION_WRONG_PASSWORD\r\n"); 38 | wifi_station_connect(); 39 | } 40 | else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND) 41 | { 42 | INFO("STATION_NO_AP_FOUND\r\n"); 43 | wifi_station_connect(); 44 | } 45 | else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL) 46 | { 47 | INFO("STATION_CONNECT_FAIL\r\n"); 48 | wifi_station_connect(); 49 | } 50 | else 51 | { 52 | INFO("STATION_IDLE\r\n"); 53 | } 54 | 55 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); 56 | os_timer_arm(&WiFiLinker, 500, 0); 57 | } 58 | if(wifiStatus != lastWifiStatus){ 59 | lastWifiStatus = wifiStatus; 60 | if(wifiCb){ 61 | uint16_t crc = CMD_ResponseStart(CMD_WIFI_CONNECT, wifiCb, 0, 1); 62 | crc = CMD_ResponseBody(crc, (uint8_t*)&wifiStatus, 1); 63 | CMD_ResponseEnd(crc); 64 | } 65 | } 66 | } 67 | 68 | uint32_t ICACHE_FLASH_ATTR 69 | WIFI_Connect(PACKET_CMD *cmd) 70 | { 71 | struct station_config stationConf; 72 | uint8_t *ssid, *pwd; 73 | ssid = (uint8_t*)&cmd->args; 74 | pwd = ssid + *(uint16_t*)ssid + 2; 75 | 76 | INFO("WIFI_INIT\r\n"); 77 | 78 | 79 | os_memset(&stationConf, 0, sizeof(struct station_config)); 80 | 81 | os_memcpy(stationConf.ssid, ssid + 2, *(uint16_t*)ssid); 82 | os_memcpy(stationConf.password, pwd + 2, *(uint16_t*)pwd); 83 | 84 | INFO("WIFI: set ssid = %s, pass= %s\r\n", stationConf.ssid, stationConf.password); 85 | wifi_station_set_auto_connect(FALSE); 86 | wifi_set_opmode(STATION_MODE); 87 | 88 | if(cmd->argc != 2 || cmd->callback == 0) 89 | return 0xFFFFFFFF; 90 | 91 | wifiCb = cmd->callback; 92 | wifi_station_set_config(&stationConf); 93 | 94 | os_timer_disarm(&WiFiLinker); 95 | os_timer_setfn(&WiFiLinker, (os_timer_func_t *)wifi_check_ip, NULL); 96 | os_timer_arm(&WiFiLinker, 1000, 0); 97 | 98 | wifi_station_set_auto_connect(TRUE); 99 | wifi_station_connect(); 100 | return 0; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /tools/.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | *.css text eol=lf 3 | *.html text eol=lf 4 | *.js text eol=lf 5 | *.json text eol=lf 6 | *.less text eol=lf 7 | *.md text eol=lf 8 | *.svg text eol=lf 9 | *.yml text eol=lf 10 | *.py text eol=lf 11 | *.sh text eol=lf 12 | -------------------------------------------------------------------------------- /tools/esptool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ESP8266 ROM Bootloader Utility 4 | # https://github.com/themadinventor/esptool 5 | # 6 | # Copyright (C) 2014 Fredrik Ahlberg 7 | # 8 | # This program is free software; you can redistribute it and/or modify it under 9 | # the terms of the GNU General Public License as published by the Free Software 10 | # Foundation; either version 2 of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, but WITHOUT 13 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License along with 17 | # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | # Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | import sys 21 | import struct 22 | import serial 23 | import math 24 | import time 25 | import argparse 26 | import os 27 | import subprocess 28 | 29 | class ESPROM: 30 | 31 | # These are the currently known commands supported by the ROM 32 | ESP_FLASH_BEGIN = 0x02 33 | ESP_FLASH_DATA = 0x03 34 | ESP_FLASH_END = 0x04 35 | ESP_MEM_BEGIN = 0x05 36 | ESP_MEM_END = 0x06 37 | ESP_MEM_DATA = 0x07 38 | ESP_SYNC = 0x08 39 | ESP_WRITE_REG = 0x09 40 | ESP_READ_REG = 0x0a 41 | 42 | # Maximum block sized for RAM and Flash writes, respectively. 43 | ESP_RAM_BLOCK = 0x1800 44 | ESP_FLASH_BLOCK = 0x100 45 | 46 | # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. 47 | ESP_ROM_BAUD = 115200 48 | 49 | # First byte of the application image 50 | ESP_IMAGE_MAGIC = 0xe9 51 | 52 | # Initial state for the checksum routine 53 | ESP_CHECKSUM_MAGIC = 0xef 54 | 55 | # OTP ROM addresses 56 | ESP_OTP_MAC0 = 0x3ff00050 57 | ESP_OTP_MAC1 = 0x3ff00054 58 | 59 | def __init__(self, port = 0, baud = ESP_ROM_BAUD): 60 | self._port = serial.Serial(port, baud) 61 | 62 | """ Read bytes from the serial port while performing SLIP unescaping """ 63 | def read(self, length = 1): 64 | b = '' 65 | while len(b) < length: 66 | c = self._port.read(1) 67 | if c == '\xdb': 68 | c = self._port.read(1) 69 | if c == '\xdc': 70 | b = b + '\xc0' 71 | elif c == '\xdd': 72 | b = b + '\xdb' 73 | else: 74 | raise Exception('Invalid SLIP escape') 75 | else: 76 | b = b + c 77 | return b 78 | 79 | """ Write bytes to the serial port while performing SLIP escaping """ 80 | def write(self, packet): 81 | buf = '\xc0' 82 | for b in packet: 83 | if b == '\xc0': 84 | buf += '\xdb\xdc' 85 | elif b == '\xdb': 86 | buf += '\xdb\xdd' 87 | else: 88 | buf += b 89 | buf += '\xc0' 90 | self._port.write(buf) 91 | 92 | """ Calculate checksum of a blob, as it is defined by the ROM """ 93 | @staticmethod 94 | def checksum(data, state = ESP_CHECKSUM_MAGIC): 95 | for b in data: 96 | state ^= ord(b) 97 | return state 98 | 99 | """ Send a request and read the response """ 100 | def command(self, op = None, data = None, chk = 0): 101 | if op: 102 | # Construct and send request 103 | pkt = struct.pack(' 16: 225 | raise Exception('Invalid firmware image') 226 | 227 | for i in xrange(segments): 228 | (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: 230 | raise Exception('Suspicious segment %x,%d' % (offset, size)) 231 | self.segments.append((offset, size, f.read(size))) 232 | 233 | # Skip the padding. The checksum is stored in the last byte so that the 234 | # file is a multiple of 16 bytes. 235 | align = 15-(f.tell() % 16) 236 | f.seek(align, 1) 237 | 238 | self.checksum = ord(f.read(1)) 239 | 240 | def add_segment(self, addr, data): 241 | # Data should be aligned on word boundary 242 | l = len(data) 243 | if l % 4: 244 | data += b"\x00" * (4 - l % 4) 245 | self.segments.append((addr, len(data), data)) 246 | 247 | def save(self, filename): 248 | f = file(filename, 'wb') 249 | f.write(struct.pack(' 0: 397 | esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) 398 | data = data[esp.ESP_RAM_BLOCK:] 399 | seq += 1 400 | print 'done!' 401 | 402 | print 'All segments done, executing at %08x' % image.entrypoint 403 | esp.mem_finish(image.entrypoint) 404 | 405 | elif args.operation == 'read_mem': 406 | print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address)) 407 | 408 | elif args.operation == 'write_mem': 409 | esp.write_reg(args.address, args.value, args.mask, 0) 410 | print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address) 411 | 412 | elif args.operation == 'dump_mem': 413 | f = file(args.filename, 'wb') 414 | for i in xrange(args.size/4): 415 | d = esp.read_reg(args.address+(i*4)) 416 | f.write(struct.pack(' 0: 434 | print '\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks), 435 | sys.stdout.flush() 436 | block = image[0:esp.ESP_FLASH_BLOCK] 437 | block = block + '\xe0' * (esp.ESP_FLASH_BLOCK-len(block)) 438 | esp.flash_block(block, seq) 439 | image = image[esp.ESP_FLASH_BLOCK:] 440 | seq += 1 441 | print 442 | print '\nLeaving...' 443 | esp.flash_finish(False) 444 | 445 | elif args.operation == 'run': 446 | esp.run() 447 | 448 | elif args.operation == 'image_info': 449 | image = ESPFirmwareImage(args.filename) 450 | print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set' 451 | print '%d segments' % len(image.segments) 452 | print 453 | checksum = ESPROM.ESP_CHECKSUM_MAGIC 454 | for (idx, (offset, size, data)) in enumerate(image.segments): 455 | print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset) 456 | checksum = ESPROM.checksum(data, checksum) 457 | print 458 | print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!') 459 | 460 | elif args.operation == 'make_image': 461 | image = ESPFirmwareImage() 462 | if len(args.segfile) == 0: 463 | raise Exception('No segments specified') 464 | if len(args.segfile) != len(args.segaddr): 465 | raise Exception('Number of specified files does not match number of specified addresses') 466 | for (seg, addr) in zip(args.segfile, args.segaddr): 467 | data = file(seg, 'rb').read() 468 | image.add_segment(addr, data) 469 | image.entrypoint = args.entrypoint 470 | image.save(args.output) 471 | 472 | elif args.operation == 'elf2image': 473 | if args.output is None: 474 | args.output = args.input + '-' 475 | e = ELFFile(args.input) 476 | image = ESPFirmwareImage() 477 | image.entrypoint = e.get_symbol_addr("call_user_start") 478 | for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")): 479 | data = e.load_section(section) 480 | image.add_segment(e.get_symbol_addr(start), data) 481 | image.save(args.output + "0x00000.bin") 482 | data = e.load_section(".irom0.text") 483 | off = e.get_symbol_addr("_irom0_text_start") - 0x40200000 484 | assert off >= 0 485 | f = open(args.output + "0x%05x.bin" % off, "wb") 486 | f.write(data) 487 | f.close() 488 | 489 | elif args.operation == 'read_mac': 490 | mac0 = esp.read_reg(esp.ESP_OTP_MAC0) 491 | mac1 = esp.read_reg(esp.ESP_OTP_MAC1) 492 | print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) 493 | -------------------------------------------------------------------------------- /tools/makefile.sh: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Generate the certificates and keys for encrypt. 4 | # 5 | 6 | # set default cert for use in the client 7 | xxd -i client.cer | sed -e \ 8 | "s/client_cer/default_certificate/" > cert.h 9 | # set default key for use in the server 10 | xxd -i server.key_1024 | sed -e \ 11 | "s/server_key_1024/default_private_key/" > private_key.h 12 | -------------------------------------------------------------------------------- /tools/xxd.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuanpmt/esp_bridge/df889a4050f9f32d456450a32f4d7e5cbd923fe2/tools/xxd.exe -------------------------------------------------------------------------------- /user/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ############################################################# 3 | # Required variables for each makefile 4 | # Discard this section from all parent makefiles 5 | # Expected variables (with automatic defaults): 6 | # CSRCS (all "C" files in the dir) 7 | # SUBDIRS (all subdirs with a Makefile) 8 | # GEN_LIBS - list of libs to be generated () 9 | # GEN_IMAGES - list of images to be generated () 10 | # COMPONENTS_xxx - a list of libs/objs in the form 11 | # subdir/lib to be extracted and rolled up into 12 | # a generated lib/image xxx.a () 13 | # 14 | ifndef PDIR 15 | GEN_LIBS = libuser.a 16 | endif 17 | 18 | 19 | ############################################################# 20 | # Configuration i.e. compile options etc. 21 | # Target specific stuff (defines etc.) goes in here! 22 | # Generally values applying to a tree are captured in the 23 | # makefile at its root level - these are then overridden 24 | # for a subtree within the makefile rooted therein 25 | # 26 | #DEFINES += 27 | 28 | ############################################################# 29 | # Recursion Magic - Don't touch this!! 30 | # 31 | # Each subtree potentially has an include directory 32 | # corresponding to the common APIs applicable to modules 33 | # rooted at that subtree. Accordingly, the INCLUDE PATH 34 | # of a module can only contain the include directories up 35 | # its parent path, and not its siblings 36 | # 37 | # Required for each makefile to inherit from the parent 38 | # 39 | 40 | INCLUDES := $(INCLUDES) -I $(PDIR)include 41 | INCLUDES += -I ./ 42 | INCLUDES += -I ../../rom/include 43 | INCLUDES += -I ../../include/ets 44 | PDIR := ../$(PDIR) 45 | sinclude $(PDIR)Makefile 46 | 47 | -------------------------------------------------------------------------------- /user/main.c: -------------------------------------------------------------------------------- 1 | #include "ets_sys.h" 2 | #include "osapi.h" 3 | #include "user_interface.h" 4 | #include "mem.h" 5 | #include "cmd.h" 6 | #include "driver/uart.h" 7 | 8 | void ICACHE_FLASH_ATTR 9 | bridge_init(void) 10 | { 11 | CMD_Init(); 12 | } 13 | 14 | void ICACHE_FLASH_ATTR 15 | user_init(void) 16 | { 17 | uart_init(BIT_RATE_19200, BIT_RATE_19200); 18 | wifi_station_set_auto_connect(FALSE); 19 | system_init_done_cb(bridge_init); 20 | } 21 | --------------------------------------------------------------------------------