ESP8285 RTOS SDK OTA

一、官方资源说明

官方指南:空中升级 (OTA) - ESP32 - — ESP-IDF 编程指南 v4.3.6 文档,虽然是正对ESP32的,但是原理是一样的。

官方参考例程:esp-idf\ESP8266_RTOS_SDK\examples\system\ota\,其中包含两个例程,一个是simple_ota_example,另一个是native_ota。simple_ota_example例程调用的是封装之后函数,只需要将固件的下载地址传入函数即可自动完成升级,而native_ota调用的是原生的函数,有更多的过程,详细展示了OTA的下载、存储过程以及校验。这里以simple_ota_example为例进行讲解。

二、修改配置文件

1、修改Partition Table

使用带ota分区的Partition Table,在flash区域中划出两块app存储空间,一块区域是当前运行的app区,另一块区域是新下载的app存放的区域。进入到工程目录中,执行make menuconfig,然后选择

Partition Table  --->

        Partition Table (Single factory app, no OTA)  --->  

                        (X) Factory app, two OTA definitions

2、允许http方式进行ota

此方式不需要证书,更简单。

 Component config  ---> 

        ESP HTTPS OTA  --->

                 [*] Allow HTTP for OTA (WARNING: ONLY FOR TESTING PURPOSE, READ HELP)  

三、编写代码

1、升级流程

上电->进入app_main()->创建升级任务(simple_ota_example_task)->执行任务->等待wifi连接并获取IP地址->http请求服务器上的固件版本号->与当前运行版本号进行比较->如果服务器上的固件版本号更高->下载新的固件->下载完成之后重启设备。

2、代码

版本比较函数

/**
  * @brief  None.
  * @param  None.
  * @retval None.
  */
int edition_compare(const char* pszStr1, const char* pszStr2)
{
	if (pszStr1 == NULL || pszStr2 == NULL) {
		return 0;
	}
	int nCurPos = 0, nCapPos=-1;
	const char* pszTmp1 = pszStr1;
	const char* pszTmp2 = pszStr2;
	while ((*pszTmp1 != '\0') && (*pszTmp2 != '\0') && (*pszTmp1 == *pszTmp2)) {	
		nCurPos++;									//找到第一个处不相同出现的位置
		pszTmp1++;
		pszTmp2++;
		if (*pszTmp1 == '.') {
			nCapPos = nCurPos;						//记录最近的‘.’的位置
		}
	}
	if (*pszTmp1 == '\0' && *pszTmp2 == '\0') { // 两个字符串相等
		return 0;
	} else if(*pszTmp1 == '\0'){
		return -1;
	} else if(*pszTmp2 == '\0'){
		return 1;
	}else{ // 两个字符串不相等,比较大小
		pszTmp1 = pszStr1 + nCapPos + 1;
		pszTmp2 = pszStr2 + nCapPos + 1;

		int pszNub1=strtol(pszTmp1,NULL,10);
		int pszNub2=strtol(pszTmp2,NULL,10);

		return (pszNub1 - pszNub2);
	}
}

创建设备事件,用于等待网络连接

const int CONNECTED_BIT = BIT0;

s_device_event_group = xEventGroupCreate();

 event_handler()函数中加入s_device_event_group的设置

/**
  * @brief  event_handler.
  * @param  None.
  * @retval None.
  */
static void event_handler(void* arg, esp_event_base_t event_base,
						  int32_t event_id, void* event_data)
{
	if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) 
	{
		esp_wifi_connect();
	}
	else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) 
	{	
		xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
		xEventGroupClearBits(s_device_event_group, WIFI_CONNECTED_BIT);
		esp_wifi_connect();
	}
	else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) 
	{
		xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
		xEventGroupSetBits(s_device_event_group, WIFI_CONNECTED_BIT);
	}
	else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) 
	{
		ESP_LOGI(TAG, "Scan done");
	}
	else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) 
	{
		ESP_LOGI(TAG, "Found channel");
	} 
	else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) 
	{
		ESP_LOGI(TAG, "Got SSID and password");

		smartconfig_event_got_ssid_pswd_t* evt = (smartconfig_event_got_ssid_pswd_t*)event_data;
		wifi_config_t wifi_config;
		uint8_t ssid[33] = { 0 };
		uint8_t password[65] = { 0 };
		uint8_t rvd_data[33] = { 0 };

		bzero(&wifi_config, sizeof(wifi_config_t));
		memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
		memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
		wifi_config.sta.bssid_set = evt->bssid_set;

		if (wifi_config.sta.bssid_set == true) {
			memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
		}

		memcpy(ssid, evt->ssid, sizeof(evt->ssid));
		memcpy(password, evt->password, sizeof(evt->password));
		ESP_LOGI(TAG, "SSID:%s", ssid);
		ESP_LOGI(TAG, "PASSWORD:%s", password);
		if (evt->type == SC_TYPE_ESPTOUCH_V2) {
			ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
			ESP_LOGI(TAG, "RVD_DATA:%s", rvd_data);
		}

		ESP_ERROR_CHECK(esp_wifi_disconnect());
		ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
		ESP_ERROR_CHECK(esp_wifi_connect());
	} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
		xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
	}
}

任务函数

/**
  * @brief  None.
  * @param  None.
  * @retval None.
  */
static void simple_ota_example_task(void * pvParameter)
{
	EventBits_t uxBits = xEventGroupWaitBits(s_device_event_group, WIFI_CONNECTED_BIT, pdFALSE, false, portMAX_DELAY ); 

	if( (uxBits & WIFI_CONNECTED_BIT) == WIFI_CONNECTED_BIT )
	{
		ESP_LOGI(TAG, "Starting OTA example...");

		char local_response_buffer[101] = {0};
		
	    esp_http_client_config_t config0 = {
			.url = "http://www.huochaigun.top/hello-world/version.html",
	        .event_handler = _http_event_handler,
//	        .user_data = local_response_buffer,        // Pass address of local buffer to get response
	        .buffer_size = 100
	    };
	    esp_http_client_handle_t client = esp_http_client_init(&config0);		

	    // GET
	    esp_err_t err = esp_http_client_perform(client);
	    if (err == ESP_OK) {
	        ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %d",
	                esp_http_client_get_status_code(client),
	                esp_http_client_get_content_length(client));
	    } else {
	        ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
	    }
		
		esp_http_client_read_response( client, local_response_buffer, 100 );
		local_response_buffer[ esp_http_client_get_content_length(client) ] = '\0';
		
		ESP_LOGI(TAG,"http response:%s\n", local_response_buffer );
		
		esp_http_client_cleanup(client);

		if( edition_compare(local_response_buffer, AppVer) > 0 )
		{
			esp_http_client_config_t config = {

				.url = "http://www.huochaigun.top/hello-world/hello-world.bin",
				.event_handler = _http_event_handler,
			};
			esp_err_t ret = esp_https_ota(&config);
			if (ret == ESP_OK) {
				esp_restart();
			} else {
				ESP_LOGE(TAG, "Firmware Upgrades Failed");
			}
		}
		else
		{
			ESP_LOGI(TAG, "The current software is the latest version");
		}
	}

	vTaskDelete( NULL );
}

app_main()中加入以下代码创建任务 

xTaskCreate(simple_ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);

 四、编译固件

执行make之后,会新生成4个bin文件,将4个bin文件下载到设备即可。

0xd000 ota_data_initial.bin
0x0 bootloader.bin
0x10000 hello-world.bin
0x8000 partitions_two_ota.bin

可提供有偿技术支持。

你可能感兴趣的:(ESP32/ESP8266,ESP8266,OTA,RTOS)