This commit is contained in:
cfif 2025-06-02 14:32:56 +03:00
commit 07c1d35d7c
5 changed files with 818 additions and 0 deletions

639
GetGsmFirmware.c Executable file
View File

@ -0,0 +1,639 @@
//
// 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);
}

87
GetGsmFirmware.h Executable file
View File

@ -0,0 +1,87 @@
//
// Created by cfif on 22.08.23.
//
#ifndef GETGSMFIRMWARE_H
#define GETGSMFIRMWARE_H
#include "AtCmdBase.h"
#include "Gsm_HttpGet.h"
#include "FirmwareLoader.h"
#include "LoggerToSerialPort.h"
#include "CmsisRtosThreadUtils.h"
// Количество повторений до прерывания процедуры получения файла
#define connect_http_retry 5
// Размер порции для приема
//#define portion_size (1024 - 4)
#define portion_size (1024 - 4)
#define firmware_php_uveos_req "uveos.xfsb"
#define firmware_php_tele_req "tele.xfsb"
typedef enum {
FIRMWARE_UVEOS = 0,
FIRMWARE_TELE = 1
} eFirmwareType;
typedef struct {
int stat_err_open;
int stat_err_read;
int stat_err_crc;
int stat_err_write;
int stat_err_file_crc;
} tFirmwareStats;
typedef void (EventUpdateFunc)(void *env, bool result, bool isAbortOld);
typedef struct {
tAtCmd *gsmAt;
uint8_t *firmware_buf;
tFirmwareStats *firmwareStats;
tString64 Apn;
tString64 Server;
tLoggerToSerialPort *log;
uint32_t portion_step;
uint32_t offset;
uint32_t attemptsAll;
uint32_t attempts;
uint32_t attempts_period;
volatile bool startUpdateFirmware;
volatile bool doUpdateFirmware;
osMutexId_t access;
bool isExaminationFirmware;
EventUpdateFunc *eventUpdateFunc;
void *envUpdateFunc;
// Старая прошивка
bool isAbortOld;
eFirmwareType firmwareType;
tStaticThreadBlock(1024) T_processing_Firmware;
} tGsmFirmware;
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);
void GsmFirmware_Start(tGsmFirmware *env);
void StartUpdateFirmware(tGsmFirmware *env);
#endif //GETGSMFIRMWARE_H

70
Gsm_HttpGet.c Executable file
View File

@ -0,0 +1,70 @@
//
// Created by xemon on 10.07.23.
//
#include <AtGsmSimComA7600_Http.h>
#include "Gsm_HttpGet.h"
static size_t Gsm_HttpGet_Open_Dir(tAtCmd *env, char *url, size_t urlSize) {
AtCommandResult res;
res = AtGsmSimComA7600_HttpInit(env);
if (res != AT_OK) {
return 0;
}
res = AtGsmSimComA7600_HttpSetUrl(env, url, urlSize);
if (res != AT_OK) {
return 0;
}
uint16_t responseCode;
size_t len;
res = AtGsmSimComA7600_HttpMethodAction(env, eAtGsmSimComA7600_HttpMethod_GET, &responseCode, &len, 10000);
if (res != AT_OK) {
return 0;
}
if (responseCode != 200) {
return 0;
}
return len;
}
static size_t Gsm_HttpGet_Read_Dir(tAtCmd *env, uint8_t *data, size_t dataLimit) {
size_t read;
AtCommandResult res = AtGsmSimComA7600_HttpRead(env, data, 0, dataLimit, &read);
if (res != AT_OK) { return 0; }
return read;
}
size_t Gsm_HttpGet_Open(tAtCmd *env, char *url, size_t urlSize) {
size_t res = 0;
if (osMutexAcquire(env->access, 2000) == osOK) {
res = Gsm_HttpGet_Open_Dir(env, url, urlSize);
osMutexRelease(env->access);
}
return res;
}
size_t Gsm_HttpGet_Read(tAtCmd *env, uint8_t *data, size_t dataLimit) {
size_t res = 0;
if (osMutexAcquire(env->access, 2000) == osOK) {
res = Gsm_HttpGet_Read_Dir(env, data, dataLimit);
osMutexRelease(env->access);
}
return res;
}
bool Gsm_HttpGet_Close(tAtCmd *env) {
bool res = false;
if (osMutexAcquire(env->access, 2000) == osOK) {
res = AtGsmSimComA7600_HttpTerminate(env) == AT_OK;
osMutexRelease(env->access);
}
return res;
}

12
Gsm_HttpGet.h Normal file
View File

@ -0,0 +1,12 @@
//
// Created by cfif on 03.07.2024.
//
#ifndef SMART_COMPONENTS_UPDATE_GSM_HTTPGET_H
#define SMART_COMPONENTS_UPDATE_GSM_HTTPGET_H
size_t Gsm_HttpGet_Open(tAtCmd *env, char *url, size_t urlSize);
size_t Gsm_HttpGet_Read(tAtCmd *env, uint8_t *data, size_t dataLimit);
bool Gsm_HttpGet_Close(tAtCmd *env);
#endif //SMART_COMPONENTS_UPDATE_GSM_HTTPGET_H

10
modular.json Executable file
View File

@ -0,0 +1,10 @@
{
"cmake": {
"inc_dirs": [
"./"
],
"srcs": [
"./**.c"
]
}
}