2016-12-19 02:40:21 -05:00
|
|
|
|
/* OTA example
|
|
|
|
|
|
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
|
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
|
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
*/
|
|
|
|
|
#include <string.h>
|
2017-01-06 05:52:58 -05:00
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
|
2016-12-19 02:40:21 -05:00
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "freertos/event_groups.h"
|
|
|
|
|
|
|
|
|
|
#include "esp_system.h"
|
|
|
|
|
#include "esp_wifi.h"
|
|
|
|
|
#include "esp_event_loop.h"
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
#include "esp_ota_ops.h"
|
|
|
|
|
#include "esp_partition.h"
|
|
|
|
|
|
|
|
|
|
#include "nvs_flash.h"
|
|
|
|
|
|
|
|
|
|
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
|
|
|
|
|
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
|
|
|
|
|
#define EXAMPLE_SERVER_IP CONFIG_SERVER_IP
|
|
|
|
|
#define EXAMPLE_SERVER_PORT CONFIG_SERVER_PORT
|
|
|
|
|
#define EXAMPLE_FILENAME CONFIG_EXAMPLE_FILENAME
|
|
|
|
|
#define BUFFSIZE 1024
|
|
|
|
|
#define TEXT_BUFFSIZE 1024
|
|
|
|
|
|
|
|
|
|
static const char *TAG = "ota";
|
|
|
|
|
/*an ota data write buffer ready to write to the flash*/
|
|
|
|
|
char ota_write_data[BUFFSIZE + 1] = { 0 };
|
|
|
|
|
/*an packet receive buffer*/
|
|
|
|
|
char text[BUFFSIZE + 1] = { 0 };
|
|
|
|
|
/* an image total length*/
|
|
|
|
|
int binary_file_length = 0;
|
|
|
|
|
/*socket id*/
|
|
|
|
|
int socket_id = -1;
|
|
|
|
|
char http_request[64] = {0};
|
|
|
|
|
/* operate handle : uninitialized value is zero ,every ota begin would exponential growth*/
|
|
|
|
|
esp_ota_handle_t out_handle = 0;
|
|
|
|
|
esp_partition_t operate_partition;
|
|
|
|
|
|
|
|
|
|
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
|
|
|
|
static EventGroupHandle_t wifi_event_group;
|
|
|
|
|
|
|
|
|
|
/* The event group allows multiple bits for each event,
|
|
|
|
|
but we only care about one event - are we connected
|
|
|
|
|
to the AP with an IP? */
|
|
|
|
|
const int CONNECTED_BIT = BIT0;
|
|
|
|
|
|
|
|
|
|
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
|
|
|
|
{
|
|
|
|
|
switch (event->event_id) {
|
|
|
|
|
case SYSTEM_EVENT_STA_START:
|
|
|
|
|
esp_wifi_connect();
|
|
|
|
|
break;
|
|
|
|
|
case SYSTEM_EVENT_STA_GOT_IP:
|
|
|
|
|
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
|
|
|
|
break;
|
|
|
|
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
|
|
|
|
/* This is a workaround as ESP32 WiFi libs don't currently
|
|
|
|
|
auto-reassociate. */
|
|
|
|
|
esp_wifi_connect();
|
|
|
|
|
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void initialise_wifi(void)
|
|
|
|
|
{
|
|
|
|
|
tcpip_adapter_init();
|
|
|
|
|
wifi_event_group = xEventGroupCreate();
|
|
|
|
|
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
|
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
|
|
|
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
|
|
|
|
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
|
|
|
|
wifi_config_t wifi_config = {
|
|
|
|
|
.sta = {
|
|
|
|
|
.ssid = EXAMPLE_WIFI_SSID,
|
|
|
|
|
.password = EXAMPLE_WIFI_PASS,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
|
|
|
|
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
|
|
|
|
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
|
|
|
|
|
ESP_ERROR_CHECK( esp_wifi_start() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*read buffer by byte still delim ,return read bytes counts*/
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* resolve a packet from http socket
|
|
|
|
|
* return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body
|
|
|
|
|
* otherwise return false
|
|
|
|
|
* */
|
|
|
|
|
bool resolve_pkg(char text[], int total_len, esp_ota_handle_t out_handle)
|
|
|
|
|
{
|
|
|
|
|
/* i means current position */
|
|
|
|
|
int i = 0, i_read_len = 0;
|
|
|
|
|
while (text[i] != 0 && i < total_len) {
|
|
|
|
|
i_read_len = read_until(&text[i], '\n', total_len);
|
|
|
|
|
// if we resolve \r\n line,we think packet header is finished
|
|
|
|
|
if (i_read_len == 2) {
|
|
|
|
|
int i_write_len = total_len - (i + 2);
|
|
|
|
|
memset(ota_write_data, 0, BUFFSIZE);
|
|
|
|
|
/*copy first http packet body to write buffer*/
|
|
|
|
|
memcpy(ota_write_data, &(text[i + 2]), i_write_len);
|
|
|
|
|
/*check write packet header first byte:0xE9 second byte:0x09 */
|
|
|
|
|
if (ota_write_data[0] == 0xE9 && i_write_len >= 2 && ota_write_data[1] == 0x09) {
|
|
|
|
|
ESP_LOGI(TAG, "OTA Write Header format Check OK. first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]);
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "OTA Write Header format Check Failed! first byte is %02x ,second byte is %02x", ota_write_data[0], ota_write_data[1]);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t err = esp_ota_write( out_handle, (const void *)ota_write_data, i_write_len);
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGI(TAG, "esp_ota_write header OK");
|
|
|
|
|
binary_file_length += i_write_len;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
i += i_read_len;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool connect_to_http_server()
|
|
|
|
|
{
|
|
|
|
|
ESP_LOGI(TAG, "Server IP: %s Server Port:%s", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
|
|
|
|
|
sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
|
|
|
|
|
|
|
|
|
|
int http_connect_flag = -1;
|
|
|
|
|
struct sockaddr_in sock_info;
|
|
|
|
|
|
|
|
|
|
socket_id = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
if (socket_id == -1) {
|
|
|
|
|
ESP_LOGE(TAG, "Create socket failed!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set connect info
|
|
|
|
|
memset(&sock_info, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
sock_info.sin_family = AF_INET;
|
|
|
|
|
sock_info.sin_addr.s_addr = inet_addr(EXAMPLE_SERVER_IP);
|
|
|
|
|
sock_info.sin_port = htons(atoi(EXAMPLE_SERVER_PORT));
|
|
|
|
|
|
|
|
|
|
// connect to http server
|
|
|
|
|
http_connect_flag = connect(socket_id, (struct sockaddr *)&sock_info, sizeof(sock_info));
|
|
|
|
|
if (http_connect_flag == -1) {
|
|
|
|
|
ESP_LOGE(TAG, "Connect to server failed! errno=%d", errno);
|
|
|
|
|
close(socket_id);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGI(TAG, "Connected to server");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ota_init()
|
|
|
|
|
{
|
|
|
|
|
esp_err_t err;
|
|
|
|
|
const esp_partition_t *esp_current_partition = esp_ota_get_boot_partition();
|
|
|
|
|
if (esp_current_partition->type != ESP_PARTITION_TYPE_APP) {
|
|
|
|
|
ESP_LOGE(TAG, "Error: esp_current_partition->type != ESP_PARTITION_TYPE_APP");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_partition_t find_partition;
|
|
|
|
|
memset(&operate_partition, 0, sizeof(esp_partition_t));
|
|
|
|
|
/*choose which OTA image should we write to*/
|
|
|
|
|
switch (esp_current_partition->subtype) {
|
|
|
|
|
case ESP_PARTITION_SUBTYPE_APP_FACTORY:
|
|
|
|
|
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0;
|
|
|
|
|
break;
|
|
|
|
|
case ESP_PARTITION_SUBTYPE_APP_OTA_0:
|
|
|
|
|
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_1;
|
|
|
|
|
break;
|
|
|
|
|
case ESP_PARTITION_SUBTYPE_APP_OTA_1:
|
|
|
|
|
find_partition.subtype = ESP_PARTITION_SUBTYPE_APP_OTA_0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
find_partition.type = ESP_PARTITION_TYPE_APP;
|
|
|
|
|
|
|
|
|
|
const esp_partition_t *partition = esp_partition_find_first(find_partition.type, find_partition.subtype, NULL);
|
|
|
|
|
assert(partition != NULL);
|
|
|
|
|
memset(&operate_partition, 0, sizeof(esp_partition_t));
|
|
|
|
|
err = esp_ota_begin( partition, OTA_SIZE_UNKNOWN, &out_handle);
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "esp_ota_begin failed err=0x%x!", err);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(&operate_partition, partition, sizeof(esp_partition_t));
|
|
|
|
|
ESP_LOGI(TAG, "esp_ota_begin init OK");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void __attribute__((noreturn)) task_fatal_error()
|
|
|
|
|
{
|
|
|
|
|
ESP_LOGE(TAG, "Exiting task due to fatal error...");
|
|
|
|
|
close(socket_id);
|
|
|
|
|
(void)vTaskDelete(NULL);
|
2017-01-06 05:52:58 -05:00
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
;
|
|
|
|
|
}
|
2016-12-19 02:40:21 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main_task(void *pvParameter)
|
|
|
|
|
{
|
|
|
|
|
esp_err_t err;
|
|
|
|
|
ESP_LOGI(TAG, "Starting OTA example...");
|
|
|
|
|
/* Wait for the callback to set the CONNECTED_BIT in the
|
|
|
|
|
event group.
|
|
|
|
|
*/
|
|
|
|
|
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
|
|
|
|
false, true, portMAX_DELAY);
|
|
|
|
|
ESP_LOGI(TAG, "Connect to Wifi ! Start to Connect to Server....");
|
|
|
|
|
|
|
|
|
|
/*connect to http server*/
|
|
|
|
|
if (connect_to_http_server()) {
|
|
|
|
|
ESP_LOGI(TAG, "Connected to http server");
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "Connect to http server failed!");
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int res = -1;
|
|
|
|
|
/*send GET request to http server*/
|
|
|
|
|
res = send(socket_id, http_request, strlen(http_request), 0);
|
|
|
|
|
if (res == -1) {
|
|
|
|
|
ESP_LOGE(TAG, "Send GET request to server failed");
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGI(TAG, "Send GET request to server succeeded");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( ota_init() ) {
|
|
|
|
|
ESP_LOGI(TAG, "OTA Init succeeded");
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "OTA Init failed");
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool pkg_body_start = false, flag = true;
|
|
|
|
|
/*deal with all receive packet*/
|
|
|
|
|
while (flag) {
|
|
|
|
|
memset(text, 0, TEXT_BUFFSIZE);
|
|
|
|
|
memset(ota_write_data, 0, BUFFSIZE);
|
|
|
|
|
int buff_len = recv(socket_id, text, TEXT_BUFFSIZE, 0);
|
|
|
|
|
if (buff_len < 0) { /*receive error*/
|
|
|
|
|
ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno);
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
} else if (buff_len > 0 && !pkg_body_start) { /*deal with packet header*/
|
|
|
|
|
memcpy(ota_write_data, text, buff_len);
|
|
|
|
|
pkg_body_start = resolve_pkg(text, buff_len, out_handle);
|
|
|
|
|
} else if (buff_len > 0 && pkg_body_start) { /*deal with packet body*/
|
|
|
|
|
memcpy(ota_write_data, text, buff_len);
|
|
|
|
|
err = esp_ota_write( out_handle, (const void *)ota_write_data, buff_len);
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "Error: esp_ota_write failed! err=%x", err);
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
}
|
|
|
|
|
binary_file_length += buff_len;
|
|
|
|
|
ESP_LOGI(TAG, "Have written image length %d", binary_file_length);
|
|
|
|
|
} else if (buff_len == 0) { /*packet over*/
|
|
|
|
|
flag = false;
|
|
|
|
|
ESP_LOGI(TAG, "Connection closed, all packets received");
|
|
|
|
|
close(socket_id);
|
|
|
|
|
} else {
|
|
|
|
|
ESP_LOGE(TAG, "Unexpected recv result");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length);
|
|
|
|
|
|
|
|
|
|
if (esp_ota_end(out_handle) != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "esp_ota_end failed!");
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
}
|
|
|
|
|
err = esp_ota_set_boot_partition(&operate_partition);
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
|
|
|
|
|
task_fatal_error();
|
|
|
|
|
}
|
|
|
|
|
ESP_LOGI(TAG, "Prepare to restart system!");
|
|
|
|
|
esp_restart();
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void app_main()
|
|
|
|
|
{
|
|
|
|
|
nvs_flash_init();
|
|
|
|
|
initialise_wifi();
|
|
|
|
|
xTaskCreate(&main_task, "main_task", 8192, NULL, 5, NULL);
|
|
|
|
|
}
|