mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-12-15 10:17:49 +08:00
feat(example): add OTA example
1. construct a valid http request header notice: URL path, HTTP version, Host,Accept, Accept-Encoding 2. check http response header notice: state code should be 200, should include Content-Length and application/octet-stream 3. download OTA bin from local OTA server 4. check bin CRC 5. reboot to run new bin if CRC passed 6. add README.md
This commit is contained in:
123
examples/ota_demo/Makefile
Normal file
123
examples/ota_demo/Makefile
Normal file
@@ -0,0 +1,123 @@
|
||||
#############################################################
|
||||
# Required variables for each makefile
|
||||
# Discard this section from all parent makefiles
|
||||
# Expected variables (with automatic defaults):
|
||||
# CSRCS (all "C" files in the dir)
|
||||
# SUBDIRS (all subdirs with a Makefile)
|
||||
# GEN_LIBS - list of libs to be generated ()
|
||||
# GEN_IMAGES - list of object file images to be generated ()
|
||||
# GEN_BINS - list of binaries to be generated ()
|
||||
# COMPONENTS_xxx - a list of libs/objs in the form
|
||||
# subdir/lib to be extracted and rolled up into
|
||||
# a generated lib/image xxx.a ()
|
||||
#
|
||||
TARGET = eagle
|
||||
#FLAVOR = release
|
||||
FLAVOR = debug
|
||||
|
||||
#EXTRA_CCFLAGS += -u
|
||||
|
||||
ifndef PDIR # {
|
||||
GEN_IMAGES= eagle.app.v6.out
|
||||
GEN_BINS= eagle.app.v6.bin
|
||||
SPECIAL_MKTARGETS=$(APP_MKTARGETS)
|
||||
SUBDIRS= \
|
||||
user \
|
||||
ota
|
||||
|
||||
endif # } PDIR
|
||||
|
||||
LDDIR = $(SDK_PATH)/ld
|
||||
|
||||
CCFLAGS += -Os
|
||||
|
||||
TARGET_LDFLAGS = \
|
||||
-nostdlib \
|
||||
-Wl,-EL \
|
||||
--longcalls \
|
||||
--text-section-literals
|
||||
|
||||
ifeq ($(FLAVOR),debug)
|
||||
TARGET_LDFLAGS += -g -O2
|
||||
endif
|
||||
|
||||
ifeq ($(FLAVOR),release)
|
||||
TARGET_LDFLAGS += -g -O0
|
||||
endif
|
||||
|
||||
COMPONENTS_eagle.app.v6 = \
|
||||
user/libuser.a \
|
||||
ota/libota.a
|
||||
|
||||
LINKFLAGS_eagle.app.v6 = \
|
||||
-L$(SDK_PATH)/lib \
|
||||
-Wl,--gc-sections \
|
||||
-nostdlib \
|
||||
-T$(LD_FILE) \
|
||||
-Wl,--no-check-sections \
|
||||
-u call_user_start \
|
||||
-Wl,-static \
|
||||
-Wl,--start-group \
|
||||
-lcirom \
|
||||
-lgcc \
|
||||
-lhal \
|
||||
-lcrypto \
|
||||
-lfreertos \
|
||||
-llwip \
|
||||
-lmain \
|
||||
-lnet80211 \
|
||||
-lphy \
|
||||
-ldriver \
|
||||
-lpp \
|
||||
-lwpa \
|
||||
$(DEP_LIBS_eagle.app.v6)\
|
||||
-Wl,--end-group
|
||||
|
||||
DEPENDS_eagle.app.v6 = \
|
||||
$(LD_FILE) \
|
||||
$(LDDIR)/eagle.rom.addr.v6.ld
|
||||
|
||||
#############################################################
|
||||
# Configuration i.e. compile options etc.
|
||||
# Target specific stuff (defines etc.) goes in here!
|
||||
# Generally values applying to a tree are captured in the
|
||||
# makefile at its root level - these are then overridden
|
||||
# for a subtree within the makefile rooted therein
|
||||
#
|
||||
|
||||
#UNIVERSAL_TARGET_DEFINES = \
|
||||
|
||||
# Other potential configuration flags include:
|
||||
# -DTXRX_TXBUF_DEBUG
|
||||
# -DTXRX_RXBUF_DEBUG
|
||||
# -DWLAN_CONFIG_CCX
|
||||
# -DMQTT_TASK: Define MQTT_TASK to enable MQTT start background
|
||||
# thread for a client.
|
||||
CONFIGURATION_DEFINES = -DICACHE_FLASH
|
||||
|
||||
DEFINES += \
|
||||
$(UNIVERSAL_TARGET_DEFINES) \
|
||||
$(CONFIGURATION_DEFINES)
|
||||
|
||||
DDEFINES += \
|
||||
$(UNIVERSAL_TARGET_DEFINES) \
|
||||
$(CONFIGURATION_DEFINES)
|
||||
|
||||
|
||||
#############################################################
|
||||
# Recursion Magic - Don't touch this!!
|
||||
#
|
||||
# Each subtree potentially has an include directory
|
||||
# corresponding to the common APIs applicable to modules
|
||||
# rooted at that subtree. Accordingly, the INCLUDE PATH
|
||||
# of a module can only contain the include directories up
|
||||
# its parent path, and not its siblings
|
||||
#
|
||||
# Required for each makefile to inherit from the parent
|
||||
#
|
||||
INCLUDES := $(INCLUDES) -I $(PDIR)include
|
||||
sinclude $(SDK_PATH)/Makefile
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
86
examples/ota_demo/README.md
Normal file
86
examples/ota_demo/README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Simple OTA Demo on ESP8266
|
||||
This example demonstrates a working OTA (over the air) firmware update workflow.
|
||||
|
||||
---
|
||||
|
||||
# Introduce
|
||||
there are two areas in flash for system to do OTA: user1 area and user2 area. they work same to each other, backup to each other.
|
||||
for more OTA flash info, please look into [ESP8266 SDK
|
||||
Getting Started Guide](https://www.espressif.com/sites/default/files/documentation/2a-esp8266-sdk_getting_started_guide_en.pdf)
|
||||
|
||||
# Aim
|
||||
Flashing the example over serial with `esptool`. On first startup, the bootloader loads this user bin which then performs an OTA update (triggered in the example code). The update downloads a new user bin from a http server and saves it into the other user bin area. At this point the example code does bin CRC check, prepare to reboot to run new user bin if CRC passed, then the bootloader reads new user bin and runs it.
|
||||
|
||||
|
||||
# Workflow
|
||||
The OTA_workflow.png diagram demonstrates the overall workflow:
|
||||
|
||||

|
||||
|
||||
## Step 1: Connect to AP
|
||||
Connect your host PC to the same AP that you will use for the ESP8266.
|
||||
|
||||
## Step 2: Run HTTP Server
|
||||
Python has a built-in HTTP server that can be used for example purposes.
|
||||
|
||||
For our upgrade example OTA file, we're going to use the `ESP8266_RTOS_SDK/bin/upgrade` to do a cycle OTA workflow.
|
||||
|
||||
Open a new terminal to run the HTTP server, then run these commands to build the example and start the server:
|
||||
|
||||
```
|
||||
cd $SDK_PATH/bin/upgrade
|
||||
python -m SimpleHTTPServer 3344
|
||||
```
|
||||
|
||||
While the server is running, the contents of the directory can be browsed at http://127.0.0.1:3344
|
||||
|
||||
NB: On some systems, the command may be `python2 -m SimpleHTTPServer`.
|
||||
|
||||
If you have any firewall software running that will block incoming access to port 3344, configure it to allow access while running the example.
|
||||
|
||||
## Step 3: Build OTA Example
|
||||
Before compile OTA demo, please change the following details in `include/ota.h` if necessary:
|
||||
|
||||
* WiFi SSID & Password
|
||||
* IP address of your host PC as "HTTP Server"
|
||||
* HTTP Port number (if using the Python HTTP server above, the default is correct)
|
||||
|
||||
Save your changes, and run `./gen_misc.sh` to build the example.
|
||||
|
||||
## Step 4: Flash OTA Example
|
||||
When flashing, use the `esptool` firstly to erase the entire flash. Then flash the user bin over serial.
|
||||
|
||||
|
||||
## Step 5: Run the OTA Example
|
||||
When the example starts up, it will print "local OTA task started..." then demo will follow the steps automatically:
|
||||
|
||||
1. Connect to the AP with configured SSID and password.
|
||||
2. Connect to the HTTP server and download the new user bin.
|
||||
3. Write the new user bin to flash, and configure the next boot.
|
||||
4. check the bin CRC
|
||||
4. Reboot to run new user bin if CRC passed
|
||||
|
||||
# Troubleshooting
|
||||
* Check your PC can ping the ESP8266 at its IP, and that the IP, AP and other configuration settings are correct in `ota.h`.
|
||||
* Check if any firewall software is preventing incoming connections on the PC.
|
||||
|
||||
## Production Implementation
|
||||
|
||||
If scaling this example for production use, please consider:
|
||||
|
||||
* Dealing with timeouts or WiFi disconnections while flashing.
|
||||
|
||||
# Adapter to your OTA scene
|
||||
if change the demo to your OTA environment, please notice the following details.
|
||||
|
||||
1). OTA always was triggered passively, please change the necessary workflow to do OTA
|
||||
2). do a domain name resolution of OTA server by `netconn_gethostbyname` to fetch a OTA IP address in real scene
|
||||
3). must modify HTTP request according to your OTA server, you could use the firefox and wireshark to debug HTTP request
|
||||
- escape the URL path if necessary
|
||||
- there is always a slash at the beginning of the URL
|
||||
- support HTTP version: `HTTP/1.0` or `HTTP/1.1`
|
||||
- change `Host` item to your domain name/port according to your OTA server
|
||||
- OTA server should transmit a Content-Type `application/octet-stream` according to `Accept` item
|
||||
- OTA server should not encrypt the http body according to `Accept-Encoding` item
|
||||
- new use bin size is decided by `Content-Length` Item
|
||||
- `recv malformed http header` means that http server tranmits a http header item without `\r\n` end before ESP8266 receives the `\r\n\r\n`
|
||||
BIN
examples/ota_demo/_static/OTA_workflow.png
Normal file
BIN
examples/ota_demo/_static/OTA_workflow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
191
examples/ota_demo/gen_misc.sh
Executable file
191
examples/ota_demo/gen_misc.sh
Executable file
@@ -0,0 +1,191 @@
|
||||
#!/bin/bash
|
||||
|
||||
:<<!
|
||||
******NOTICE******
|
||||
MUST set SDK_PATH & BIN_PATH firstly!!!
|
||||
example:
|
||||
export SDK_PATH=~/esp_iot_sdk_freertos
|
||||
export BIN_PATH=~/esp8266_bin
|
||||
!
|
||||
|
||||
export SDK_PATH=$SDK_PATH
|
||||
export BIN_PATH=$BIN_PATH
|
||||
|
||||
echo "gen_misc.sh version 20150911"
|
||||
echo ""
|
||||
|
||||
if [ $SDK_PATH ]; then
|
||||
echo "SDK_PATH:"
|
||||
echo "$SDK_PATH"
|
||||
echo ""
|
||||
else
|
||||
echo "ERROR: Please export SDK_PATH in gen_misc.sh firstly, exit!!!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ $BIN_PATH ]; then
|
||||
echo "BIN_PATH:"
|
||||
echo "$BIN_PATH"
|
||||
echo ""
|
||||
else
|
||||
echo "ERROR: Please export BIN_PATH in gen_misc.sh firstly, exit!!!"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Please check SDK_PATH & BIN_PATH, enter (Y/y) to continue:"
|
||||
read input
|
||||
|
||||
if [[ $input != Y ]] && [[ $input != y ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo "Please follow below steps(1-5) to generate specific bin(s):"
|
||||
echo "STEP 1: use boot_v1.2+ by default"
|
||||
boot=new
|
||||
|
||||
echo "boot mode: $boot"
|
||||
echo ""
|
||||
|
||||
echo "STEP 2: choose bin generate(0=eagle.flash.bin+eagle.irom0text.bin, 1=user1.bin, 2=user2.bin)"
|
||||
echo "enter (0/1/2, default 0):"
|
||||
read input
|
||||
|
||||
if [ -z "$input" ]; then
|
||||
if [ $boot != none ]; then
|
||||
boot=none
|
||||
echo "ignore boot"
|
||||
fi
|
||||
app=0
|
||||
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
|
||||
elif [ $input == 1 ]; then
|
||||
if [ $boot == none ]; then
|
||||
app=0
|
||||
echo "choose no boot before"
|
||||
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
|
||||
else
|
||||
app=1
|
||||
echo "generate bin: user1.bin"
|
||||
fi
|
||||
elif [ $input == 2 ]; then
|
||||
if [ $boot == none ]; then
|
||||
app=0
|
||||
echo "choose no boot before"
|
||||
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
|
||||
else
|
||||
app=2
|
||||
echo "generate bin: user2.bin"
|
||||
fi
|
||||
else
|
||||
if [ $boot != none ]; then
|
||||
boot=none
|
||||
echo "ignore boot"
|
||||
fi
|
||||
app=0
|
||||
echo "generate bin: eagle.flash.bin+eagle.irom0text.bin"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo "STEP 3: choose spi speed(0=20MHz, 1=26.7MHz, 2=40MHz, 3=80MHz)"
|
||||
echo "enter (0/1/2/3, default 2):"
|
||||
read input
|
||||
|
||||
if [ -z "$input" ]; then
|
||||
spi_speed=40
|
||||
elif [ $input == 0 ]; then
|
||||
spi_speed=20
|
||||
elif [ $input == 1 ]; then
|
||||
spi_speed=26.7
|
||||
elif [ $input == 3 ]; then
|
||||
spi_speed=80
|
||||
else
|
||||
spi_speed=40
|
||||
fi
|
||||
|
||||
echo "spi speed: $spi_speed MHz"
|
||||
echo ""
|
||||
|
||||
echo "STEP 4: choose spi mode(0=QIO, 1=QOUT, 2=DIO, 3=DOUT)"
|
||||
echo "enter (0/1/2/3, default 0):"
|
||||
read input
|
||||
|
||||
if [ -z "$input" ]; then
|
||||
spi_mode=QIO
|
||||
elif [ $input == 1 ]; then
|
||||
spi_mode=QOUT
|
||||
elif [ $input == 2 ]; then
|
||||
spi_mode=DIO
|
||||
elif [ $input == 3 ]; then
|
||||
spi_mode=DOUT
|
||||
else
|
||||
spi_mode=QIO
|
||||
fi
|
||||
|
||||
echo "spi mode: $spi_mode"
|
||||
echo ""
|
||||
|
||||
echo "STEP 5: choose spi size and map"
|
||||
echo " 0= 512KB( 256KB+ 256KB)"
|
||||
echo " 2=1024KB( 512KB+ 512KB)"
|
||||
echo " 3=2048KB( 512KB+ 512KB)"
|
||||
echo " 4=4096KB( 512KB+ 512KB)"
|
||||
echo " 5=2048KB(1024KB+1024KB)"
|
||||
echo " 6=4096KB(1024KB+1024KB)"
|
||||
echo " 7=4096KB(2048KB+2048KB) not support ,just for compatible with nodeMCU board"
|
||||
echo " 8=8192KB(1024KB+1024KB)"
|
||||
echo " 9=16384KB(1024KB+1024KB)"
|
||||
echo "enter (0/2/3/4/5/6/7/8/9, default 0):"
|
||||
read input
|
||||
|
||||
if [ -z "$input" ]; then
|
||||
spi_size_map=0
|
||||
echo "spi size: 512KB"
|
||||
echo "spi ota map: 256KB + 256KB"
|
||||
elif [ $input == 2 ]; then
|
||||
spi_size_map=2
|
||||
echo "spi size: 1024KB"
|
||||
echo "spi ota map: 512KB + 512KB"
|
||||
elif [ $input == 3 ]; then
|
||||
spi_size_map=3
|
||||
echo "spi size: 2048KB"
|
||||
echo "spi ota map: 512KB + 512KB"
|
||||
elif [ $input == 4 ]; then
|
||||
spi_size_map=4
|
||||
echo "spi size: 4096KB"
|
||||
echo "spi ota map: 512KB + 512KB"
|
||||
elif [ $input == 5 ]; then
|
||||
spi_size_map=5
|
||||
echo "spi size: 2048KB"
|
||||
echo "spi ota map: 1024KB + 1024KB"
|
||||
elif [ $input == 6 ]; then
|
||||
spi_size_map=6
|
||||
echo "spi size: 4096KB"
|
||||
echo "spi ota map: 1024KB + 1024KB"
|
||||
elif [ $input == 7 ]; then
|
||||
spi_size_map=7
|
||||
echo"not support ,just for compatible with nodeMCU board"
|
||||
exit
|
||||
elif [ $input == 8 ]; then
|
||||
spi_size_map=8
|
||||
echo "spi size: 8192KB"
|
||||
echo "spi ota map: 1024KB + 1024KB"
|
||||
elif [ $input == 9 ]; then
|
||||
spi_size_map=9
|
||||
echo "spi size: 16384KB"
|
||||
echo "spi ota map: 1024KB + 1024KB"
|
||||
else
|
||||
spi_size_map=0
|
||||
echo "spi size: 512KB"
|
||||
echo "spi ota map: 256KB + 256KB"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo "start..."
|
||||
echo ""
|
||||
|
||||
make clean
|
||||
|
||||
make BOOT=$boot APP=$app SPI_SPEED=$spi_speed SPI_MODE=$spi_mode SPI_SIZE_MAP=$spi_size_map
|
||||
44
examples/ota_demo/include/ota.h
Normal file
44
examples/ota_demo/include/ota.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2018 <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 OTA_H_
|
||||
#define OTA_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// WiFi
|
||||
#define WIFI_SSID "BL_841R" // type:string, your AP/router SSID to config your device networking
|
||||
#define WIFI_PASSWORD "1234567890" // type:string, your AP/router password
|
||||
|
||||
// OTA
|
||||
#define LOCAL_OTA_SERVER_IP "192.168.111.104" // local OTA server ip
|
||||
#define LOCAL_OTA_SERVER_PORT 3344 // local OTA server port
|
||||
#define OTA_TIMEOUT 120000
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
45
examples/ota_demo/ota/Makefile
Normal file
45
examples/ota_demo/ota/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
#############################################################
|
||||
# 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
|
||||
UP_EXTRACT_DIR = ..
|
||||
GEN_LIBS = libota.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 ../include
|
||||
PDIR := ../$(PDIR)
|
||||
sinclude $(PDIR)Makefile
|
||||
|
||||
533
examples/ota_demo/ota/local_ota.c
Normal file
533
examples/ota_demo/ota/local_ota.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2018 <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 <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_system.h"
|
||||
#include "spi_flash.h"
|
||||
#include "upgrade.h"
|
||||
|
||||
#include "ota.h"
|
||||
|
||||
static bool http_200_check = false; // http state code
|
||||
static bool resp_body_start = false; // whether http header over
|
||||
static uint32_t download_length = 0; // current download length
|
||||
static int content_len = 0; // parsed by Content-Length item
|
||||
static char *content_type = NULL; // Content-type should be bin type(application/octet-stream)
|
||||
|
||||
extern int got_ip_flag;
|
||||
static struct upgrade_param *upgrade;
|
||||
|
||||
struct upgrade_param {
|
||||
uint32_t fw_bin_addr;
|
||||
uint16_t fw_bin_sec;
|
||||
uint16_t fw_bin_sec_num;
|
||||
uint16_t fw_bin_sec_earse;
|
||||
uint8_t extra;
|
||||
uint8_t save[4];
|
||||
uint8_t *buffer;
|
||||
};
|
||||
|
||||
static void __attribute__((noreturn)) task_fatal_error()
|
||||
{
|
||||
printf("Exiting task due to fatal error...\n");
|
||||
(void)vTaskDelete(NULL);
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static bool OUT_OF_RANGE(uint16 erase_sec)
|
||||
{
|
||||
uint8_t spi_size_map = system_get_flash_size_map();
|
||||
uint16_t sec_num = 0;
|
||||
uint16_t start_sec = 0;
|
||||
|
||||
if (spi_size_map == FLASH_SIZE_8M_MAP_512_512 ||
|
||||
spi_size_map == FLASH_SIZE_16M_MAP_512_512 ||
|
||||
spi_size_map == FLASH_SIZE_32M_MAP_512_512) {
|
||||
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 129;
|
||||
sec_num = 123;
|
||||
} else if (spi_size_map == FLASH_SIZE_16M_MAP_1024_1024 ||
|
||||
spi_size_map == FLASH_SIZE_32M_MAP_1024_1024) {
|
||||
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 257;
|
||||
sec_num = 251;
|
||||
} else {
|
||||
start_sec = (system_upgrade_userbin_check() == USER_BIN2) ? 1 : 65;
|
||||
sec_num = 59;
|
||||
}
|
||||
|
||||
if ((erase_sec >= start_sec) && (erase_sec <= (start_sec + sec_num))) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : user_upgrade_internal
|
||||
* Description : a
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
static bool system_upgrade_internal(struct upgrade_param *upgrade, uint8_t *data, u32_t len)
|
||||
{
|
||||
bool ret = false;
|
||||
uint16_t secnm = 0;
|
||||
|
||||
if (data == NULL || len == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*got the sumlngth,erase all upgrade sector*/
|
||||
if (len > SPI_FLASH_SEC_SIZE) {
|
||||
upgrade->fw_bin_sec_earse = upgrade->fw_bin_sec;
|
||||
|
||||
secnm = ((upgrade->fw_bin_addr + len) >> 12) + (len & 0xfff ? 1 : 0);
|
||||
|
||||
while (upgrade->fw_bin_sec_earse != secnm) {
|
||||
taskENTER_CRITICAL();
|
||||
|
||||
if (OUT_OF_RANGE(upgrade->fw_bin_sec_earse)) {
|
||||
printf("fw_bin_sec_earse:%d, Out of range\n", upgrade->fw_bin_sec_earse);
|
||||
break;
|
||||
|
||||
} else {
|
||||
spi_flash_erase_sector(upgrade->fw_bin_sec_earse);
|
||||
upgrade->fw_bin_sec_earse++;
|
||||
}
|
||||
|
||||
taskEXIT_CRITICAL();
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
printf("flash erase over\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
upgrade->buffer = (uint8_t *)calloc(1, len + upgrade->extra);
|
||||
|
||||
memcpy(upgrade->buffer, upgrade->save, upgrade->extra);
|
||||
memcpy(upgrade->buffer + upgrade->extra, data, len);
|
||||
|
||||
len += upgrade->extra;
|
||||
upgrade->extra = len & 0x03;
|
||||
len -= upgrade->extra;
|
||||
|
||||
if (upgrade->extra <= 4) {
|
||||
memcpy(upgrade->save, upgrade->buffer + len, upgrade->extra);
|
||||
} else {
|
||||
printf("ERR3:arr_overflow,%u,%d\n", __LINE__, upgrade->extra);
|
||||
}
|
||||
|
||||
do {
|
||||
if (upgrade->fw_bin_addr + len >= (upgrade->fw_bin_sec + upgrade->fw_bin_sec_num) * SPI_FLASH_SEC_SIZE) {
|
||||
printf("spi_flash_write exceed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (spi_flash_write(upgrade->fw_bin_addr, (uint32 *)upgrade->buffer, len) != SPI_FLASH_RESULT_OK) {
|
||||
printf("spi_flash_write failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
upgrade->fw_bin_addr += len;
|
||||
} while (0);
|
||||
|
||||
free(upgrade->buffer);
|
||||
upgrade->buffer = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : system_get_fw_start_sec
|
||||
* Description : a
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
uint16_t system_get_fw_start_sec()
|
||||
{
|
||||
if (upgrade != NULL) {
|
||||
return upgrade->fw_bin_sec;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : user_upgrade
|
||||
* Description : a
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
bool system_upgrade(uint8_t *data, uint32_t len)
|
||||
{
|
||||
bool ret;
|
||||
ret = system_upgrade_internal(upgrade, data, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void upgrade_recycle(void)
|
||||
{
|
||||
printf("upgrade recycle\n");
|
||||
download_length = 0;
|
||||
http_200_check = false;
|
||||
resp_body_start = false;
|
||||
content_len = 0;
|
||||
content_type = NULL;
|
||||
system_upgrade_deinit();
|
||||
|
||||
if (system_upgrade_flag_check() == UPGRADE_FLAG_FINISH) {
|
||||
system_upgrade_reboot(); // if need
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : system_upgrade_init
|
||||
* Description : a
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void system_upgrade_init(void)
|
||||
{
|
||||
uint32_t user_bin2_start, user_bin1_start;
|
||||
uint8_t spi_size_map = system_get_flash_size_map();
|
||||
|
||||
if (upgrade == NULL) {
|
||||
upgrade = (struct upgrade_param *)calloc(1, sizeof(struct upgrade_param));
|
||||
}
|
||||
|
||||
user_bin1_start = 1;
|
||||
|
||||
if (spi_size_map == FLASH_SIZE_8M_MAP_512_512 ||
|
||||
spi_size_map == FLASH_SIZE_16M_MAP_512_512 ||
|
||||
spi_size_map == FLASH_SIZE_32M_MAP_512_512) {
|
||||
user_bin2_start = 129;
|
||||
upgrade->fw_bin_sec_num = 123;
|
||||
} else if (spi_size_map == FLASH_SIZE_16M_MAP_1024_1024 ||
|
||||
spi_size_map == FLASH_SIZE_32M_MAP_1024_1024) {
|
||||
user_bin2_start = 257;
|
||||
upgrade->fw_bin_sec_num = 251;
|
||||
} else {
|
||||
user_bin2_start = 65;
|
||||
upgrade->fw_bin_sec_num = 59;
|
||||
}
|
||||
|
||||
upgrade->fw_bin_sec = (system_upgrade_userbin_check() == USER_BIN1) ? user_bin2_start : user_bin1_start;
|
||||
|
||||
upgrade->fw_bin_addr = upgrade->fw_bin_sec * SPI_FLASH_SEC_SIZE;
|
||||
|
||||
upgrade->fw_bin_sec_earse = upgrade->fw_bin_sec;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : system_upgrade_deinit
|
||||
* Description : a
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void system_upgrade_deinit(void)
|
||||
{
|
||||
if (upgrade != NULL) {
|
||||
free(upgrade);
|
||||
upgrade = NULL;
|
||||
}
|
||||
|
||||
printf("ota end, free heap size:%d\n", system_get_free_heap_size());
|
||||
return;
|
||||
}
|
||||
|
||||
/*read buffer by byte still delim ,return read bytes counts*/
|
||||
static int read_until(char *buffer, char delim, int len)
|
||||
{
|
||||
// /*TODO: delim check,buffer check,further: do an buffer length limited*/
|
||||
int i = 0;
|
||||
|
||||
while (buffer[i] != delim && i < len) {
|
||||
++i;
|
||||
}
|
||||
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
bool read_past_http_header(char text[], int total_len)
|
||||
{
|
||||
/* i means current position */
|
||||
int i = 0, i_read_len = 0;
|
||||
char *ptr = NULL, *ptr2 = NULL;
|
||||
char length_str[32] = {0};
|
||||
|
||||
while (text[i] != 0 && i < total_len) {
|
||||
if (content_len == 0 && (ptr = (char *)strstr(text, "Content-Length")) != NULL) {
|
||||
ptr += 16;
|
||||
ptr2 = (char *)strstr(ptr, "\r\n");
|
||||
memset(length_str, 0, sizeof(length_str));
|
||||
memcpy(length_str, ptr, ptr2 - ptr);
|
||||
content_len = atoi(length_str);
|
||||
printf("parse Content-Length:%d\n", content_len);
|
||||
}
|
||||
|
||||
if (content_type == NULL) {
|
||||
content_type = (char *)strstr(text, "application/octet-stream");
|
||||
}
|
||||
|
||||
i_read_len = read_until(&text[i], '\n', total_len - i);
|
||||
|
||||
if (i_read_len > total_len - i) {
|
||||
printf("recv malformed http header\n");
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
// if resolve \r\n line, http header is finished
|
||||
if (i_read_len == 2) {
|
||||
if (content_len == 0) {
|
||||
printf("did not parse Content-Length item\n");
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
if (content_type == NULL) {
|
||||
printf("server did not return \"Content-type: application/octet-stream\"\n");
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
// erase flash when first flash, for save new bin
|
||||
if (false == system_upgrade(text, content_len)) {
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
// the valid left http body length
|
||||
int i_write_len = total_len - (i + 2);
|
||||
|
||||
if (false == system_upgrade(&(text[i + 2]), i_write_len)) {
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
printf("system upgrade error");
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
download_length += i_write_len;
|
||||
printf("first download len:%d\n", download_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
i += i_read_len;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : upgrade_download
|
||||
* Description : parse http response ,and download remote data and write in flash
|
||||
* Parameters : int sta_socket : ota client socket fd
|
||||
* char *pusrdata : remote data
|
||||
* length : data length
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void upgrade_download(int sta_socket, char *pusrdata, unsigned short length)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
char *ptmp2 = NULL;
|
||||
char lengthbuffer[32];
|
||||
|
||||
// first response should include state code:200
|
||||
if (!http_200_check && strstr(pusrdata, "200") == NULL) {
|
||||
printf("ota url is invalid or bin is not exist");
|
||||
task_fatal_error();
|
||||
}
|
||||
|
||||
http_200_check = true;
|
||||
|
||||
if (!resp_body_start) {
|
||||
// deal with http header
|
||||
resp_body_start = read_past_http_header(pusrdata, length);
|
||||
return;
|
||||
}
|
||||
|
||||
// deal with http body
|
||||
// http transmit body more than content-length occasionally
|
||||
// default bin size = content-length, throw up the other http body
|
||||
if (download_length + length > content_len) {
|
||||
length = content_len - download_length;
|
||||
download_length = content_len;
|
||||
} else {
|
||||
download_length += length;
|
||||
}
|
||||
|
||||
printf("downloaded len:%d\n", download_length);
|
||||
|
||||
// save http body(bin) to flash
|
||||
if (false == system_upgrade(pusrdata, length)) {
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : local_ota_begin
|
||||
* Description : ota_task function
|
||||
* Parameters : task param
|
||||
* Returns : none
|
||||
*******************************************************************************/
|
||||
void local_ota_begin()
|
||||
{
|
||||
int read_bytes;
|
||||
int sin_size;
|
||||
int sta_socket;
|
||||
char recv_buf[1460];
|
||||
uint8_t user_bin[21] = {0};
|
||||
struct sockaddr_in remote_ip;
|
||||
printf("Hello, welcome to local ota!\r\n");
|
||||
printf("ota server addr %s port %d\n", LOCAL_OTA_SERVER_IP, LOCAL_OTA_SERVER_PORT);
|
||||
|
||||
while (1) {
|
||||
sta_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (-1 == sta_socket) {
|
||||
close(sta_socket);
|
||||
printf("socket fail !\r\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("socket ok!\r\n");
|
||||
bzero(&remote_ip, sizeof(struct sockaddr_in));
|
||||
remote_ip.sin_family = AF_INET;
|
||||
|
||||
remote_ip.sin_addr.s_addr = inet_addr(LOCAL_OTA_SERVER_IP);
|
||||
remote_ip.sin_port = htons(LOCAL_OTA_SERVER_PORT);
|
||||
|
||||
if (0 != connect(sta_socket, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr))) {
|
||||
close(sta_socket);
|
||||
printf("connect fail!\r\n");
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("connect ok!\r\n");
|
||||
|
||||
if (system_upgrade_userbin_check() == UPGRADE_FW_BIN1) {
|
||||
memcpy(user_bin, "user2.2048.new.5.bin", 21);
|
||||
|
||||
} else if (system_upgrade_userbin_check() == UPGRADE_FW_BIN2) {
|
||||
memcpy(user_bin, "user1.2048.new.5.bin", 21);
|
||||
}
|
||||
|
||||
/*send GET request to http server*/
|
||||
const char *GET_FORMAT =
|
||||
"GET %s HTTP/1.0\r\n"
|
||||
"Host: %s:%d\r\n"
|
||||
"Accept: application/octet-stream\r\n"
|
||||
"Accept-Encoding: identity\r\n"
|
||||
"User-Agent: esp8266-rtos-sdk/1.0 esp8266\r\n\r\n";
|
||||
|
||||
char *http_request = NULL;
|
||||
int get_len = asprintf(&http_request, GET_FORMAT, user_bin, LOCAL_OTA_SERVER_IP, LOCAL_OTA_SERVER_PORT);
|
||||
|
||||
if (get_len < 0) {
|
||||
printf("malloc memory failed.\n");
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
free(http_request);
|
||||
close(sta_socket);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (write(sta_socket, http_request, strlen(http_request) + 1) < 0) {
|
||||
close(sta_socket);
|
||||
printf("send fail\n");
|
||||
free(http_request);
|
||||
upgrade_recycle();
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("send success\n");
|
||||
free(http_request);
|
||||
|
||||
while ((read_bytes = read(sta_socket , recv_buf, 1460)) >= 0) {
|
||||
if (read_bytes > 0) {
|
||||
upgrade_download(sta_socket, recv_buf, read_bytes);
|
||||
} else {
|
||||
printf("peer close socket\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// default bin size equal to content-length
|
||||
if (download_length == content_len && download_length != 0) {
|
||||
printf("upgrade file download finished, bin size:%d\n", download_length);
|
||||
|
||||
if (upgrade_crc_check(system_get_fw_start_sec(), download_length) != true) {
|
||||
printf("upgrade crc check failed !\n");
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
} else {
|
||||
printf("bin check crc ok\n");
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
|
||||
}
|
||||
|
||||
upgrade_recycle();
|
||||
}
|
||||
}
|
||||
|
||||
printf("read data fail! ret:%d\r\n", read_bytes);
|
||||
close(sta_socket);
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
|
||||
upgrade_recycle();
|
||||
}
|
||||
}
|
||||
|
||||
// local_ota_task
|
||||
void local_ota_task(void *pvParameter)
|
||||
{
|
||||
os_timer_t upgrade_timer;
|
||||
printf("\nlocal OTA task started...\n");
|
||||
|
||||
while (!got_ip_flag) {
|
||||
vTaskDelay(2000 / portTICK_RATE_MS);
|
||||
printf("wait for fetching IP...\n");
|
||||
}
|
||||
|
||||
printf("ota begin, free heap size:%d\n", system_get_free_heap_size());
|
||||
system_upgrade_flag_set(UPGRADE_FLAG_START);
|
||||
system_upgrade_init();
|
||||
|
||||
local_ota_begin();
|
||||
|
||||
// OTA timeout, shutdown OTA
|
||||
os_timer_disarm(&upgrade_timer);
|
||||
os_timer_setfn(&upgrade_timer, (os_timer_func_t *)upgrade_recycle, NULL);
|
||||
os_timer_arm(&upgrade_timer, OTA_TIMEOUT, 0);
|
||||
}
|
||||
159
examples/ota_demo/ota/upgrade_check_api.c
Normal file
159
examples/ota_demo/ota/upgrade_check_api.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2018 <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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "c_types.h"
|
||||
#include "spi_flash.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#define BUFSIZE 512
|
||||
#define CRC_BLOCK_SIZE 512
|
||||
|
||||
uint32_t start_sec;
|
||||
static uint32_t *crc_table;
|
||||
|
||||
static int init_crc_table(void);
|
||||
|
||||
static uint32_t crc32(uint32_t crc, unsigned char *buffer, uint32_t size);
|
||||
|
||||
static int init_crc_table(void)
|
||||
{
|
||||
uint32_t c;
|
||||
uint32_t i, j;
|
||||
|
||||
crc_table = (uint32_t *)calloc(1, 256 * 4);
|
||||
|
||||
if (crc_table == NULL) {
|
||||
printf("malloc crc table failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
c = (uint32_t)i;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (c & 1) {
|
||||
c = 0xedb88320L ^ (c >> 1);
|
||||
} else {
|
||||
c = c >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc_table[i] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t crc32(uint32_t crc, unsigned char *buffer, uint32_t size)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ;
|
||||
}
|
||||
|
||||
static int calc_img_crc(uint32_t sumlength, uint32_t *img_crc)
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
int i = 0;
|
||||
uint8 error = 0;
|
||||
unsigned char *buf = (char *)calloc(1, BUFSIZE);
|
||||
|
||||
if (buf == NULL) {
|
||||
printf("malloc crc buf failed\n");
|
||||
free(crc_table);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
uint16_t sec_block = sumlength / CRC_BLOCK_SIZE ;
|
||||
uint32_t sec_last = sumlength % CRC_BLOCK_SIZE;
|
||||
|
||||
for (i = 0; i < sec_block; i++) {
|
||||
if (0 != (error = spi_flash_read(start_sec * SPI_FLASH_SEC_SIZE + i * CRC_BLOCK_SIZE , (uint32 *)buf, BUFSIZE))) {
|
||||
free(crc_table);
|
||||
free(buf);
|
||||
printf("spi_flash_read error %d\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
crc = crc32(crc, buf, BUFSIZE);
|
||||
}
|
||||
|
||||
if (sec_last > 0) {
|
||||
if (0 != (error = spi_flash_read(start_sec * SPI_FLASH_SEC_SIZE + i * CRC_BLOCK_SIZE, (uint32 *)buf, sec_last))) {
|
||||
free(crc_table);
|
||||
free(buf);
|
||||
printf("spi_flash_read error %d\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
crc = crc32(crc, buf, sec_last);
|
||||
}
|
||||
|
||||
*img_crc = crc;
|
||||
free(crc_table);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool upgrade_crc_check(uint16 fw_bin_sec , uint32_t sumlength)
|
||||
{
|
||||
int ret;
|
||||
uint32_t img_crc;
|
||||
uint32_t flash_crc = 0xFF;
|
||||
start_sec = fw_bin_sec;
|
||||
|
||||
printf("fw_bin_sec %d sumlength %d\n", fw_bin_sec, sumlength);
|
||||
|
||||
if (0 != init_crc_table()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = calc_img_crc(sumlength - 4, &img_crc);
|
||||
|
||||
if (ret < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
img_crc = abs(img_crc);
|
||||
printf("img_crc = %u\n", img_crc);
|
||||
spi_flash_read(start_sec * SPI_FLASH_SEC_SIZE + sumlength - 4, &flash_crc, 4);
|
||||
printf("flash_crc = %u\n", flash_crc);
|
||||
|
||||
if (img_crc == flash_crc) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
44
examples/ota_demo/user/Makefile
Normal file
44
examples/ota_demo/user/Makefile
Normal file
@@ -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
|
||||
|
||||
134
examples/ota_demo/user/user_main.c
Normal file
134
examples/ota_demo/user/user_main.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* ESPRESSIF MIT License
|
||||
*
|
||||
* Copyright (c) 2018 <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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "esp_sta.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#include "ota.h"
|
||||
|
||||
int got_ip_flag = 0;
|
||||
|
||||
extern void local_ota_task(void *pvParameter);
|
||||
|
||||
/******************************************************************************
|
||||
* 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_t user_rf_cal_sector_set(void)
|
||||
{
|
||||
flash_size_map size_map = system_get_flash_size_map();
|
||||
uint32_t 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;
|
||||
|
||||
case FLASH_SIZE_64M_MAP_1024_1024:
|
||||
rf_cal_sec = 2048 - 5;
|
||||
break;
|
||||
|
||||
case FLASH_SIZE_128M_MAP_1024_1024:
|
||||
rf_cal_sec = 4096 - 5;
|
||||
break;
|
||||
|
||||
default:
|
||||
rf_cal_sec = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return rf_cal_sec;
|
||||
}
|
||||
|
||||
// WiFi callback function
|
||||
void event_handler(System_Event_t *event)
|
||||
{
|
||||
switch (event->event_id) {
|
||||
case EVENT_STAMODE_GOT_IP:
|
||||
printf("WiFi connected\n");
|
||||
got_ip_flag = 1;
|
||||
break;
|
||||
|
||||
case EVENT_STAMODE_DISCONNECTED:
|
||||
printf("WiFi disconnected, try to connect...\n");
|
||||
got_ip_flag = 0;
|
||||
wifi_station_connect();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_wifi(void)
|
||||
{
|
||||
wifi_set_opmode(STATION_MODE);
|
||||
|
||||
// set AP parameter
|
||||
struct station_config config;
|
||||
bzero(&config, sizeof(struct station_config));
|
||||
sprintf(config.ssid, WIFI_SSID);
|
||||
sprintf(config.password, WIFI_PASSWORD);
|
||||
wifi_station_set_config(&config);
|
||||
|
||||
wifi_station_set_auto_connect(true);
|
||||
wifi_station_set_reconnect_policy(true);
|
||||
wifi_set_event_handler_cb(event_handler);
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
initialize_wifi();
|
||||
|
||||
if (xTaskCreate(local_ota_task, "main_process", 1024, NULL, 5, NULL) != pdPASS) {
|
||||
printf("lota create failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user