ESP32'de HTTP-OTA yöntemiyle yazılımı güncellemeye çalışıyorum ?

Başlatan mr.engineer, 11 Mart 2022, 21:34:19

mr.engineer

Merhaba,

ESP32'de HTTP-OTA yöntemiyle yazılımı güncellemeye çalışıyorum. Bir adrese http request edip dosyayı indirip flash'a yazabiliyorum. İşlem bitince reset atılıyor ve yeni yüklenmiş olan uygulama çalışmaya başlıyor, fakat bir süre sonra RTC_WDT sebepli bir reset ile sistem yeniden başlıyor ve esp eski yazılımı başlatıyor. Burada belirttiğim "bir süre" aslında 90 sn. RTC watc-dog timer için bizim ayarladığımız süre.

Bu konuda dökümanın söylediği şey; yeni yüklenen program çalışırken bir hata oluşursa, sistem tekrar eski programdan başlatılır. (rollback)

Eğer roll-back seçeneğini kapatırsam bu durumu engelliyorum yani sürekli yeni program çalışıyor ama bir süre sonra çalışan uygulama ile ilgili başka hatalar geliyor. Tam anlamasam da programın bozuk olduğunu belirtiyor.


Aklıma tek gelen şey program yazılırken bir hata olması. Update işleminin yapıldığı task'ın priority'sini en yükseğe çektim ama durum değişmedi.

Daha önce benzer bir işlem yapan varsa bilgilendirirse sevinirim.

hasankara

# Name      Type    SubType    Offset      Size    Flags
# Note: if you have increased the bootloader size    make sure to update the offsets to avoid overlap            
nvs   data   nvs      0x4000   
certs   data   nvs      0x2000   
otadata   data   ota           0x2000   
phy_init   data   phy           0x1000   
ota_0   app   ota_0         0x180000   
ota_1   app   ota_1         0x180000   

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
	assert(evt != NULL);

	switch (evt->event_id)
	{
	case HTTP_EVENT_ERROR:
		ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
		break;
	case HTTP_EVENT_ON_CONNECTED:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
		break;
	case HTTP_EVENT_HEADER_SENT:
		ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
		break;
	case HTTP_EVENT_ON_HEADER:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
		break;
	case HTTP_EVENT_ON_DATA:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
		if (!esp_http_client_is_chunked_response(evt->client))
		{
			// Write out data
			ESP_LOGD(TAG, "%.*s", evt->data_len, (char *)evt->data);
		}
		break;
	case HTTP_EVENT_ON_FINISH:
		ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
		break;
	case HTTP_EVENT_DISCONNECTED:
		ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
		break;
	}
	return ESP_OK;
}

static void start_ota()
{

	//    if (!fw_versions_are_equal(current_ver, ota_config.targetFwVer) && ota_params_are_specified(ota_config))
	{
		ESP_LOGW(TAG, "Starting OTA, firmware versions are different - current: %s, target: %s", FIRMWARE_VERSION, dev->otaFwVer);
		ESP_LOGI(TAG, "Target firmware version: %s", dev->otaFwVer);
		ESP_LOGI(TAG, "Firmware URL: %s", dev->otaFwUrl);
		msg_print("OTA start");
		vTaskDelay(1000);
		esp_http_client_config_t config = {
			.url = dev->otaFwUrl,
			.cert_pem = (char *)server_cert_pem_start,
			.event_handler = _http_event_handler,
		};

		/* OTA OPERATION*/
		//		esp_err_t ret = esp_https_ota(&config);
		esp_err_t ret = ESP_FAIL;
		int cnt = 0;
		do
		{
			esp_https_ota_config_t ota_config = {
				.http_config = &config,
			};

			esp_https_ota_handle_t https_ota_handle = NULL;
			ret = esp_https_ota_begin(&ota_config, &https_ota_handle);
			if (https_ota_handle == NULL)
			{
				sprintf((char *)&ota_print, "OTA Not Started.");
				ota_print_new++;
				ret = ESP_FAIL;
				break;
			}

			while (1)
			{
				ret = esp_https_ota_perform(https_ota_handle);
				if (ret != ESP_ERR_HTTPS_OTA_IN_PROGRESS)
				{
					break;
				}
				sprintf((char *)&ota_print, "OTA Progress: %d", cnt);
				ota_print_new++;
				cnt++;
			}

			if (ret != ESP_OK)
			{
				esp_https_ota_abort(https_ota_handle);
			}
			else
			{
				ret = esp_https_ota_finish(https_ota_handle);
			}

			if (ret != ESP_OK)
			{
				sprintf((char *)&ota_print, "OTA Aborted: %d", cnt);
				ota_print_new++;
			}
			else
			{
				sprintf((char *)&ota_print, "OTA Complete: %d", cnt);
				ota_print_new++;
			}

		} while (0);

		if (ret == ESP_OK)
		{
			sys_reset_run();
		}
		else
		{
			msg_print("OTA Fail");
			ESP_LOGE(TAG, "Firmware Upgrades Failed");
		}
		dev->flg.ota_state = ota_cmd_none;
	}
	vTaskDelete(0);
}

Ben sorunsuz ota güncellemesini kullanıyorum. partition table ve ota kodu yuarıda ki gibi belki faydası olur diye ekliyorum.

ota komut kontrolü yapan ayrı bir taskin içinde de aşağıda ki kod parçası ile ilgili taski oluşturuyorum.

if (dev->flg.ota_state == ota_cmd_start)
		{
			dev->flg.ota_state = ota_cmd_busy;
			xTaskCreatePinnedToCore(start_ota, "ota", 1024 * 3, NULL, 1, NULL, 1);
		}

mr.engineer

@hasankara teşekkürler. Ben de otayı benzer şekilde kullanıyorum. Partition table ile ilgili sorunum yok, zaten yeni uygulamayı update ederken partition table'ı değiştirmiyorum.
Advanced_ota_example örneğindeki gibi ota'yı kullanıyorum. Seninki gibi sayılır. Fakat yeni uygulama yüklendikten sonra RTC-watc-dog ile reset atıyordu ve eski uygulamaya geçiyordu.

Bootloader config menüsünde CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE diye bir seçenek var bunu disable edince sorun çözüldü. Roll-back özelliği ile hatalı çalışan uygulama silinip eskisine dönüyor. Bunu disable edince sorun çözüldü ama doğru mu yaptım emin olmamadım.

Advanced_ota_example'da da bu özellik default olarak disable geliyor. Eğer enable edersem, reset atmıyor ama power on/off yapınca yeni yazılımı silip eskisini yüklüyor.

Aşağıdaki linkdeki açıklaması var ama bana wdt ve power on/off durumunda roll-back yapması saçma geldi.

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-bootloader-app-rollback-enable

hasankara




Bu özellikten benimde yeni haberim oldu diyebilirim. Bende kapalıymış ilgili özellik. Faydası olur diye benim ayarların resmini yüklüyorum.

mr.engineer