SMART_COMPONENTS_GetGsmFirm.../GetGsmFirmware.c

640 lines
22 KiB
C
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by cfif on 22.08.23.
//
#include "GetGsmFirmware.h"
#include "string.h"
#include "stdlib.h"
#include "FirmwareLoader.h"
#include "ld_adr.h"
#include "InternalFlashPage.h"
#include "AtGsm_NetworkRegistrationStatus.h"
#include "AtGsmOperatorSelection.h"
#include "SystemDelayInterface.h"
#include "AtGsmSimComA7600_DefinePdpContext.h"
#define LOG_SIGN "UPDATE"
#define LOGGER &env->log->logger
#define FIRMWARE_MAIN_ADDR (0x08000000 + BOOT_AREA_LENGTH)
#define FIRMWARE_MAIN_RECOVERY_ADDR (FIRMWARE_MAIN_ADDR + FIRMWARE_MAIN_AREA_LENGTH)
#define FIRMWARE_TELE_MAIN_ADDR (FIRMWARE_MAIN_RECOVERY_ADDR + FIRMWARE_MAIN_UPDATE_AREA_LENGTH)
#define FIRMWARE_TELE_RECOVERY_ADDR (FIRMWARE_MAIN_ADDR + FIRMWARE_MAIN_AREA_LENGTH)
tFirmwareLoader FIRMWARE_UVEOS_LOADER;
static uint32_t GetGsmFirmwareCrc32(const uint8_t *buf, size_t size) {
uint32_t crc = 0;
for (size_t i = 0; i < size; ++i) {
crc += buf[i];
}
return crc;
}
static bool WaitNetworkRegistration(tGsmFirmware *env, tAtCmd *gsmAt, uint16_t timeReg) {
uint32_t timeEnd = SystemGetMs() + timeReg;
tAtGsm_NetworkRegistrationReportMode mode;
tAtGsm_NetworkRegistrationState state;
while (timeEnd > SystemGetMs()) {
if (AtGsm_NetworkRegistrationStatus(gsmAt, &mode, &state)) {
if (state == AT_NETWORK_REGISTRATION_STATE_REGISTERED_HOME ||
state == AT_NETWORK_REGISTRATION_STATE_REGISTERED_ROAMING) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена регистрация")
return true;
}
}
SystemDelayMs(60);
}
return false;
}
static bool NetworkRequire(tGsmFirmware *env, tAtCmd *gsmAt) {
bool result = false;
if (osMutexAcquire(gsmAt->access, 2000) == osOK) {
if (!WaitNetworkRegistration(env, gsmAt, 2000)) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Включение регистрации в сети");
for (uint8_t i = 0; i < 5; ++i) {
AtGsm_OperatorSelectionAutomatic(gsmAt);
SystemDelayMs(150);
}
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ждем сеть...");
if (WaitNetworkRegistration(env, gsmAt, 2000)) {
result = true;
LoggerInfoStatic(LOGGER, LOG_SIGN, "Регистрация в сети получена");
} else {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Регистрация в сети не получена");
}
} else {
result = true;
LoggerInfoStatic(LOGGER, LOG_SIGN, "Регистрация в сети присутствует");
}
osMutexRelease(gsmAt->access);
}
return result;
}
static int getFileSizeFirmware(tGsmFirmware *env, tAtCmd *gsmAt, char *firmware_php_path_req, uint8_t *firmware_buf) {
char url[128];
url[0] = '\0';
strcat(url, firmware_php_path_req);
strcat(url, "?file=");
if (env->firmwareType == FIRMWARE_UVEOS) {
strcat(url, firmware_php_uveos_req);
}
if (env->firmwareType == FIRMWARE_TELE) {
strcat(url, firmware_php_tele_req);
}
strcat(url, "&return_size=1");
int FileSizeCurrent = 0;
int connection_step = 0;
while (connection_step < connect_http_retry) {
Gsm_HttpGet_Close(gsmAt);
size_t fileSize = Gsm_HttpGet_Open(gsmAt, url, strlen(url));
if (fileSize > 0) {
size_t read = Gsm_HttpGet_Read(gsmAt, firmware_buf, 2048);
if (read > 0) {
FileSizeCurrent = atoi((char *) firmware_buf);
break;
} else {
++connection_step;
}
} else {
++connection_step;
}
}
return FileSizeCurrent;
}
static int getMetadataFirmware(tGsmFirmware *env, tAtCmd *gsmAt, char *firmware_php_path_req, int sizeFileFirmware,
uint8_t *firmware_buf) {
char buf[12];
char url[128];
url[0] = '\0';
strcat(url, firmware_php_path_req);
strcat(url, "?offset=");
int offsetMeta = sizeFileFirmware - FIRMWARE_META_LENGTH;
utoa(offsetMeta, buf, 10);
strcat(url, buf);
strcat(url, "&limit=");
utoa(FIRMWARE_META_LENGTH, buf, 10);
strcat(url, buf);
strcat(url, "&file=");
if (env->firmwareType == FIRMWARE_UVEOS) {
strcat(url, firmware_php_uveos_req);
}
if (env->firmwareType == FIRMWARE_TELE) {
strcat(url, firmware_php_tele_req);
}
int connection_step = 0;
size_t fileSizeMeta = 0;
while (connection_step < connect_http_retry) {
if (env->startUpdateFirmware == false)
return 0;
Gsm_HttpGet_Close(gsmAt);
fileSizeMeta = Gsm_HttpGet_Open(gsmAt, url, strlen(url));
if (fileSizeMeta > 0) {
size_t read = Gsm_HttpGet_Read(gsmAt, firmware_buf, 2048);
if (read > 0) {
break;
} else {
++connection_step;
}
} else {
++connection_step;
}
}
return (int) fileSizeMeta;
}
static bool
getFileBodyFirmware(tGsmFirmware *env, bool isDoGsmFirmware) {
if (env->Server.length < 1) {
LoggerStrInfoStatic(LOGGER, LOG_SIGN, "Ошибка. Не введен адреса сервера обновления");
return false;
}
if (NetworkRequire(env, env->gsmAt)) {
LoggerStrInfoStatic(LOGGER, LOG_SIGN, "Начало обновления прошивки");
} else {
LoggerStrInfoStatic(LOGGER, LOG_SIGN, "Ошибка. Нет регистрации в сети");
return false;
}
memset(env->firmwareStats, 0, sizeof(tFirmwareStats));
AtCommandResult res = AtGsmSimComA7600_PdpActivate(env->gsmAt, 2);
res = AtGsmSimComA7600_DefinePdpContext(env->gsmAt, 2, AtGsmSimComA7600_PdpType_IP,
env->Apn.data,
env->Apn.length);
res = AtGsmSimComA7600_PdpActivate(env->gsmAt, 2);
uint32_t connection_step = 0;
size_t FileSizeCurrent = 0;
while ((FileSizeCurrent == 0) && (connection_step < connect_http_retry)) {
if (env->startUpdateFirmware == false)
return false;
FileSizeCurrent = getFileSizeFirmware(env, env->gsmAt, env->Server.data, env->firmware_buf);
if (FileSizeCurrent == 0) {
++env->firmwareStats->stat_err_open;
++connection_step;
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Получение размера прошивки. Ошибка соединения с сервером. Попытка: %d из %d",
connection_step, connect_http_retry);
SystemDelayMs(3000);
}
}
if (FileSizeCurrent == 0) {
return false;
}
connection_step = 0;
size_t FileSizeMeta = 0;
while ((FileSizeMeta == 0) && (connection_step < connect_http_retry)) {
if (env->startUpdateFirmware == false)
return false;
FileSizeMeta = getMetadataFirmware(env, env->gsmAt, env->Server.data, (int) FileSizeCurrent, env->firmware_buf);
if (FileSizeMeta == 0) {
++env->firmwareStats->stat_err_open;
++connection_step;
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Получение метаданных прошивки. Ошибка соединения с сервером. Попытка: %d из %d",
connection_step, connect_http_retry);
SystemDelayMs(3000);
}
}
if (FileSizeMeta == 0) {
return false;
}
// Проверка нужно ли обновляться
if (env->isExaminationFirmware) {
tFirmwareLoader FIRMWARE_HTTP;
FirmwareLoader_Init(&FIRMWARE_HTTP, FIRMWARE_META_LENGTH, 0, (uint32_t) &env->firmware_buf[0]);
FirmwareLoader_LoadMetadata(&FIRMWARE_HTTP, &FIRMWARE_HTTP.update);
uint32_t httpCrc32 = *FIRMWARE_HTTP.update.metadata.crc;
uint32_t uveosCrc32 = *FIRMWARE_UVEOS_LOADER.main.metadata.crc;
bool sameNames =
(*FIRMWARE_UVEOS_LOADER.main.metadata.nameLength == *FIRMWARE_HTTP.update.metadata.nameLength) &&
memcmp(
FIRMWARE_UVEOS_LOADER.main.metadata.name,
FIRMWARE_HTTP.update.metadata.name,
*FIRMWARE_HTTP.update.metadata.nameLength) == 0;
if ((uveosCrc32 == httpCrc32) && sameNames) {
env->isAbortOld = true;
LoggerStrInfoStatic(LOGGER, LOG_SIGN, "Прошивка в обновлении не нуждается");
return true;
}
}
if (!isDoGsmFirmware) {
if (osMutexAcquire(env->access, 5000) == osOK) {
if (FirmwareLoader_ClearUpdateFlash(&FIRMWARE_UVEOS_LOADER)) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "ПЗУ очищено");
} else {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка очистки ПЗУ");
++env->firmwareStats->stat_err_write;
osMutexRelease(env->access);
return false;
}
osMutexRelease(env->access);
}
} else {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Очистка ПЗУ не требуется");
}
char url[128];
char buf[12];
uint32_t portion_full = FileSizeCurrent / portion_size;
uint32_t portion_size_tail = FileSizeCurrent % portion_size;
if (portion_size_tail > 0)
++portion_full;
uint32_t limit = portion_size;
connection_step = 0;
if (!isDoGsmFirmware) {
env->offset = 0;
env->portion_step = 0;
}
env->firmwareStats->stat_err_open = 0;
env->firmwareStats->stat_err_read = 0;
env->firmwareStats->stat_err_crc = 0;
env->firmwareStats->stat_err_write = 0;
// Цикл по всем порциям
while ((env->portion_step < portion_full) && (connection_step < connect_http_retry)) {
if (env->startUpdateFirmware == false)
return false;
Gsm_HttpGet_Close(env->gsmAt);
url[0] = '\0';
strcat(url, env->Server.data);
strcat(url, "?offset=");
utoa(env->offset, buf, 10);
strcat(url, buf);
strcat(url, "&limit=");
utoa(limit, buf, 10);
strcat(url, buf);
strcat(url, "&file=");
if (env->firmwareType == FIRMWARE_UVEOS) {
strcat(url, firmware_php_uveos_req);
}
if (env->firmwareType == FIRMWARE_TELE) {
strcat(url, firmware_php_tele_req);
}
size_t fileSize = Gsm_HttpGet_Open(env->gsmAt, url, strlen(url));
if (fileSize == limit + 4) {
size_t read = Gsm_HttpGet_Read(env->gsmAt, env->firmware_buf, fileSize);
if (read == fileSize) {
uint32_t crc_recv = ((uint32_t *) &env->firmware_buf[limit])[0];
uint32_t crc_calc = GetGsmFirmwareCrc32(env->firmware_buf, limit);
if (crc_recv != crc_calc) {
++env->firmwareStats->stat_err_crc;
++connection_step;
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Ошибка контрольной суммы данных от сервера. Попытка: %d из %d",
connection_step, connect_http_retry);
continue;
}
connection_step = 0;
++env->portion_step;
if (osMutexAcquire(env->access, 5000) == osOK) {
if (sInternalFlashPage_Write(FIRMWARE_UVEOS_LOADER.update.address, env->offset, env->firmware_buf,
limit) == limit) {
LoggerStrFormatInfo(LOGGER, LOG_SIGN, "Загружено: %d из %d", env->portion_step, portion_full);
} else {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка записи в ПЗУ");
++env->firmwareStats->stat_err_write;
osMutexRelease(env->access);
return false;
}
osMutexRelease(env->access);
}
if ((portion_size_tail > 0) && (env->portion_step == portion_full - 1)) {
env->offset += portion_size;
limit = portion_size_tail;
} else {
env->offset += portion_size;
}
} else {
++env->firmwareStats->stat_err_read;
++connection_step;
LoggerStrFormatInfo(LOGGER, LOG_SIGN, "Ошибка получения данных от сервера. Попытка: %d из %d",
connection_step, connect_http_retry);
SystemDelayMs(500);
}
} else {
++env->firmwareStats->stat_err_open;
++connection_step;
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Получение данных прошивки. Ошибка соединения с сервером. Попытка: %d из %d",
connection_step, connect_http_retry);
SystemDelayMs(3000);
}
}
if ((connection_step == connect_http_retry) || (env->firmwareStats->stat_err_write != 0)) {
return false;
}
return true;
}
bool GetDoGsmFirmware(tGsmFirmware *env) {
bool isLoadFirmware = getFileBodyFirmware(env, true);
return isLoadFirmware;
}
bool GetGsmFirmware(tGsmFirmware *env) {
bool isLoadFirmware = getFileBodyFirmware(env, false);
return isLoadFirmware;
}
void StartUpdateFirmware(tGsmFirmware *env) {
env->doUpdateFirmware = false;
env->startUpdateFirmware = true;
env->isAbortOld = false;
}
void _Noreturn FirmwareProcessingTask(tGsmFirmware *env) {
// uint32_t attempts;
for (;;) {
if (env->startUpdateFirmware) {
if (env->doUpdateFirmware) {
bool result = GetDoGsmFirmware(env);
if (env->startUpdateFirmware == false) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Выход из режима обновления УВЭОС");
continue;
}
if (result) {
env->startUpdateFirmware = false;
env->doUpdateFirmware = false;
LoggerInfoStatic(LOGGER, LOG_SIGN, "Успех. Обновление завершено без ошибок");
env->eventUpdateFunc(env->envUpdateFunc, true, env->isAbortOld);
} else {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка. Обновление не завершено");
--env->attempts;
env->eventUpdateFunc(env->envUpdateFunc, false, env->isAbortOld);
if (env->attempts > 0) {
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Обновление будет завершено позже, через %d сек. Осталось попыток %d из %d",
env->attempts_period,
env->attempts,
env->attemptsAll);
for (uint32_t i = 0; i < env->attempts_period; ++i) {
if (env->startUpdateFirmware == false) {
break;
}
SystemDelayMs(1000);
}
if (env->startUpdateFirmware == false) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Выход из режима обновления УВЭОС");
continue;
}
} else {
env->startUpdateFirmware = false;
env->doUpdateFirmware = false;
LoggerInfoStatic(LOGGER, LOG_SIGN,
"Попытки исчерпаны. Обновление будет завершено после получения команды на обновление");
}
}
} else {
bool result = GetGsmFirmware(env);
if (env->startUpdateFirmware == false) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Выход из режима обновления УВЭОС");
continue;
}
if (result) {
env->startUpdateFirmware = false;
LoggerInfoStatic(LOGGER, LOG_SIGN, "Успех. Обновление завершено без ошибок");
env->eventUpdateFunc(env->envUpdateFunc, true, env->isAbortOld);
} else {
// attempts = env->attempts;
env->doUpdateFirmware = true;
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка. Обновление не завершено");
env->eventUpdateFunc(env->envUpdateFunc, false, env->isAbortOld);
if (env->attempts > 0) {
LoggerStrFormatInfo(LOGGER, LOG_SIGN,
"Обновление будет завершено позже, через %d сек. Осталось попыток %d из %d",
env->attempts_period,
env->attempts,
env->attemptsAll);
for (uint32_t i = 0; i < env->attempts_period; ++i) {
if (env->startUpdateFirmware == false) {
break;
}
SystemDelayMs(1000);
}
if (env->startUpdateFirmware == false) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Выход из режима обновления УВЭОС");
continue;
}
} else {
/*
LoggerInfoStatic(LOGGER, LOG_SIGN, "Дополнительные 100 попыток");
env->attempts = 100;
*/
for (uint32_t i = 0; i < env->attempts_period; ++i) {
if (env->startUpdateFirmware == false) {
break;
}
SystemDelayMs(1000);
}
if (env->startUpdateFirmware == false) {
LoggerInfoStatic(LOGGER, LOG_SIGN, "Выход из режима обновления УВЭОС");
continue;
}
env->startUpdateFirmware = false;
env->doUpdateFirmware = false;
LoggerInfoStatic(LOGGER, LOG_SIGN,
"Попытки исчерпаны. Обновление будет завершено после получения команды на обновление");
}
}
}
}
SystemDelayMs(1000);
}
}
void InitGsmFirmware(tGsmFirmware *env,
tAtCmd *gsmAt,
eFirmwareType firmwareType,
uint8_t *firmware_buf,
tFirmwareStats *firmwareStats,
tString64 *Apn,
tString64 *Server,
uint32_t attempts,
uint32_t attempts_period,
osMutexId_t access,
bool isExaminationFirmware,
EventUpdateFunc *eventUpdateFunc,
void *envUpdateFunc,
tLoggerToSerialPort *log) {
if (firmwareType == FIRMWARE_UVEOS) {
FirmwareLoader_Init(&FIRMWARE_UVEOS_LOADER, FIRMWARE_MAIN_AREA_LENGTH, FIRMWARE_MAIN_ADDR,
FIRMWARE_MAIN_RECOVERY_ADDR);
}
if (firmwareType == FIRMWARE_TELE) {
FirmwareLoader_Init(&FIRMWARE_UVEOS_LOADER, FIRMWARE_TELE_AREA_LENGTH, FIRMWARE_TELE_MAIN_ADDR,
FIRMWARE_MAIN_RECOVERY_ADDR);
}
bool mainFwOk = FirmwareLoader_CheckBlock(&FIRMWARE_UVEOS_LOADER, &FIRMWARE_UVEOS_LOADER.main);
env->isExaminationFirmware = isExaminationFirmware;
env->access = access;
env->firmwareType = firmwareType;
env->doUpdateFirmware = false;
env->startUpdateFirmware = false;
env->eventUpdateFunc = eventUpdateFunc;
env->envUpdateFunc = envUpdateFunc;
env->attemptsAll = attempts;
env->attempts = attempts;
env->attempts_period = attempts_period;
env->gsmAt = gsmAt;
env->firmware_buf = firmware_buf;
env->firmwareStats = firmwareStats;
memset(env->Apn.data, 0, sizeof(env->Apn.data));
env->Apn.length = Apn->length;
memcpy(&env->Apn.data, Apn->data, Apn->length);
memset(env->Server.data, 0, sizeof(env->Server.data));
env->Server.length = Server->length;
memcpy(&env->Server.data, Server->data, Server->length);
env->log = log;
InitThreadBlock(env->T_processing_Firmware, "Firmware", osPriorityNormal);
}
void GsmFirmware_Start(tGsmFirmware *env) {
ThreadBlock_Start(env->T_processing_Firmware, env, FirmwareProcessingTask);
}