mirror of
https://github.com/Fishwaldo/esp_ghota.git
synced 2025-03-15 19:31:37 +00:00
Fix Compiles on ESP-IDF versions > 4.4 (#8)
* fixes for esp-idf > version 5 * Test builds on different versions of esp-idf in github CI
This commit is contained in:
parent
e1f297b16c
commit
335b33062b
4 changed files with 328 additions and 224 deletions
7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
|
@ -12,16 +12,17 @@ jobs:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
targets: [esp32, esp32s3]
|
targets: [esp32, esp32s3]
|
||||||
|
espidf: [v4.4.6, v5.0.5, v5.1.2, v5.2]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: esp-idf build
|
- name: esp-idf build
|
||||||
uses: Fishwaldo/esp-idf-ci-action@v1.2
|
uses: espressif/esp-idf-ci-action@v1
|
||||||
with:
|
with:
|
||||||
esp_idf_version: v4.4.3
|
esp_idf_version: ${{ matrix.espidf }}
|
||||||
target: ${{ matrix.targets }}
|
target: ${{ matrix.targets }}
|
||||||
path: 'examples/esp_ghota_example'
|
path: 'examples/esp_ghota_example'
|
||||||
- name: Rename artifact
|
- name: Rename artifact
|
||||||
|
|
|
@ -25,7 +25,7 @@ You should be careful with your GitHub PAT and putting it in the source code. I
|
||||||
### esp-idf via Espressif Component Registry:
|
### esp-idf via Espressif Component Registry:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
idf.py add-dependency Fishwaldo/ghota^0.0.1
|
idf.py add-dependency Fishwaldo/ghota^1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Platform IO Registry:
|
#### Platform IO Registry:
|
||||||
|
@ -34,7 +34,7 @@ add this to your platform.ini file:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
lib_deps =
|
lib_deps =
|
||||||
Fishwaldo/ghota@^0.0.1
|
fishwaldo/ghota@^1.0.0
|
||||||
```
|
```
|
||||||
|
|
||||||
You also need to copy the contents of [Kconfig](Kconfig) into your project's Kconfig file, and run pio run -t menuconfig to configure the component.
|
You also need to copy the contents of [Kconfig](Kconfig) into your project's Kconfig file, and run pio run -t menuconfig to configure the component.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "esp_ghota",
|
"name": "esp_ghota",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"description": "a OTA library to upgrade your firmware via the Github Releases API",
|
"description": "a OTA library to upgrade your firmware via the Github Releases API",
|
||||||
"keywords": "esp32 ota github",
|
"keywords": "esp32 ota github",
|
||||||
"repository":
|
"repository":
|
||||||
|
|
539
src/esp_ghota.c
539
src/esp_ghota.c
|
@ -21,18 +21,26 @@ static const char *TAG = "GHOTA";
|
||||||
|
|
||||||
ESP_EVENT_DEFINE_BASE(GHOTA_EVENTS);
|
ESP_EVENT_DEFINE_BASE(GHOTA_EVENTS);
|
||||||
|
|
||||||
typedef struct ghota_client_handle_t {
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||||
|
#define PRICONTENT_LENGTH PRId64
|
||||||
|
#else
|
||||||
|
#define PRICONTENT_LENGTH PRId32
|
||||||
|
#endif
|
||||||
|
typedef struct ghota_client_handle_t
|
||||||
|
{
|
||||||
ghota_config_t config;
|
ghota_config_t config;
|
||||||
char *username;
|
char *username;
|
||||||
char *token;
|
char *token;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
char tag_name[CONFIG_MAX_FILENAME_LEN];
|
char tag_name[CONFIG_MAX_FILENAME_LEN];
|
||||||
char name[CONFIG_MAX_FILENAME_LEN];
|
char name[CONFIG_MAX_FILENAME_LEN];
|
||||||
char url[CONFIG_MAX_URL_LEN];
|
char url[CONFIG_MAX_URL_LEN];
|
||||||
char storageurl[CONFIG_MAX_URL_LEN];
|
char storageurl[CONFIG_MAX_URL_LEN];
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} result;
|
} result;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
char name[CONFIG_MAX_FILENAME_LEN];
|
char name[CONFIG_MAX_FILENAME_LEN];
|
||||||
char url[CONFIG_MAX_URL_LEN];
|
char url[CONFIG_MAX_URL_LEN];
|
||||||
} scratch;
|
} scratch;
|
||||||
|
@ -43,7 +51,6 @@ typedef struct ghota_client_handle_t {
|
||||||
const esp_partition_t *storage_partition;
|
const esp_partition_t *storage_partition;
|
||||||
} ghota_client_handle_t;
|
} ghota_client_handle_t;
|
||||||
|
|
||||||
|
|
||||||
enum release_flags
|
enum release_flags
|
||||||
{
|
{
|
||||||
GHOTA_RELEASE_GOT_TAG = 0x01,
|
GHOTA_RELEASE_GOT_TAG = 0x01,
|
||||||
|
@ -55,7 +62,6 @@ enum release_flags
|
||||||
|
|
||||||
SemaphoreHandle_t ghota_lock = NULL;
|
SemaphoreHandle_t ghota_lock = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void SetFlag(ghota_client_handle_t *handle, enum release_flags flag)
|
static void SetFlag(ghota_client_handle_t *handle, enum release_flags flag)
|
||||||
{
|
{
|
||||||
handle->result.flags |= flag;
|
handle->result.flags |= flag;
|
||||||
|
@ -70,16 +76,20 @@ static void ClearFlag(ghota_client_handle_t *handle, enum release_flags flag)
|
||||||
handle->result.flags &= ~flag;
|
handle->result.flags &= ~flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
ghota_client_handle_t *ghota_init(ghota_config_t *newconfig) {
|
ghota_client_handle_t *ghota_init(ghota_config_t *newconfig)
|
||||||
if (!ghota_lock) {
|
{
|
||||||
|
if (!ghota_lock)
|
||||||
|
{
|
||||||
ghota_lock = xSemaphoreCreateMutex();
|
ghota_lock = xSemaphoreCreateMutex();
|
||||||
}
|
}
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS) {
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to take lock");
|
ESP_LOGE(TAG, "Failed to take lock");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ghota_client_handle_t *handle = malloc(sizeof(ghota_client_handle_t));
|
ghota_client_handle_t *handle = malloc(sizeof(ghota_client_handle_t));
|
||||||
if (handle == NULL) {
|
if (handle == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to allocate memory for client handle");
|
ESP_LOGE(TAG, "Failed to allocate memory for client handle");
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -102,9 +112,13 @@ ghota_client_handle_t *ghota_init(ghota_config_t *newconfig) {
|
||||||
asprintf(&handle->config.reponame, CONFIG_GITHUB_REPO);
|
asprintf(&handle->config.reponame, CONFIG_GITHUB_REPO);
|
||||||
else
|
else
|
||||||
asprintf(&handle->config.reponame, newconfig->reponame);
|
asprintf(&handle->config.reponame, newconfig->reponame);
|
||||||
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||||
|
const esp_app_desc_t *app_desc = esp_app_get_description();
|
||||||
|
#else
|
||||||
const esp_app_desc_t *app_desc = esp_ota_get_app_description();
|
const esp_app_desc_t *app_desc = esp_ota_get_app_description();
|
||||||
if (semver_parse(app_desc->version, &handle->current_version)) {
|
#endif
|
||||||
|
if (semver_parse(app_desc->version, &handle->current_version))
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to parse current version");
|
ESP_LOGE(TAG, "Failed to parse current version");
|
||||||
ghota_free(handle);
|
ghota_free(handle);
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
|
@ -112,10 +126,10 @@ ghota_client_handle_t *ghota_init(ghota_config_t *newconfig) {
|
||||||
}
|
}
|
||||||
handle->result.flags = 0;
|
handle->result.flags = 0;
|
||||||
|
|
||||||
// if (newconfig->updateInterval < 60) {
|
// if (newconfig->updateInterval < 60) {
|
||||||
// ESP_LOGE(TAG, "Update interval must be at least 60 Minutes");
|
// ESP_LOGE(TAG, "Update interval must be at least 60 Minutes");
|
||||||
// newconfig->updateInterval = 60;
|
// newconfig->updateInterval = 60;
|
||||||
// }
|
// }
|
||||||
handle->config.updateInterval = newconfig->updateInterval;
|
handle->config.updateInterval = newconfig->updateInterval;
|
||||||
|
|
||||||
handle->task_handle = NULL;
|
handle->task_handle = NULL;
|
||||||
|
@ -124,8 +138,10 @@ ghota_client_handle_t *ghota_init(ghota_config_t *newconfig) {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_free(ghota_client_handle_t *handle) {
|
esp_err_t ghota_free(ghota_client_handle_t *handle)
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS) {
|
{
|
||||||
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to take lock");
|
ESP_LOGE(TAG, "Failed to take lock");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -142,8 +158,10 @@ esp_err_t ghota_free(ghota_client_handle_t *handle) {
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_set_auth(ghota_client_handle_t *handle, const char *username, const char *password) {
|
esp_err_t ghota_set_auth(ghota_client_handle_t *handle, const char *username, const char *password)
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS) {
|
{
|
||||||
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to take lock");
|
ESP_LOGE(TAG, "Failed to take lock");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -153,10 +171,10 @@ esp_err_t ghota_set_auth(ghota_client_handle_t *handle, const char *username, co
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t type)
|
static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t type)
|
||||||
{
|
{
|
||||||
if (jsp->udata == NULL) {
|
if (jsp->udata == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "No user data for callback");
|
ESP_LOGE(TAG, "No user data for callback");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +187,8 @@ static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t ty
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Get a value corresponsing to "tag_name" key */
|
/* Get a value corresponsing to "tag_name" key */
|
||||||
if (!GetFlag(handle, GHOTA_RELEASE_GOT_TAG)) {
|
if (!GetFlag(handle, GHOTA_RELEASE_GOT_TAG))
|
||||||
|
{
|
||||||
if (jsp->stack_pos >= 2 /* Number of stack entries must be high */
|
if (jsp->stack_pos >= 2 /* Number of stack entries must be high */
|
||||||
&& jsp->stack[0].type == LWJSON_STREAM_TYPE_OBJECT /* First must be object */
|
&& jsp->stack[0].type == LWJSON_STREAM_TYPE_OBJECT /* First must be object */
|
||||||
&& jsp->stack[1].type == LWJSON_STREAM_TYPE_KEY /* We need key to be before */
|
&& jsp->stack[1].type == LWJSON_STREAM_TYPE_KEY /* We need key to be before */
|
||||||
|
@ -180,14 +199,9 @@ static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t ty
|
||||||
SetFlag(handle, GHOTA_RELEASE_GOT_TAG);
|
SetFlag(handle, GHOTA_RELEASE_GOT_TAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET) || !GetFlag(handle, GHOTA_RELEASE_GOT_STORAGE)) {
|
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET) || !GetFlag(handle, GHOTA_RELEASE_GOT_STORAGE))
|
||||||
if (jsp->stack_pos == 5
|
{
|
||||||
&& jsp->stack[0].type == LWJSON_STREAM_TYPE_OBJECT
|
if (jsp->stack_pos == 5 && jsp->stack[0].type == LWJSON_STREAM_TYPE_OBJECT && jsp->stack[1].type == LWJSON_STREAM_TYPE_KEY && strcasecmp(jsp->stack[1].meta.name, "assets") == 0 && jsp->stack[2].type == LWJSON_STREAM_TYPE_ARRAY && jsp->stack[3].type == LWJSON_STREAM_TYPE_OBJECT && jsp->stack[4].type == LWJSON_STREAM_TYPE_KEY)
|
||||||
&& jsp->stack[1].type == LWJSON_STREAM_TYPE_KEY
|
|
||||||
&& strcasecmp(jsp->stack[1].meta.name, "assets") == 0
|
|
||||||
&& jsp->stack[2].type == LWJSON_STREAM_TYPE_ARRAY
|
|
||||||
&& jsp->stack[3].type == LWJSON_STREAM_TYPE_OBJECT
|
|
||||||
&& jsp->stack[4].type == LWJSON_STREAM_TYPE_KEY)
|
|
||||||
{
|
{
|
||||||
ESP_LOGD(TAG, "Assets Got key '%s' with value '%s'", jsp->stack[jsp->stack_pos - 1].meta.name, jsp->data.str.buff);
|
ESP_LOGD(TAG, "Assets Got key '%s' with value '%s'", jsp->stack[jsp->stack_pos - 1].meta.name, jsp->data.str.buff);
|
||||||
if (strcasecmp(jsp->stack[4].meta.name, "name") == 0)
|
if (strcasecmp(jsp->stack[4].meta.name, "name") == 0)
|
||||||
|
@ -203,19 +217,25 @@ static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t ty
|
||||||
ESP_LOGD(TAG, "Got URL for Asset: %s", handle->scratch.url);
|
ESP_LOGD(TAG, "Got URL for Asset: %s", handle->scratch.url);
|
||||||
}
|
}
|
||||||
/* Now test if we got both name an download url */
|
/* Now test if we got both name an download url */
|
||||||
if (GetFlag(handle, GHOTA_RELEASE_GOT_FNAME) && GetFlag(handle, GHOTA_RELEASE_GOT_URL)) {
|
if (GetFlag(handle, GHOTA_RELEASE_GOT_FNAME) && GetFlag(handle, GHOTA_RELEASE_GOT_URL))
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Testing Firmware filenames %s -> %s - Matching Filename against %s and %s", handle->scratch.name, handle->scratch.url, handle->config.filenamematch, handle->config.storagenamematch);
|
ESP_LOGD(TAG, "Testing Firmware filenames %s -> %s - Matching Filename against %s and %s", handle->scratch.name, handle->scratch.url, handle->config.filenamematch, handle->config.storagenamematch);
|
||||||
/* see if the filename matches */
|
/* see if the filename matches */
|
||||||
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET) && fnmatch(handle->config.filenamematch, handle->scratch.name, 0) == 0) {
|
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET) && fnmatch(handle->config.filenamematch, handle->scratch.name, 0) == 0)
|
||||||
|
{
|
||||||
strncpy(handle->result.name, handle->scratch.name, CONFIG_MAX_FILENAME_LEN);
|
strncpy(handle->result.name, handle->scratch.name, CONFIG_MAX_FILENAME_LEN);
|
||||||
strncpy(handle->result.url, handle->scratch.url, CONFIG_MAX_URL_LEN);
|
strncpy(handle->result.url, handle->scratch.url, CONFIG_MAX_URL_LEN);
|
||||||
ESP_LOGD(TAG, "Valid Firmware Found: %s - %s", handle->result.name, handle->result.url);
|
ESP_LOGD(TAG, "Valid Firmware Found: %s - %s", handle->result.name, handle->result.url);
|
||||||
SetFlag(handle, GHOTA_RELEASE_VALID_ASSET);
|
SetFlag(handle, GHOTA_RELEASE_VALID_ASSET);
|
||||||
} else if (!GetFlag(handle, GHOTA_RELEASE_GOT_STORAGE) && fnmatch(handle->config.storagenamematch, handle->scratch.name, 0) == 0) {
|
}
|
||||||
|
else if (!GetFlag(handle, GHOTA_RELEASE_GOT_STORAGE) && fnmatch(handle->config.storagenamematch, handle->scratch.name, 0) == 0)
|
||||||
|
{
|
||||||
strncpy(handle->result.storageurl, handle->scratch.url, CONFIG_MAX_URL_LEN);
|
strncpy(handle->result.storageurl, handle->scratch.url, CONFIG_MAX_URL_LEN);
|
||||||
ESP_LOGD(TAG, "Valid Storage Asset Found: %s - %s", handle->scratch.name, handle->result.storageurl);
|
ESP_LOGD(TAG, "Valid Storage Asset Found: %s - %s", handle->scratch.name, handle->result.storageurl);
|
||||||
SetFlag(handle, GHOTA_RELEASE_GOT_STORAGE);
|
SetFlag(handle, GHOTA_RELEASE_GOT_STORAGE);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Invalid Asset Found: %s", handle->scratch.name);
|
ESP_LOGD(TAG, "Invalid Asset Found: %s", handle->scratch.name);
|
||||||
ClearFlag(handle, GHOTA_RELEASE_GOT_FNAME);
|
ClearFlag(handle, GHOTA_RELEASE_GOT_FNAME);
|
||||||
ClearFlag(handle, GHOTA_RELEASE_GOT_URL);
|
ClearFlag(handle, GHOTA_RELEASE_GOT_URL);
|
||||||
|
@ -228,51 +248,56 @@ static void lwjson_callback(lwjson_stream_parser_t *jsp, lwjson_stream_type_t ty
|
||||||
static esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
static esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||||
{
|
{
|
||||||
lwjsonr_t res;
|
lwjsonr_t res;
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wswitch"
|
#pragma GCC diagnostic ignored "-Wswitch"
|
||||||
switch (evt->event_id) {
|
switch (evt->event_id)
|
||||||
case HTTP_EVENT_ON_HEADER:
|
{
|
||||||
if (strncasecmp(evt->header_key, "x-ratelimit-remaining", strlen("x-ratelimit-remaining")) == 0) {
|
case HTTP_EVENT_ON_HEADER:
|
||||||
int limit = atoi(evt->header_value);
|
if (strncasecmp(evt->header_key, "x-ratelimit-remaining", strlen("x-ratelimit-remaining")) == 0)
|
||||||
ESP_LOGD(TAG, "Github API Rate Limit Remaining: %d", limit);
|
{
|
||||||
if (limit < 10) {
|
int limit = atoi(evt->header_value);
|
||||||
ESP_LOGW(TAG, "Github API Rate Limit Remaining is low: %d", limit);
|
ESP_LOGD(TAG, "Github API Rate Limit Remaining: %d", limit);
|
||||||
}
|
if (limit < 10)
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_ON_DATA:
|
|
||||||
if (!esp_http_client_is_chunked_response(evt->client))
|
|
||||||
{
|
{
|
||||||
char *buf = evt->data;
|
ESP_LOGW(TAG, "Github API Rate Limit Remaining is low: %d", limit);
|
||||||
for (int i = 0; i < evt->data_len; i++)
|
|
||||||
{
|
|
||||||
res = lwjson_stream_parse((lwjson_stream_parser_t *)evt->user_data, *buf);
|
|
||||||
if (!(res == lwjsonOK || res == lwjsonSTREAMDONE || res == lwjsonSTREAMINPROG))
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "Lwjson Error: %d", res);
|
|
||||||
}
|
|
||||||
buf++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case HTTP_EVENT_DISCONNECTED: {
|
|
||||||
int mbedtls_err = 0;
|
|
||||||
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "Last esp error code: 0x%x", err);
|
|
||||||
ESP_LOGE(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_ON_DATA:
|
||||||
|
if (!esp_http_client_is_chunked_response(evt->client))
|
||||||
|
{
|
||||||
|
char *buf = evt->data;
|
||||||
|
for (int i = 0; i < evt->data_len; i++)
|
||||||
|
{
|
||||||
|
res = lwjson_stream_parse((lwjson_stream_parser_t *)evt->user_data, *buf);
|
||||||
|
if (!(res == lwjsonOK || res == lwjsonSTREAMDONE || res == lwjsonSTREAMINPROG))
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Lwjson Error: %d", res);
|
||||||
|
}
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_DISCONNECTED:
|
||||||
|
{
|
||||||
|
int mbedtls_err = 0;
|
||||||
|
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Last esp error code: 0x%x", err);
|
||||||
|
ESP_LOGE(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_check(ghota_client_handle_t *handle)
|
esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
{
|
{
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS) {
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to get lock");
|
ESP_LOGE(TAG, "Failed to get lock");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +314,7 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
stream_parser.udata = (void*)handle;
|
stream_parser.udata = (void *)handle;
|
||||||
|
|
||||||
char url[CONFIG_MAX_URL_LEN];
|
char url[CONFIG_MAX_URL_LEN];
|
||||||
snprintf(url, CONFIG_MAX_URL_LEN, "https://%s/repos/%s/%s/releases/latest", handle->config.hostname, handle->config.orgname, handle->config.reponame);
|
snprintf(url, CONFIG_MAX_URL_LEN, "https://%s/repos/%s/%s/releases/latest", handle->config.hostname, handle->config.orgname, handle->config.reponame);
|
||||||
|
@ -300,7 +325,8 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
.event_handler = _http_event_handler,
|
.event_handler = _http_event_handler,
|
||||||
.user_data = &stream_parser,
|
.user_data = &stream_parser,
|
||||||
};
|
};
|
||||||
if (handle->username) {
|
if (handle->username)
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Using Authenticated Request to %s", url);
|
ESP_LOGD(TAG, "Using Authenticated Request to %s", url);
|
||||||
httpconfig.username = handle->username;
|
httpconfig.username = handle->username;
|
||||||
httpconfig.password = handle->token;
|
httpconfig.password = handle->token;
|
||||||
|
@ -313,7 +339,7 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
esp_err_t err = esp_http_client_perform(client);
|
esp_err_t err = esp_http_client_perform(client);
|
||||||
if (err == ESP_OK)
|
if (err == ESP_OK)
|
||||||
{
|
{
|
||||||
ESP_LOGD(TAG, "HTTP GET Status = %d, content_length = %d",
|
ESP_LOGD(TAG, "HTTP GET Status = %d, content_length = %" PRICONTENT_LENGTH ,
|
||||||
esp_http_client_get_status_code(client),
|
esp_http_client_get_status_code(client),
|
||||||
esp_http_client_get_content_length(client));
|
esp_http_client_get_content_length(client));
|
||||||
}
|
}
|
||||||
|
@ -324,13 +350,13 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (esp_http_client_get_status_code(client) == 200)
|
if (esp_http_client_get_status_code(client) == 200)
|
||||||
{
|
{
|
||||||
if (GetFlag(handle, GHOTA_RELEASE_VALID_ASSET))
|
if (GetFlag(handle, GHOTA_RELEASE_VALID_ASSET))
|
||||||
{
|
{
|
||||||
if (semver_parse(handle->result.tag_name, &handle->latest_version)) {
|
if (semver_parse(handle->result.tag_name, &handle->latest_version))
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to parse new version");
|
ESP_LOGE(TAG, "Failed to parse new version");
|
||||||
esp_http_client_cleanup(client);
|
esp_http_client_cleanup(client);
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
||||||
|
@ -341,10 +367,13 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
ESP_LOGI(TAG, "New Version %d.%d.%d", handle->latest_version.major, handle->latest_version.minor, handle->latest_version.patch);
|
ESP_LOGI(TAG, "New Version %d.%d.%d", handle->latest_version.major, handle->latest_version.minor, handle->latest_version.patch);
|
||||||
ESP_LOGI(TAG, "Asset: %s", handle->result.name);
|
ESP_LOGI(TAG, "Asset: %s", handle->result.name);
|
||||||
ESP_LOGI(TAG, "Firmware URL: %s", handle->result.url);
|
ESP_LOGI(TAG, "Firmware URL: %s", handle->result.url);
|
||||||
if (strlen(handle->result.storageurl)) {
|
if (strlen(handle->result.storageurl))
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Storage URL: %s", handle->result.storageurl);
|
ESP_LOGI(TAG, "Storage URL: %s", handle->result.storageurl);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Asset: No Valid Firmware Assets Found");
|
ESP_LOGI(TAG, "Asset: No Valid Firmware Assets Found");
|
||||||
esp_http_client_cleanup(client);
|
esp_http_client_cleanup(client);
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, handle, sizeof(ghota_client_handle_t *), portMAX_DELAY));
|
||||||
|
@ -369,7 +398,8 @@ esp_err_t ghota_check(ghota_client_handle_t *handle)
|
||||||
|
|
||||||
static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
|
static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
|
||||||
{
|
{
|
||||||
if (new_app_info == NULL) {
|
if (new_app_info == NULL)
|
||||||
|
{
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "New Firmware Details:");
|
ESP_LOGI(TAG, "New Firmware Details:");
|
||||||
|
@ -379,12 +409,12 @@ static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
|
||||||
ESP_LOGI(TAG, "ESP-IDF: %s", new_app_info->idf_ver);
|
ESP_LOGI(TAG, "ESP-IDF: %s", new_app_info->idf_ver);
|
||||||
ESP_LOGI(TAG, "SHA256:");
|
ESP_LOGI(TAG, "SHA256:");
|
||||||
ESP_LOG_BUFFER_HEX(TAG, new_app_info->app_elf_sha256, sizeof(new_app_info->app_elf_sha256));
|
ESP_LOG_BUFFER_HEX(TAG, new_app_info->app_elf_sha256, sizeof(new_app_info->app_elf_sha256));
|
||||||
|
|
||||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||||
ESP_LOGD(TAG, "Current partition %s type %d subtype %d (offset 0x%08x)",
|
ESP_LOGD(TAG, "Current partition %s type %d subtype %d (offset 0x%08" PRIx32 ")",
|
||||||
running->label, running->type, running->subtype, running->address);
|
running->label, running->type, running->subtype, running->address);
|
||||||
const esp_partition_t *update = esp_ota_get_next_update_partition(NULL);
|
const esp_partition_t *update = esp_ota_get_next_update_partition(NULL);
|
||||||
ESP_LOGD(TAG, "Update partition %s type %d subtype %d (offset 0x%08x)",
|
ESP_LOGD(TAG, "Update partition %s type %d subtype %d (offset 0x%08" PRIx32 ")",
|
||||||
update->label, update->type, update->subtype, update->address);
|
update->label, update->type, update->subtype, update->address);
|
||||||
|
|
||||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||||
|
@ -394,7 +424,8 @@ static esp_err_t validate_image_header(esp_app_desc_t *new_app_info)
|
||||||
* esp_https_ota_finish at the end of OTA update procedure.
|
* esp_https_ota_finish at the end of OTA update procedure.
|
||||||
*/
|
*/
|
||||||
const uint32_t hw_sec_version = esp_efuse_read_secure_version();
|
const uint32_t hw_sec_version = esp_efuse_read_secure_version();
|
||||||
if (new_app_info->secure_version < hw_sec_version) {
|
if (new_app_info->secure_version < hw_sec_version)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "New firmware security version is less than eFuse programmed, %d < %d", new_app_info->secure_version, hw_sec_version);
|
ESP_LOGW(TAG, "New firmware security version is less than eFuse programmed, %d < %d", new_app_info->secure_version, hw_sec_version);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -408,79 +439,92 @@ static esp_err_t http_client_set_header_cb(esp_http_client_handle_t http_client)
|
||||||
return esp_http_client_set_header(http_client, "Accept", "application/octet-stream");
|
return esp_http_client_set_header(http_client, "Accept", "application/octet-stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t _http_event_storage_handler(esp_http_client_event_t *evt) {
|
esp_err_t _http_event_storage_handler(esp_http_client_event_t *evt)
|
||||||
|
{
|
||||||
static int output_pos;
|
static int output_pos;
|
||||||
static int last_progress;
|
static int last_progress;
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wswitch"
|
#pragma GCC diagnostic ignored "-Wswitch"
|
||||||
switch (evt->event_id) {
|
switch (evt->event_id)
|
||||||
case HTTP_EVENT_ON_CONNECTED: {
|
{
|
||||||
output_pos = 0;
|
case HTTP_EVENT_ON_CONNECTED:
|
||||||
last_progress = 0;
|
{
|
||||||
/* Erase the Partition */
|
output_pos = 0;
|
||||||
break;
|
last_progress = 0;
|
||||||
}
|
/* Erase the Partition */
|
||||||
case HTTP_EVENT_ON_DATA:
|
break;
|
||||||
if (!esp_http_client_is_chunked_response(evt->client)) {
|
|
||||||
ghota_client_handle_t *handle = (ghota_client_handle_t *)evt->user_data;
|
|
||||||
if (output_pos == 0) {
|
|
||||||
ESP_LOGD(TAG, "Erasing Partition");
|
|
||||||
ESP_ERROR_CHECK(esp_partition_erase_range(handle->storage_partition, 0, handle->storage_partition->size));
|
|
||||||
ESP_LOGD(TAG, "Erasing Complete");
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_partition_write(handle->storage_partition, output_pos, evt->data, evt->data_len));
|
|
||||||
output_pos += evt->data_len;
|
|
||||||
int progress = 100 * ((float)output_pos / (float)handle->storage_partition->size);
|
|
||||||
if ((progress % 5 == 0) && (progress != last_progress)) {
|
|
||||||
ESP_LOGV(TAG, "Storage Firmware Update Progress: %d%%", progress);
|
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_STORAGE_UPDATE_PROGRESS, &progress, sizeof(progress), portMAX_DELAY));
|
|
||||||
last_progress = progress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HTTP_EVENT_DISCONNECTED: {
|
|
||||||
int mbedtls_err = 0;
|
|
||||||
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "Last esp error code: 0x%x", err);
|
|
||||||
ESP_LOGE(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#pragma GCC diagnostic pop
|
case HTTP_EVENT_ON_DATA:
|
||||||
|
if (!esp_http_client_is_chunked_response(evt->client))
|
||||||
|
{
|
||||||
|
ghota_client_handle_t *handle = (ghota_client_handle_t *)evt->user_data;
|
||||||
|
if (output_pos == 0)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "Erasing Partition");
|
||||||
|
ESP_ERROR_CHECK(esp_partition_erase_range(handle->storage_partition, 0, handle->storage_partition->size));
|
||||||
|
ESP_LOGD(TAG, "Erasing Complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_partition_write(handle->storage_partition, output_pos, evt->data, evt->data_len));
|
||||||
|
output_pos += evt->data_len;
|
||||||
|
int progress = 100 * ((float)output_pos / (float)handle->storage_partition->size);
|
||||||
|
if ((progress % 5 == 0) && (progress != last_progress))
|
||||||
|
{
|
||||||
|
ESP_LOGV(TAG, "Storage Firmware Update Progress: %d%%", progress);
|
||||||
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_STORAGE_UPDATE_PROGRESS, &progress, sizeof(progress), portMAX_DELAY));
|
||||||
|
last_progress = progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HTTP_EVENT_DISCONNECTED:
|
||||||
|
{
|
||||||
|
int mbedtls_err = 0;
|
||||||
|
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "Last esp error code: 0x%x", err);
|
||||||
|
ESP_LOGE(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_storage_update(ghota_client_handle_t *handle) {
|
esp_err_t ghota_storage_update(ghota_client_handle_t *handle)
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
{
|
||||||
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdTRUE)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to take lock");
|
ESP_LOGE(TAG, "Failed to take lock");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
if (handle == NULL) {
|
if (handle == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Invalid Handle");
|
ESP_LOGE(TAG, "Invalid Handle");
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (!strlen(handle->result.storageurl)) {
|
if (!strlen(handle->result.storageurl))
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "No Storage URL");
|
ESP_LOGE(TAG, "No Storage URL");
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
if (!strlen(handle->config.storagepartitionname)) {
|
if (!strlen(handle->config.storagepartitionname))
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "No Storage Partition Name");
|
ESP_LOGE(TAG, "No Storage Partition Name");
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
handle->storage_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, handle->config.storagepartitionname);
|
handle->storage_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, handle->config.storagepartitionname);
|
||||||
if (handle->storage_partition == NULL) {
|
if (handle->storage_partition == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Storage Partition Not Found");
|
ESP_LOGE(TAG, "Storage Partition Not Found");
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Storage Partition %s - Type %x Subtype %x Found at %x - size %d", handle->storage_partition->label, handle->storage_partition->type, handle->storage_partition->subtype, handle->storage_partition->address, handle->storage_partition->size);
|
ESP_LOGD(TAG, "Storage Partition %s - Type %x Subtype %x Found at %" PRIx32 " - size %" PRIu32, handle->storage_partition->label, handle->storage_partition->type, handle->storage_partition->subtype, handle->storage_partition->address, handle->storage_partition->size);
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_START_STORAGE_UPDATE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_START_STORAGE_UPDATE, NULL, 0, portMAX_DELAY));
|
||||||
/* give time for the system to react, such as unmounting the filesystems etc */
|
/* give time for the system to react, such as unmounting the filesystems etc */
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
@ -493,7 +537,8 @@ esp_err_t ghota_storage_update(ghota_client_handle_t *handle) {
|
||||||
.buffer_size_tx = 2048,
|
.buffer_size_tx = 2048,
|
||||||
|
|
||||||
};
|
};
|
||||||
if (handle->username) {
|
if (handle->username)
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Using Authenticated Request to %s", config.url);
|
ESP_LOGD(TAG, "Using Authenticated Request to %s", config.url);
|
||||||
config.username = handle->username;
|
config.username = handle->username;
|
||||||
config.password = handle->token;
|
config.password = handle->token;
|
||||||
|
@ -502,41 +547,46 @@ esp_err_t ghota_storage_update(ghota_client_handle_t *handle) {
|
||||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||||
ESP_ERROR_CHECK(esp_http_client_set_header(client, "Accept", "application/octet-stream"));
|
ESP_ERROR_CHECK(esp_http_client_set_header(client, "Accept", "application/octet-stream"));
|
||||||
esp_err_t err = esp_http_client_perform(client);
|
esp_err_t err = esp_http_client_perform(client);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK)
|
||||||
ESP_LOGD(TAG, "HTTP GET Status = %d, content_length = %d",
|
{
|
||||||
esp_http_client_get_status_code(client),
|
ESP_LOGD(TAG, "HTTP GET Status = %d, content_length = %" PRICONTENT_LENGTH,
|
||||||
esp_http_client_get_content_length(client));
|
esp_http_client_get_status_code(client),
|
||||||
uint8_t sha256[32] = { 0 };
|
esp_http_client_get_content_length(client));
|
||||||
|
uint8_t sha256[32] = {0};
|
||||||
ESP_ERROR_CHECK(esp_partition_get_sha256(handle->storage_partition, sha256));
|
ESP_ERROR_CHECK(esp_partition_get_sha256(handle->storage_partition, sha256));
|
||||||
ESP_LOG_BUFFER_HEX("New Storage Partition SHA256:", sha256, sizeof(sha256));
|
ESP_LOG_BUFFER_HEX("New Storage Partition SHA256:", sha256, sizeof(sha256));
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FINISH_STORAGE_UPDATE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FINISH_STORAGE_UPDATE, NULL, 0, portMAX_DELAY));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_STORAGE_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_STORAGE_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
||||||
|
|
||||||
}
|
}
|
||||||
esp_http_client_cleanup(client);
|
esp_http_client_cleanup(client);
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t ghota_update(ghota_client_handle_t *handle)
|
||||||
esp_err_t ghota_update(ghota_client_handle_t *handle) {
|
{
|
||||||
esp_err_t ota_finish_err = ESP_OK;
|
esp_err_t ota_finish_err = ESP_OK;
|
||||||
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
if (xSemaphoreTake(ghota_lock, pdMS_TO_TICKS(1000)) != pdTRUE)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to take lock");
|
ESP_LOGE(TAG, "Failed to take lock");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Scheduled Check for Firmware Update Starting");
|
ESP_LOGI(TAG, "Scheduled Check for Firmware Update Starting");
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_START_UPDATE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_START_UPDATE, NULL, 0, portMAX_DELAY));
|
||||||
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET)) {
|
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET))
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "No Valid Release Asset Found");
|
ESP_LOGE(TAG, "No Valid Release Asset Found");
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
int cmp = semver_compare_version(handle->latest_version, handle->current_version);
|
int cmp = semver_compare_version(handle->latest_version, handle->current_version);
|
||||||
if ( cmp != 1) {
|
if (cmp != 1)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Current Version is equal or newer than new release");
|
ESP_LOGE(TAG, "Current Version is equal or newer than new release");
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_UPDATE_FAILED, NULL, 0, portMAX_DELAY));
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
|
@ -549,7 +599,8 @@ esp_err_t ghota_update(ghota_client_handle_t *handle) {
|
||||||
.buffer_size_tx = 4096,
|
.buffer_size_tx = 4096,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (handle->username) {
|
if (handle->username)
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Using Authenticated Request to %s", httpconfig.url);
|
ESP_LOGD(TAG, "Using Authenticated Request to %s", httpconfig.url);
|
||||||
httpconfig.username = handle->username;
|
httpconfig.username = handle->username;
|
||||||
httpconfig.password = handle->token;
|
httpconfig.password = handle->token;
|
||||||
|
@ -558,58 +609,74 @@ esp_err_t ghota_update(ghota_client_handle_t *handle) {
|
||||||
|
|
||||||
esp_https_ota_config_t ota_config = {
|
esp_https_ota_config_t ota_config = {
|
||||||
.http_config = &httpconfig,
|
.http_config = &httpconfig,
|
||||||
.http_client_init_cb = http_client_set_header_cb,
|
.http_client_init_cb = http_client_set_header_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
esp_https_ota_handle_t https_ota_handle = NULL;
|
esp_https_ota_handle_t https_ota_handle = NULL;
|
||||||
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
|
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed: %d", err);
|
ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed: %d", err);
|
||||||
goto ota_end;
|
goto ota_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_app_desc_t app_desc;
|
esp_app_desc_t app_desc;
|
||||||
err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
|
err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed: %d", err);
|
ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed: %d", err);
|
||||||
goto ota_end;
|
goto ota_end;
|
||||||
}
|
}
|
||||||
err = validate_image_header(&app_desc);
|
err = validate_image_header(&app_desc);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "image header verification failed: %d", err);
|
ESP_LOGE(TAG, "image header verification failed: %d", err);
|
||||||
goto ota_end;
|
goto ota_end;
|
||||||
}
|
}
|
||||||
int last_progress = -1;
|
int last_progress = -1;
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
err = esp_https_ota_perform(https_ota_handle);
|
err = esp_https_ota_perform(https_ota_handle);
|
||||||
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
|
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int32_t dl = esp_https_ota_get_image_len_read(https_ota_handle);
|
int32_t dl = esp_https_ota_get_image_len_read(https_ota_handle);
|
||||||
int32_t size = esp_https_ota_get_image_size(https_ota_handle);
|
int32_t size = esp_https_ota_get_image_size(https_ota_handle);
|
||||||
int progress = 100 * ((float)dl / (float)size);
|
int progress = 100 * ((float)dl / (float)size);
|
||||||
if ((progress % 5 == 0) && (progress != last_progress)) {
|
if ((progress % 5 == 0) && (progress != last_progress))
|
||||||
|
{
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS, &progress, sizeof(progress), portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS, &progress, sizeof(progress), portMAX_DELAY));
|
||||||
ESP_LOGV(TAG, "Firmware Update Progress: %d%%", progress);
|
ESP_LOGV(TAG, "Firmware Update Progress: %d%%", progress);
|
||||||
last_progress = progress;
|
last_progress = progress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) {
|
if (esp_https_ota_is_complete_data_received(https_ota_handle) != true)
|
||||||
|
{
|
||||||
// the OTA image was not completely received and user can customise the response to this situation.
|
// the OTA image was not completely received and user can customise the response to this situation.
|
||||||
ESP_LOGE(TAG, "Complete data was not received.");
|
ESP_LOGE(TAG, "Complete data was not received.");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ota_finish_err = esp_https_ota_finish(https_ota_handle);
|
ota_finish_err = esp_https_ota_finish(https_ota_handle);
|
||||||
if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {
|
if ((err == ESP_OK) && (ota_finish_err == ESP_OK))
|
||||||
|
{
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FINISH_UPDATE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_FINISH_UPDATE, NULL, 0, portMAX_DELAY));
|
||||||
if (strlen(handle->result.storageurl)) {
|
if (strlen(handle->result.storageurl))
|
||||||
|
{
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
if (ghota_storage_update(handle) == ESP_OK) {
|
if (ghota_storage_update(handle) == ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "Storage Update Successful");
|
ESP_LOGI(TAG, "Storage Update Successful");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Storage Update Failed");
|
ESP_LOGE(TAG, "Storage Update Failed");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
xSemaphoreGive(ghota_lock);
|
xSemaphoreGive(ghota_lock);
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
|
ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
|
||||||
|
@ -617,8 +684,11 @@ esp_err_t ghota_update(ghota_client_handle_t *handle) {
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
esp_restart();
|
esp_restart();
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
} else {
|
}
|
||||||
if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
|
else
|
||||||
|
{
|
||||||
|
if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
|
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
|
||||||
}
|
}
|
||||||
ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
|
ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
|
||||||
|
@ -636,8 +706,10 @@ ota_end:
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
semver_t *ghota_get_current_version(ghota_client_handle_t *handle) {
|
semver_t *ghota_get_current_version(ghota_client_handle_t *handle)
|
||||||
if (!handle) {
|
{
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
semver_t *cur = malloc(sizeof(semver_t));
|
semver_t *cur = malloc(sizeof(semver_t));
|
||||||
|
@ -645,11 +717,14 @@ semver_t *ghota_get_current_version(ghota_client_handle_t *handle) {
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
semver_t *ghota_get_latest_version(ghota_client_handle_t *handle) {
|
semver_t *ghota_get_latest_version(ghota_client_handle_t *handle)
|
||||||
if (!handle) {
|
{
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET)) {
|
if (!GetFlag(handle, GHOTA_RELEASE_VALID_ASSET))
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
semver_t *new = malloc(sizeof(semver_t));
|
semver_t *new = malloc(sizeof(semver_t));
|
||||||
|
@ -657,19 +732,27 @@ semver_t *ghota_get_latest_version(ghota_client_handle_t *handle) {
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ghota_task(void *pvParameters) {
|
static void ghota_task(void *pvParameters)
|
||||||
|
{
|
||||||
ghota_client_handle_t *handle = (ghota_client_handle_t *)pvParameters;
|
ghota_client_handle_t *handle = (ghota_client_handle_t *)pvParameters;
|
||||||
ESP_LOGI(TAG, "Firmware Update Task Starting");
|
ESP_LOGI(TAG, "Firmware Update Task Starting");
|
||||||
if (handle) {
|
if (handle)
|
||||||
if (ghota_check(handle) == ESP_OK) {
|
{
|
||||||
if (semver_gt(handle->latest_version, handle->current_version) == 1) {
|
if (ghota_check(handle) == ESP_OK)
|
||||||
|
{
|
||||||
|
if (semver_gt(handle->latest_version, handle->current_version) == 1)
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "New Version Available");
|
ESP_LOGI(TAG, "New Version Available");
|
||||||
ghota_update(handle);
|
ghota_update(handle);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "No New Version Available");
|
ESP_LOGI(TAG, "No New Version Available");
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, NULL, 0, portMAX_DELAY));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGI(TAG, "No Update Available");
|
ESP_LOGI(TAG, "No Update Available");
|
||||||
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, NULL, 0, portMAX_DELAY));
|
ESP_ERROR_CHECK(esp_event_post(GHOTA_EVENTS, GHOTA_EVENT_NOUPDATE_AVAILABLE, NULL, 0, portMAX_DELAY));
|
||||||
}
|
}
|
||||||
|
@ -680,41 +763,53 @@ static void ghota_task(void *pvParameters) {
|
||||||
handle->task_handle = NULL;
|
handle->task_handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_start_update_task(ghota_client_handle_t *handle) {
|
esp_err_t ghota_start_update_task(ghota_client_handle_t *handle)
|
||||||
if (!handle) {
|
{
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
eTaskState state = eInvalid;
|
eTaskState state = eInvalid;
|
||||||
TaskHandle_t tmp = xTaskGetHandle("ghota_task");
|
TaskHandle_t tmp = xTaskGetHandle("ghota_task");
|
||||||
if (tmp) {
|
if (tmp)
|
||||||
|
{
|
||||||
state = eTaskGetState(tmp);
|
state = eTaskGetState(tmp);
|
||||||
}
|
}
|
||||||
if (state == eDeleted || state == eInvalid) {
|
if (state == eDeleted || state == eInvalid)
|
||||||
|
{
|
||||||
ESP_LOGD(TAG, "Starting Task to Check for Updates");
|
ESP_LOGD(TAG, "Starting Task to Check for Updates");
|
||||||
if (xTaskCreate(ghota_task, "ghota_task", 6144, handle, 5, &handle->task_handle) != pdPASS) {
|
if (xTaskCreate(ghota_task, "ghota_task", 6144, handle, 5, &handle->task_handle) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "Failed to Start ghota_task");
|
ESP_LOGW(TAG, "Failed to Start ghota_task");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ESP_LOGW(TAG, "ghota_task Already Running");
|
ESP_LOGW(TAG, "ghota_task Already Running");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ghota_timer_callback(TimerHandle_t xTimer) {
|
static void ghota_timer_callback(TimerHandle_t xTimer)
|
||||||
|
{
|
||||||
ghota_client_handle_t *handle = (ghota_client_handle_t *)pvTimerGetTimerID(xTimer);
|
ghota_client_handle_t *handle = (ghota_client_handle_t *)pvTimerGetTimerID(xTimer);
|
||||||
if (handle) {
|
if (handle)
|
||||||
|
{
|
||||||
handle->countdown--;
|
handle->countdown--;
|
||||||
if (handle->countdown == 0) {
|
if (handle->countdown == 0)
|
||||||
|
{
|
||||||
handle->countdown = handle->config.updateInterval;
|
handle->countdown = handle->config.updateInterval;
|
||||||
ghota_start_update_task(handle);
|
ghota_start_update_task(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ghota_start_update_timer(ghota_client_handle_t *handle) {
|
esp_err_t ghota_start_update_timer(ghota_client_handle_t *handle)
|
||||||
if (!handle) {
|
{
|
||||||
|
if (!handle)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to initialize GHOTA Client");
|
ESP_LOGE(TAG, "Failed to initialize GHOTA Client");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -723,46 +818,54 @@ esp_err_t ghota_start_update_timer(ghota_client_handle_t *handle) {
|
||||||
/* run timer every minute */
|
/* run timer every minute */
|
||||||
uint64_t ticks = pdMS_TO_TICKS(1000) * 60;
|
uint64_t ticks = pdMS_TO_TICKS(1000) * 60;
|
||||||
TimerHandle_t timer = xTimerCreate("ghota_timer", ticks, pdTRUE, (void *)handle, ghota_timer_callback);
|
TimerHandle_t timer = xTimerCreate("ghota_timer", ticks, pdTRUE, (void *)handle, ghota_timer_callback);
|
||||||
if ( timer == NULL) {
|
if (timer == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to create timer");
|
ESP_LOGE(TAG, "Failed to create timer");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
} else {
|
}
|
||||||
if (xTimerStart(timer, 0) != pdPASS) {
|
else
|
||||||
|
{
|
||||||
|
if (xTimerStart(timer, 0) != pdPASS)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Failed to start timer");
|
ESP_LOGE(TAG, "Failed to start timer");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
} else {
|
}
|
||||||
ESP_LOGI(TAG, "Started Update Timer for %d Minutes", handle->config.updateInterval);
|
else
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Started Update Timer for %" PRIu32 " Minutes", handle->config.updateInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *ghota_get_event_str(ghota_event_e event) {
|
char *ghota_get_event_str(ghota_event_e event)
|
||||||
switch (event) {
|
{
|
||||||
case GHOTA_EVENT_START_CHECK:
|
switch (event)
|
||||||
return "GHOTA_EVENT_START_CHECK";
|
{
|
||||||
case GHOTA_EVENT_UPDATE_AVAILABLE:
|
case GHOTA_EVENT_START_CHECK:
|
||||||
return "GHOTA_EVENT_UPDATE_AVAILABLE";
|
return "GHOTA_EVENT_START_CHECK";
|
||||||
case GHOTA_EVENT_NOUPDATE_AVAILABLE:
|
case GHOTA_EVENT_UPDATE_AVAILABLE:
|
||||||
return "GHOTA_EVENT_NOUPDATE_AVAILABLE";
|
return "GHOTA_EVENT_UPDATE_AVAILABLE";
|
||||||
case GHOTA_EVENT_START_UPDATE:
|
case GHOTA_EVENT_NOUPDATE_AVAILABLE:
|
||||||
return "GHOTA_EVENT_START_UPDATE";
|
return "GHOTA_EVENT_NOUPDATE_AVAILABLE";
|
||||||
case GHOTA_EVENT_FINISH_UPDATE:
|
case GHOTA_EVENT_START_UPDATE:
|
||||||
return "GHOTA_EVENT_FINISH_UPDATE";
|
return "GHOTA_EVENT_START_UPDATE";
|
||||||
case GHOTA_EVENT_UPDATE_FAILED:
|
case GHOTA_EVENT_FINISH_UPDATE:
|
||||||
return "GHOTA_EVENT_UPDATE_FAILED";
|
return "GHOTA_EVENT_FINISH_UPDATE";
|
||||||
case GHOTA_EVENT_START_STORAGE_UPDATE:
|
case GHOTA_EVENT_UPDATE_FAILED:
|
||||||
return "GHOTA_EVENT_START_STORAGE_UPDATE";
|
return "GHOTA_EVENT_UPDATE_FAILED";
|
||||||
case GHOTA_EVENT_FINISH_STORAGE_UPDATE:
|
case GHOTA_EVENT_START_STORAGE_UPDATE:
|
||||||
return "GHOTA_EVENT_FINISH_STORAGE_UPDATE";
|
return "GHOTA_EVENT_START_STORAGE_UPDATE";
|
||||||
case GHOTA_EVENT_STORAGE_UPDATE_FAILED:
|
case GHOTA_EVENT_FINISH_STORAGE_UPDATE:
|
||||||
return "GHOTA_EVENT_STORAGE_UPDATE_FAILED";
|
return "GHOTA_EVENT_FINISH_STORAGE_UPDATE";
|
||||||
case GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS:
|
case GHOTA_EVENT_STORAGE_UPDATE_FAILED:
|
||||||
return "GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS";
|
return "GHOTA_EVENT_STORAGE_UPDATE_FAILED";
|
||||||
case GHOTA_EVENT_STORAGE_UPDATE_PROGRESS:
|
case GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS:
|
||||||
return "GHOTA_EVENT_STORAGE_UPDATE_PROGRESS";
|
return "GHOTA_EVENT_FIRMWARE_UPDATE_PROGRESS";
|
||||||
case GHOTA_EVENT_PENDING_REBOOT:
|
case GHOTA_EVENT_STORAGE_UPDATE_PROGRESS:
|
||||||
return "GHOTA_EVENT_PENDING_REBOOT";
|
return "GHOTA_EVENT_STORAGE_UPDATE_PROGRESS";
|
||||||
|
case GHOTA_EVENT_PENDING_REBOOT:
|
||||||
|
return "GHOTA_EVENT_PENDING_REBOOT";
|
||||||
}
|
}
|
||||||
return "Unknown Event";
|
return "Unknown Event";
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue