[FL-2527] Updater: Migrating to new manifest path convention (#1213)
* Updater: Migrating to new manifest path convention * RPC: Added update preparation status to RPC * RPC: bumped protobuf submodule * Bumped protobuf_version.h * FuriCore: add missing include. Lib: make mlib smaller * Explicitly tell where we have doubles and fix random in animations * makefile: added -DLFS_NO_DEBUG * Updater: path len constant dedup * Updater: checking for hardware version match before parsing manifest * LD: moved _DRIVER_CONTEXT sections to .bss, where they belong. * LD: avoiding PROBGITS warning, moved _CONTEXT to data * Updater: Added version check on update package - refusing to install outdated Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
dfdc33b076
commit
597ee5b939
@ -68,7 +68,7 @@ static void bt_cli_command_carrier_rx(Cli* cli, string_t args, void* context) {
|
|||||||
|
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
osDelay(250);
|
osDelay(250);
|
||||||
printf("RSSI: %6.1f dB\r", furi_hal_bt_get_rssi());
|
printf("RSSI: %6.1f dB\r", (double)furi_hal_bt_get_rssi());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +140,9 @@ static void bt_cli_command_packet_rx(Cli* cli, string_t args, void* context) {
|
|||||||
printf("Press CTRL+C to stop\r\n");
|
printf("Press CTRL+C to stop\r\n");
|
||||||
furi_hal_bt_start_packet_rx(channel, datarate);
|
furi_hal_bt_start_packet_rx(channel, datarate);
|
||||||
|
|
||||||
float rssi_raw = 0;
|
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
osDelay(250);
|
osDelay(250);
|
||||||
rssi_raw = furi_hal_bt_get_rssi();
|
printf("RSSI: %03.1f dB\r", (double)furi_hal_bt_get_rssi());
|
||||||
printf("RSSI: %03.1f dB\r", rssi_raw);
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
uint16_t packets_received = furi_hal_bt_stop_packet_test();
|
uint16_t packets_received = furi_hal_bt_stop_packet_test();
|
||||||
|
@ -99,7 +99,7 @@ static void bt_test_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
canvas_draw_str(canvas, 6, 60, model->message);
|
canvas_draw_str(canvas, 6, 60, model->message);
|
||||||
if(model->state == BtTestStateStarted) {
|
if(model->state == BtTestStateStarted) {
|
||||||
if(model->rssi != 0.0f) {
|
if(model->rssi != 0.0f) {
|
||||||
snprintf(info_str, sizeof(info_str), "RSSI:%3.1f dB", model->rssi);
|
snprintf(info_str, sizeof(info_str), "RSSI:%3.1f dB", (double)model->rssi);
|
||||||
canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str);
|
canvas_draw_str_aligned(canvas, 124, 60, AlignRight, AlignBottom, info_str);
|
||||||
}
|
}
|
||||||
} else if(model->state == BtTestStateStopped) {
|
} else if(model->state == BtTestStateStopped) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <gui/view_stack.h>
|
#include <gui/view_stack.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
#include <furi_hal.h>
|
||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
#include <portmacro.h>
|
#include <portmacro.h>
|
||||||
#include <dolphin/dolphin.h>
|
#include <dolphin/dolphin.h>
|
||||||
@ -391,7 +392,7 @@ static StorageAnimation*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lucky_number = random() % whole_weight;
|
uint32_t lucky_number = furi_hal_random_get() % whole_weight;
|
||||||
uint32_t weight = 0;
|
uint32_t weight = 0;
|
||||||
|
|
||||||
StorageAnimation* selected = NULL;
|
StorageAnimation* selected = NULL;
|
||||||
|
@ -100,7 +100,8 @@ static const FrameBubble*
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t index = random() % (active ? model->active_bubbles : model->passive_bubbles);
|
uint8_t index =
|
||||||
|
furi_hal_random_get() % (active ? model->active_bubbles : model->passive_bubbles);
|
||||||
const BubbleAnimation* animation = model->current;
|
const BubbleAnimation* animation = model->current;
|
||||||
|
|
||||||
for(int i = 0; i < animation->frame_bubble_sequences_count; ++i) {
|
for(int i = 0; i < animation->frame_bubble_sequences_count; ++i) {
|
||||||
|
@ -145,7 +145,7 @@ bool infrared_parser_is_raw_signal_valid(
|
|||||||
frequency);
|
frequency);
|
||||||
result = false;
|
result = false;
|
||||||
} else if((duty_cycle <= 0) || (duty_cycle > 1)) {
|
} else if((duty_cycle <= 0) || (duty_cycle > 1)) {
|
||||||
FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", duty_cycle);
|
FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)duty_cycle);
|
||||||
result = false;
|
result = false;
|
||||||
} else if((timings_cnt <= 0) || (timings_cnt > MAX_TIMINGS_AMOUNT)) {
|
} else if((timings_cnt <= 0) || (timings_cnt > MAX_TIMINGS_AMOUNT)) {
|
||||||
FURI_LOG_E(
|
FURI_LOG_E(
|
||||||
|
@ -29,6 +29,8 @@ void LfRfidViewTuneVM::view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
|
|
||||||
constexpr uint8_t buffer_size = 128;
|
constexpr uint8_t buffer_size = 128;
|
||||||
char buffer[buffer_size + 1];
|
char buffer[buffer_size + 1];
|
||||||
|
double freq = ((float)SystemCoreClock / ((float)model->ARR + 1));
|
||||||
|
double duty = ((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f;
|
||||||
snprintf(
|
snprintf(
|
||||||
buffer,
|
buffer,
|
||||||
buffer_size,
|
buffer_size,
|
||||||
@ -38,10 +40,10 @@ void LfRfidViewTuneVM::view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
"duty = %.4f",
|
"duty = %.4f",
|
||||||
model->pos == 0 ? ">" : "",
|
model->pos == 0 ? ">" : "",
|
||||||
model->ARR,
|
model->ARR,
|
||||||
(float)SystemCoreClock / ((float)model->ARR + 1),
|
freq,
|
||||||
model->pos == 1 ? ">" : "",
|
model->pos == 1 ? ">" : "",
|
||||||
model->CCR,
|
model->CCR,
|
||||||
((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f);
|
duty);
|
||||||
elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer);
|
elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,15 +275,22 @@ static void rpc_system_system_update_request_process(const PB_Main* request, voi
|
|||||||
RpcSession* session = (RpcSession*)context;
|
RpcSession* session = (RpcSession*)context;
|
||||||
furi_assert(session);
|
furi_assert(session);
|
||||||
|
|
||||||
bool update_prepare_result =
|
UpdatePrepareResult update_prepare_result =
|
||||||
update_operation_prepare(request->content.system_update_request.update_manifest) ==
|
update_operation_prepare(request->content.system_update_request.update_manifest);
|
||||||
UpdatePrepareResultOK;
|
/* RPC enum does not have such entry; setting to closest one */
|
||||||
|
if(update_prepare_result == UpdatePrepareResultOutdatedManifestVersion) {
|
||||||
|
update_prepare_result = UpdatePrepareResultManifestInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
PB_Main* response = malloc(sizeof(PB_Main));
|
PB_Main* response = malloc(sizeof(PB_Main));
|
||||||
response->command_id = request->command_id;
|
response->command_id = request->command_id;
|
||||||
response->has_next = false;
|
response->has_next = false;
|
||||||
response->command_status = update_prepare_result ? PB_CommandStatus_OK :
|
response->command_status = (update_prepare_result == UpdatePrepareResultOK) ?
|
||||||
PB_CommandStatus_ERROR_INVALID_PARAMETERS;
|
PB_CommandStatus_OK :
|
||||||
|
PB_CommandStatus_ERROR_INVALID_PARAMETERS;
|
||||||
|
response->which_content = PB_Main_system_update_response_tag;
|
||||||
|
response->content.system_update_response.code =
|
||||||
|
(PB_System_UpdateResponse_UpdateResultCode)update_prepare_result;
|
||||||
rpc_send_and_release(session, response);
|
rpc_send_and_release(session, response);
|
||||||
free(response);
|
free(response);
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
|
|||||||
|
|
||||||
while(!cli_cmd_interrupt_received(cli)) {
|
while(!cli_cmd_interrupt_received(cli)) {
|
||||||
osDelay(250);
|
osDelay(250);
|
||||||
printf("RSSI: %03.1fdbm\r", furi_hal_subghz_get_rssi());
|
printf("RSSI: %03.1fdbm\r", (double)furi_hal_subghz_get_rssi());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ void unit_tests_cli(Cli* cli, string_t args, void* context) {
|
|||||||
|
|
||||||
cycle_counter = (furi_hal_get_tick() - cycle_counter);
|
cycle_counter = (furi_hal_get_tick() - cycle_counter);
|
||||||
|
|
||||||
FURI_LOG_I(TAG, "Consumed: %0.2fs", (float)cycle_counter / 1000);
|
FURI_LOG_I(TAG, "Consumed: %u us", cycle_counter);
|
||||||
|
|
||||||
if(test_result == 0) {
|
if(test_result == 0) {
|
||||||
furi_hal_delay_ms(200); /* wait for tested services and apps to deallocate */
|
furi_hal_delay_ms(200); /* wait for tested services and apps to deallocate */
|
||||||
|
@ -52,7 +52,7 @@ static void updater_cli_restore(string_t args) {
|
|||||||
static void updater_cli_help(string_t args) {
|
static void updater_cli_help(string_t args) {
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
printf("Commands:\r\n"
|
printf("Commands:\r\n"
|
||||||
"\tinstall /ext/update/PACKAGE/update.fuf - verify & apply update package\r\n"
|
"\tinstall /ext/path/to/update.fuf - verify & apply update package\r\n"
|
||||||
"\tbackup /ext/path/to/backup.tar - create internal storage backup\r\n"
|
"\tbackup /ext/path/to/backup.tar - create internal storage backup\r\n"
|
||||||
"\trestore /ext/path/to/backup.tar - restore internal storage backup\r\n");
|
"\trestore /ext/path/to/backup.tar - restore internal storage backup\r\n");
|
||||||
}
|
}
|
||||||
|
@ -260,16 +260,18 @@ bool update_task_parse_manifest(UpdateTask* update_task) {
|
|||||||
string_init(manifest_path);
|
string_init(manifest_path);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
update_task_set_progress(update_task, UpdateTaskStageProgress, 10);
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 13);
|
||||||
if(!update_operation_get_current_package_path(
|
if(!furi_hal_version_do_i_belong_here()) {
|
||||||
update_task->storage, update_task->update_path)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
path_concat(
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 20);
|
||||||
string_get_cstr(update_task->update_path),
|
if(!update_operation_get_current_package_manifest_path(
|
||||||
UPDATE_MANIFEST_DEFAULT_NAME,
|
update_task->storage, manifest_path)) {
|
||||||
manifest_path);
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_extract_dirname(string_get_cstr(manifest_path), update_task->update_path);
|
||||||
update_task_set_progress(update_task, UpdateTaskStageProgress, 30);
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 30);
|
||||||
|
|
||||||
UpdateManifest* manifest = update_task->manifest;
|
UpdateManifest* manifest = update_task->manifest;
|
||||||
@ -277,6 +279,16 @@ bool update_task_parse_manifest(UpdateTask* update_task) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 40);
|
||||||
|
if(manifest->manifest_version < UPDATE_OPERATION_MIN_MANIFEST_VERSION) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 50);
|
||||||
|
if(manifest->target != furi_hal_version_get_hw_target()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
update_task->state.groups = update_task_get_task_groups(update_task);
|
update_task->state.groups = update_task_get_task_groups(update_task);
|
||||||
for(size_t stage_counter = 0; stage_counter < COUNT_OF(update_task_stage_progress);
|
for(size_t stage_counter = 0; stage_counter < COUNT_OF(update_task_stage_progress);
|
||||||
++stage_counter) {
|
++stage_counter) {
|
||||||
@ -286,13 +298,13 @@ bool update_task_parse_manifest(UpdateTask* update_task) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update_task_set_progress(update_task, UpdateTaskStageProgress, 50);
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 60);
|
||||||
if((update_task->state.groups & UpdateTaskStageGroupFirmware) &&
|
if((update_task->state.groups & UpdateTaskStageGroupFirmware) &&
|
||||||
!update_task_check_file_exists(update_task, manifest->firmware_dfu_image)) {
|
!update_task_check_file_exists(update_task, manifest->firmware_dfu_image)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_task_set_progress(update_task, UpdateTaskStageProgress, 70);
|
update_task_set_progress(update_task, UpdateTaskStageProgress, 80);
|
||||||
if((update_task->state.groups & UpdateTaskStageGroupRadio) &&
|
if((update_task->state.groups & UpdateTaskStageGroupRadio) &&
|
||||||
(!update_task_check_file_exists(update_task, manifest->radio_image) ||
|
(!update_task_check_file_exists(update_task, manifest->radio_image) ||
|
||||||
(manifest->radio_version.version.type == 0))) {
|
(manifest->radio_version.version.type == 0))) {
|
||||||
|
@ -63,7 +63,6 @@ static bool update_task_post_update(UpdateTask* update_task) {
|
|||||||
|
|
||||||
TarArchive* archive = tar_archive_alloc(update_task->storage);
|
TarArchive* archive = tar_archive_alloc(update_task->storage);
|
||||||
do {
|
do {
|
||||||
CHECK_RESULT(update_task_parse_manifest(update_task));
|
|
||||||
path_concat(
|
path_concat(
|
||||||
string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, file_path);
|
string_get_cstr(update_task->update_path), LFS_BACKUP_DEFAULT_FILENAME, file_path);
|
||||||
|
|
||||||
@ -114,7 +113,7 @@ int32_t update_task_worker_backup_restore(void* context) {
|
|||||||
return UPDATE_TASK_NOERR;
|
return UPDATE_TASK_NOERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!update_operation_get_current_package_path(update_task->storage, update_task->update_path)) {
|
if(!update_task_parse_manifest(update_task)) {
|
||||||
return UPDATE_TASK_FAILED;
|
return UPDATE_TASK_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,7 @@ typedef struct _PB_Main {
|
|||||||
PB_Storage_BackupRestoreRequest storage_backup_restore_request;
|
PB_Storage_BackupRestoreRequest storage_backup_restore_request;
|
||||||
PB_System_PowerInfoRequest system_power_info_request;
|
PB_System_PowerInfoRequest system_power_info_request;
|
||||||
PB_System_PowerInfoResponse system_power_info_response;
|
PB_System_PowerInfoResponse system_power_info_response;
|
||||||
|
PB_System_UpdateResponse system_update_response;
|
||||||
} content;
|
} content;
|
||||||
} PB_Main;
|
} PB_Main;
|
||||||
|
|
||||||
@ -171,6 +172,7 @@ extern "C" {
|
|||||||
#define PB_Main_storage_backup_restore_request_tag 43
|
#define PB_Main_storage_backup_restore_request_tag 43
|
||||||
#define PB_Main_system_power_info_request_tag 44
|
#define PB_Main_system_power_info_request_tag 44
|
||||||
#define PB_Main_system_power_info_response_tag 45
|
#define PB_Main_system_power_info_response_tag 45
|
||||||
|
#define PB_Main_system_update_response_tag 46
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define PB_Empty_FIELDLIST(X, a) \
|
#define PB_Empty_FIELDLIST(X, a) \
|
||||||
@ -228,7 +230,8 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_update_request,content.system
|
|||||||
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_create_request,content.storage_backup_create_request), 42) \
|
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_create_request,content.storage_backup_create_request), 42) \
|
||||||
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_restore_request,content.storage_backup_restore_request), 43) \
|
X(a, STATIC, ONEOF, MSG_W_CB, (content,storage_backup_restore_request,content.storage_backup_restore_request), 43) \
|
||||||
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_request,content.system_power_info_request), 44) \
|
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_request,content.system_power_info_request), 44) \
|
||||||
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_response,content.system_power_info_response), 45)
|
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_response,content.system_power_info_response), 45) \
|
||||||
|
X(a, STATIC, ONEOF, MSG_W_CB, (content,system_update_response,content.system_update_response), 46)
|
||||||
#define PB_Main_CALLBACK NULL
|
#define PB_Main_CALLBACK NULL
|
||||||
#define PB_Main_DEFAULT NULL
|
#define PB_Main_DEFAULT NULL
|
||||||
#define PB_Main_content_empty_MSGTYPE PB_Empty
|
#define PB_Main_content_empty_MSGTYPE PB_Empty
|
||||||
@ -273,6 +276,7 @@ X(a, STATIC, ONEOF, MSG_W_CB, (content,system_power_info_response,content.s
|
|||||||
#define PB_Main_content_storage_backup_restore_request_MSGTYPE PB_Storage_BackupRestoreRequest
|
#define PB_Main_content_storage_backup_restore_request_MSGTYPE PB_Storage_BackupRestoreRequest
|
||||||
#define PB_Main_content_system_power_info_request_MSGTYPE PB_System_PowerInfoRequest
|
#define PB_Main_content_system_power_info_request_MSGTYPE PB_System_PowerInfoRequest
|
||||||
#define PB_Main_content_system_power_info_response_MSGTYPE PB_System_PowerInfoResponse
|
#define PB_Main_content_system_power_info_response_MSGTYPE PB_System_PowerInfoResponse
|
||||||
|
#define PB_Main_content_system_update_response_MSGTYPE PB_System_UpdateResponse
|
||||||
|
|
||||||
extern const pb_msgdesc_t PB_Empty_msg;
|
extern const pb_msgdesc_t PB_Empty_msg;
|
||||||
extern const pb_msgdesc_t PB_StopSession_msg;
|
extern const pb_msgdesc_t PB_StopSession_msg;
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#define PROTOBUF_MAJOR_VERSION 0
|
#define PROTOBUF_MAJOR_VERSION 0
|
||||||
#define PROTOBUF_MINOR_VERSION 6
|
#define PROTOBUF_MINOR_VERSION 7
|
||||||
|
@ -48,6 +48,9 @@ PB_BIND(PB_System_ProtobufVersionResponse, PB_System_ProtobufVersionResponse, AU
|
|||||||
PB_BIND(PB_System_UpdateRequest, PB_System_UpdateRequest, AUTO)
|
PB_BIND(PB_System_UpdateRequest, PB_System_UpdateRequest, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(PB_System_UpdateResponse, PB_System_UpdateResponse, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(PB_System_PowerInfoRequest, PB_System_PowerInfoRequest, AUTO)
|
PB_BIND(PB_System_PowerInfoRequest, PB_System_PowerInfoRequest, AUTO)
|
||||||
|
|
||||||
|
|
||||||
@ -56,3 +59,4 @@ PB_BIND(PB_System_PowerInfoResponse, PB_System_PowerInfoResponse, AUTO)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,17 @@ typedef enum _PB_System_RebootRequest_RebootMode {
|
|||||||
PB_System_RebootRequest_RebootMode_UPDATE = 2
|
PB_System_RebootRequest_RebootMode_UPDATE = 2
|
||||||
} PB_System_RebootRequest_RebootMode;
|
} PB_System_RebootRequest_RebootMode;
|
||||||
|
|
||||||
|
typedef enum _PB_System_UpdateResponse_UpdateResultCode {
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_OK = 0,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_ManifestPathInvalid = 1,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_ManifestFolderNotFound = 2,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_ManifestInvalid = 3,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_StageMissing = 4,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_StageIntegrityError = 5,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_ManifestPointerError = 6,
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode_TargetMismatch = 7
|
||||||
|
} PB_System_UpdateResponse_UpdateResultCode;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
typedef struct _PB_System_DeviceInfoRequest {
|
typedef struct _PB_System_DeviceInfoRequest {
|
||||||
char dummy_field;
|
char dummy_field;
|
||||||
@ -84,6 +95,10 @@ typedef struct _PB_System_RebootRequest {
|
|||||||
PB_System_RebootRequest_RebootMode mode;
|
PB_System_RebootRequest_RebootMode mode;
|
||||||
} PB_System_RebootRequest;
|
} PB_System_RebootRequest;
|
||||||
|
|
||||||
|
typedef struct _PB_System_UpdateResponse {
|
||||||
|
PB_System_UpdateResponse_UpdateResultCode code;
|
||||||
|
} PB_System_UpdateResponse;
|
||||||
|
|
||||||
typedef struct _PB_System_GetDateTimeResponse {
|
typedef struct _PB_System_GetDateTimeResponse {
|
||||||
bool has_datetime;
|
bool has_datetime;
|
||||||
PB_System_DateTime datetime;
|
PB_System_DateTime datetime;
|
||||||
@ -100,6 +115,10 @@ typedef struct _PB_System_SetDateTimeRequest {
|
|||||||
#define _PB_System_RebootRequest_RebootMode_MAX PB_System_RebootRequest_RebootMode_UPDATE
|
#define _PB_System_RebootRequest_RebootMode_MAX PB_System_RebootRequest_RebootMode_UPDATE
|
||||||
#define _PB_System_RebootRequest_RebootMode_ARRAYSIZE ((PB_System_RebootRequest_RebootMode)(PB_System_RebootRequest_RebootMode_UPDATE+1))
|
#define _PB_System_RebootRequest_RebootMode_ARRAYSIZE ((PB_System_RebootRequest_RebootMode)(PB_System_RebootRequest_RebootMode_UPDATE+1))
|
||||||
|
|
||||||
|
#define _PB_System_UpdateResponse_UpdateResultCode_MIN PB_System_UpdateResponse_UpdateResultCode_OK
|
||||||
|
#define _PB_System_UpdateResponse_UpdateResultCode_MAX PB_System_UpdateResponse_UpdateResultCode_TargetMismatch
|
||||||
|
#define _PB_System_UpdateResponse_UpdateResultCode_ARRAYSIZE ((PB_System_UpdateResponse_UpdateResultCode)(PB_System_UpdateResponse_UpdateResultCode_TargetMismatch+1))
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -120,6 +139,7 @@ extern "C" {
|
|||||||
#define PB_System_ProtobufVersionRequest_init_default {0}
|
#define PB_System_ProtobufVersionRequest_init_default {0}
|
||||||
#define PB_System_ProtobufVersionResponse_init_default {0, 0}
|
#define PB_System_ProtobufVersionResponse_init_default {0, 0}
|
||||||
#define PB_System_UpdateRequest_init_default {NULL}
|
#define PB_System_UpdateRequest_init_default {NULL}
|
||||||
|
#define PB_System_UpdateResponse_init_default {_PB_System_UpdateResponse_UpdateResultCode_MIN}
|
||||||
#define PB_System_PowerInfoRequest_init_default {0}
|
#define PB_System_PowerInfoRequest_init_default {0}
|
||||||
#define PB_System_PowerInfoResponse_init_default {NULL, NULL}
|
#define PB_System_PowerInfoResponse_init_default {NULL, NULL}
|
||||||
#define PB_System_PingRequest_init_zero {NULL}
|
#define PB_System_PingRequest_init_zero {NULL}
|
||||||
@ -136,6 +156,7 @@ extern "C" {
|
|||||||
#define PB_System_ProtobufVersionRequest_init_zero {0}
|
#define PB_System_ProtobufVersionRequest_init_zero {0}
|
||||||
#define PB_System_ProtobufVersionResponse_init_zero {0, 0}
|
#define PB_System_ProtobufVersionResponse_init_zero {0, 0}
|
||||||
#define PB_System_UpdateRequest_init_zero {NULL}
|
#define PB_System_UpdateRequest_init_zero {NULL}
|
||||||
|
#define PB_System_UpdateResponse_init_zero {_PB_System_UpdateResponse_UpdateResultCode_MIN}
|
||||||
#define PB_System_PowerInfoRequest_init_zero {0}
|
#define PB_System_PowerInfoRequest_init_zero {0}
|
||||||
#define PB_System_PowerInfoResponse_init_zero {NULL, NULL}
|
#define PB_System_PowerInfoResponse_init_zero {NULL, NULL}
|
||||||
|
|
||||||
@ -157,6 +178,7 @@ extern "C" {
|
|||||||
#define PB_System_ProtobufVersionResponse_major_tag 1
|
#define PB_System_ProtobufVersionResponse_major_tag 1
|
||||||
#define PB_System_ProtobufVersionResponse_minor_tag 2
|
#define PB_System_ProtobufVersionResponse_minor_tag 2
|
||||||
#define PB_System_RebootRequest_mode_tag 1
|
#define PB_System_RebootRequest_mode_tag 1
|
||||||
|
#define PB_System_UpdateResponse_code_tag 1
|
||||||
#define PB_System_GetDateTimeResponse_datetime_tag 1
|
#define PB_System_GetDateTimeResponse_datetime_tag 1
|
||||||
#define PB_System_SetDateTimeRequest_datetime_tag 1
|
#define PB_System_SetDateTimeRequest_datetime_tag 1
|
||||||
|
|
||||||
@ -241,6 +263,11 @@ X(a, POINTER, SINGULAR, STRING, update_manifest, 1)
|
|||||||
#define PB_System_UpdateRequest_CALLBACK NULL
|
#define PB_System_UpdateRequest_CALLBACK NULL
|
||||||
#define PB_System_UpdateRequest_DEFAULT NULL
|
#define PB_System_UpdateRequest_DEFAULT NULL
|
||||||
|
|
||||||
|
#define PB_System_UpdateResponse_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, code, 1)
|
||||||
|
#define PB_System_UpdateResponse_CALLBACK NULL
|
||||||
|
#define PB_System_UpdateResponse_DEFAULT NULL
|
||||||
|
|
||||||
#define PB_System_PowerInfoRequest_FIELDLIST(X, a) \
|
#define PB_System_PowerInfoRequest_FIELDLIST(X, a) \
|
||||||
|
|
||||||
#define PB_System_PowerInfoRequest_CALLBACK NULL
|
#define PB_System_PowerInfoRequest_CALLBACK NULL
|
||||||
@ -266,6 +293,7 @@ extern const pb_msgdesc_t PB_System_PlayAudiovisualAlertRequest_msg;
|
|||||||
extern const pb_msgdesc_t PB_System_ProtobufVersionRequest_msg;
|
extern const pb_msgdesc_t PB_System_ProtobufVersionRequest_msg;
|
||||||
extern const pb_msgdesc_t PB_System_ProtobufVersionResponse_msg;
|
extern const pb_msgdesc_t PB_System_ProtobufVersionResponse_msg;
|
||||||
extern const pb_msgdesc_t PB_System_UpdateRequest_msg;
|
extern const pb_msgdesc_t PB_System_UpdateRequest_msg;
|
||||||
|
extern const pb_msgdesc_t PB_System_UpdateResponse_msg;
|
||||||
extern const pb_msgdesc_t PB_System_PowerInfoRequest_msg;
|
extern const pb_msgdesc_t PB_System_PowerInfoRequest_msg;
|
||||||
extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg;
|
extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg;
|
||||||
|
|
||||||
@ -284,6 +312,7 @@ extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg;
|
|||||||
#define PB_System_ProtobufVersionRequest_fields &PB_System_ProtobufVersionRequest_msg
|
#define PB_System_ProtobufVersionRequest_fields &PB_System_ProtobufVersionRequest_msg
|
||||||
#define PB_System_ProtobufVersionResponse_fields &PB_System_ProtobufVersionResponse_msg
|
#define PB_System_ProtobufVersionResponse_fields &PB_System_ProtobufVersionResponse_msg
|
||||||
#define PB_System_UpdateRequest_fields &PB_System_UpdateRequest_msg
|
#define PB_System_UpdateRequest_fields &PB_System_UpdateRequest_msg
|
||||||
|
#define PB_System_UpdateResponse_fields &PB_System_UpdateResponse_msg
|
||||||
#define PB_System_PowerInfoRequest_fields &PB_System_PowerInfoRequest_msg
|
#define PB_System_PowerInfoRequest_fields &PB_System_PowerInfoRequest_msg
|
||||||
#define PB_System_PowerInfoResponse_fields &PB_System_PowerInfoResponse_msg
|
#define PB_System_PowerInfoResponse_fields &PB_System_PowerInfoResponse_msg
|
||||||
|
|
||||||
@ -304,6 +333,7 @@ extern const pb_msgdesc_t PB_System_PowerInfoResponse_msg;
|
|||||||
#define PB_System_ProtobufVersionResponse_size 12
|
#define PB_System_ProtobufVersionResponse_size 12
|
||||||
#define PB_System_RebootRequest_size 2
|
#define PB_System_RebootRequest_size 2
|
||||||
#define PB_System_SetDateTimeRequest_size 24
|
#define PB_System_SetDateTimeRequest_size 24
|
||||||
|
#define PB_System_UpdateResponse_size 2
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0ad90705b9434b6f8fb2c4b605069f0d56d8cc70
|
Subproject commit ffa62429f3c678537e0e883a3a8c3ae5f1398ed4
|
@ -37,6 +37,7 @@
|
|||||||
#include "memmgr_heap.h"
|
#include "memmgr_heap.h"
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <cmsis_os2.h>
|
#include <cmsis_os2.h>
|
||||||
#include <stm32wbxx.h>
|
#include <stm32wbxx.h>
|
||||||
#include <furi_hal_console.h>
|
#include <furi_hal_console.h>
|
||||||
|
@ -48,7 +48,7 @@ int main() {
|
|||||||
flipper_boot_update_exec();
|
flipper_boot_update_exec();
|
||||||
// if things go nice, we shouldn't reach this point.
|
// if things go nice, we shouldn't reach this point.
|
||||||
// But if we do, abandon to avoid bootloops
|
// But if we do, abandon to avoid bootloops
|
||||||
update_operation_disarm();
|
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal);
|
||||||
furi_hal_power_reset();
|
furi_hal_power_reset();
|
||||||
} else {
|
} else {
|
||||||
furi_hal_light_sequence("rgb G");
|
furi_hal_light_sequence("rgb G");
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
#include <toolbox/path.h>
|
#include <toolbox/path.h>
|
||||||
#include <toolbox/crc32_calc.h>
|
#include <toolbox/crc32_calc.h>
|
||||||
|
|
||||||
static FATFS* pfs = NULL;
|
#define FS_ROOT_PATH "/"
|
||||||
|
#define UPDATE_POINTER_FILE_PATH FS_ROOT_PATH UPDATE_MANIFEST_POINTER_FILE_NAME
|
||||||
|
|
||||||
static const char FS_ROOT_PATH[] = "/";
|
static FATFS* pfs = NULL;
|
||||||
|
|
||||||
#define CHECK_FRESULT(result) \
|
#define CHECK_FRESULT(result) \
|
||||||
{ \
|
{ \
|
||||||
@ -100,41 +101,34 @@ static bool flipper_update_load_stage(const string_t work_dir, UpdateManifest* m
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool flipper_update_get_work_directory(string_t out_dir) {
|
static bool flipper_update_get_manifest_path(string_t out_path) {
|
||||||
const uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex);
|
|
||||||
if(update_index == UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC) {
|
|
||||||
string_set(out_dir, UPDATE_DIR_DEFAULT_REL_PATH);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DIR dir;
|
|
||||||
UINT entry_idx = 0;
|
|
||||||
FILINFO fno;
|
|
||||||
CHECK_FRESULT(f_opendir(&dir, UPDATE_DIR_DEFAULT_REL_PATH));
|
|
||||||
string_set(out_dir, UPDATE_DIR_DEFAULT_REL_PATH);
|
|
||||||
|
|
||||||
while(f_readdir(&dir, &fno) == FR_OK) {
|
|
||||||
entry_idx++;
|
|
||||||
if(fno.fname[0] == '\0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(entry_idx == update_index) {
|
|
||||||
path_append(out_dir, fno.fname);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string_reset(out_dir);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UpdateManifest* flipper_update_process_manifest(const string_t work_dir) {
|
|
||||||
FIL file;
|
FIL file;
|
||||||
FILINFO stat;
|
FILINFO stat;
|
||||||
|
uint16_t size_read = 0;
|
||||||
|
char manifest_name_buf[UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN] = {0};
|
||||||
|
|
||||||
string_t manifest_path;
|
string_reset(out_path);
|
||||||
string_init_set(manifest_path, work_dir);
|
CHECK_FRESULT(f_stat(UPDATE_POINTER_FILE_PATH, &stat));
|
||||||
path_append(manifest_path, UPDATE_MANIFEST_DEFAULT_NAME);
|
CHECK_FRESULT(f_open(&file, UPDATE_POINTER_FILE_PATH, FA_OPEN_EXISTING | FA_READ));
|
||||||
|
do {
|
||||||
|
if(f_read(&file, manifest_name_buf, UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN, &size_read) !=
|
||||||
|
FR_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((size_read == 0) || (size_read == UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string_set_str(out_path, manifest_name_buf);
|
||||||
|
string_right(out_path, strlen("/ext"));
|
||||||
|
} while(0);
|
||||||
|
f_close(&file);
|
||||||
|
return !string_empty_p(out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UpdateManifest* flipper_update_process_manifest(const string_t manifest_path) {
|
||||||
|
FIL file;
|
||||||
|
FILINFO stat;
|
||||||
|
|
||||||
CHECK_FRESULT(f_stat(string_get_cstr(manifest_path), &stat));
|
CHECK_FRESULT(f_stat(string_get_cstr(manifest_path), &stat));
|
||||||
CHECK_FRESULT(f_open(&file, string_get_cstr(manifest_path), FA_OPEN_EXISTING | FA_READ));
|
CHECK_FRESULT(f_open(&file, string_get_cstr(manifest_path), FA_OPEN_EXISTING | FA_READ));
|
||||||
@ -164,7 +158,7 @@ static UpdateManifest* flipper_update_process_manifest(const string_t work_dir)
|
|||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
string_clear(manifest_path);
|
f_close(&file);
|
||||||
free(manifest_data);
|
free(manifest_data);
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
@ -174,22 +168,25 @@ void flipper_boot_update_exec() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t work_dir;
|
string_t work_dir, manifest_path;
|
||||||
string_init(work_dir);
|
string_init(work_dir);
|
||||||
|
string_init(manifest_path);
|
||||||
do {
|
do {
|
||||||
if(!flipper_update_get_work_directory(work_dir)) {
|
if(!flipper_update_get_manifest_path(manifest_path)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateManifest* manifest = flipper_update_process_manifest(work_dir);
|
UpdateManifest* manifest = flipper_update_process_manifest(manifest_path);
|
||||||
if(!manifest) {
|
if(!manifest) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path_extract_dirname(string_get_cstr(manifest_path), work_dir);
|
||||||
if(!flipper_update_load_stage(work_dir, manifest)) {
|
if(!flipper_update_load_stage(work_dir, manifest)) {
|
||||||
update_manifest_free(manifest);
|
update_manifest_free(manifest);
|
||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
|
string_clear(manifest_path);
|
||||||
string_clear(work_dir);
|
string_clear(work_dir);
|
||||||
free(pfs);
|
free(pfs);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <hw_conf.h>
|
#include <hw_conf.h>
|
||||||
|
|
||||||
|
#define TAG "FuriHalRandom"
|
||||||
|
|
||||||
uint32_t furi_hal_random_get() {
|
uint32_t furi_hal_random_get() {
|
||||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID))
|
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID))
|
||||||
;
|
;
|
||||||
@ -51,9 +53,13 @@ void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void srand(unsigned seed) {
|
void srand(unsigned seed) {
|
||||||
UNUSED(seed); // FIXME!
|
UNUSED(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rand() {
|
int rand() {
|
||||||
return (furi_hal_random_get() & RAND_MAX);
|
return (furi_hal_random_get() & RAND_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long random() {
|
||||||
|
return (furi_hal_random_get() & RAND_MAX);
|
||||||
|
}
|
||||||
|
@ -972,9 +972,9 @@ void furi_hal_subghz_stop_async_tx() {
|
|||||||
FURI_LOG_D(
|
FURI_LOG_D(
|
||||||
TAG,
|
TAG,
|
||||||
"Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%",
|
"Async TX Radio stats: on %0.0fus, off %0.0fus, DutyCycle: %0.0f%%",
|
||||||
(float)furi_hal_subghz_async_tx.duty_high,
|
(double)furi_hal_subghz_async_tx.duty_high,
|
||||||
(float)furi_hal_subghz_async_tx.duty_low,
|
(double)furi_hal_subghz_async_tx.duty_low,
|
||||||
duty_cycle);
|
(double)duty_cycle);
|
||||||
|
|
||||||
furi_hal_subghz_state = SubGhzStateIdle;
|
furi_hal_subghz_state = SubGhzStateIdle;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,7 @@ SECTIONS
|
|||||||
_sdata = .; /* create a global symbol at data start */
|
_sdata = .; /* create a global symbol at data start */
|
||||||
*(.data) /* .data sections */
|
*(.data) /* .data sections */
|
||||||
*(.data*) /* .data* sections */
|
*(.data*) /* .data* sections */
|
||||||
|
*(*_DRIVER_CONTEXT)
|
||||||
|
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_edata = .; /* define a global symbol at data end */
|
_edata = .; /* define a global symbol at data end */
|
||||||
@ -158,7 +159,7 @@ SECTIONS
|
|||||||
} >RAM1
|
} >RAM1
|
||||||
|
|
||||||
/* User_heap_stack section, used to check that there is enough RAM left */
|
/* User_heap_stack section, used to check that there is enough RAM left */
|
||||||
._user_heap_stack :
|
._user_heap_stack(NOLOAD):
|
||||||
{
|
{
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
__heap_start__ = .;
|
__heap_start__ = .;
|
||||||
@ -173,7 +174,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
__free_flash_start__ = .;
|
__free_flash_start__ = .;
|
||||||
. = ORIGIN(FLASH) + LENGTH(FLASH);
|
. = ORIGIN(FLASH) + LENGTH(FLASH);
|
||||||
} >FLASH
|
} >FLASH
|
||||||
|
|
||||||
/* Remove information from the standard libraries */
|
/* Remove information from the standard libraries */
|
||||||
/DISCARD/ :
|
/DISCARD/ :
|
||||||
|
@ -19,9 +19,9 @@ endif
|
|||||||
MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
MCU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
||||||
|
|
||||||
# Warnings configuration
|
# Warnings configuration
|
||||||
CFLAGS += -Wall -Wextra -Wredundant-decls
|
CFLAGS += -Wall -Wextra -Wredundant-decls -Wdouble-promotion
|
||||||
|
|
||||||
CFLAGS += $(MCU_FLAGS) -DSTM32WB55xx -fdata-sections -ffunction-sections
|
CFLAGS += $(MCU_FLAGS) -DSTM32WB55xx -fdata-sections -ffunction-sections -fsingle-precision-constant
|
||||||
LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs
|
LDFLAGS += $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs
|
||||||
|
|
||||||
CPPFLAGS += -fno-rtti -fno-use-cxa-atexit -fno-exceptions
|
CPPFLAGS += -fno-rtti -fno-use-cxa-atexit -fno-exceptions
|
||||||
|
@ -276,7 +276,7 @@ bool flipper_format_stream_write_value_line(Stream* stream, FlipperStreamWriteDa
|
|||||||
#ifndef FLIPPER_STREAM_LITE
|
#ifndef FLIPPER_STREAM_LITE
|
||||||
case FlipperStreamValueFloat: {
|
case FlipperStreamValueFloat: {
|
||||||
const float* data = write_data->data;
|
const float* data = write_data->data;
|
||||||
string_printf(value, "%f", data[i]);
|
string_printf(value, "%f", (double)data[i]);
|
||||||
}; break;
|
}; break;
|
||||||
#endif
|
#endif
|
||||||
case FlipperStreamValueInt32: {
|
case FlipperStreamValueInt32: {
|
||||||
|
@ -4,7 +4,7 @@ LIB_DIR = $(PROJECT_ROOT)/lib
|
|||||||
CFLAGS += -I$(LIB_DIR)
|
CFLAGS += -I$(LIB_DIR)
|
||||||
|
|
||||||
# Mlib containers
|
# Mlib containers
|
||||||
CFLAGS += -I$(LIB_DIR)/mlib
|
CFLAGS += -I$(LIB_DIR)/mlib -D'M_MEMORY_FULL(x)=abort()'
|
||||||
|
|
||||||
# U8G2 display library
|
# U8G2 display library
|
||||||
U8G2_DIR = $(LIB_DIR)/u8g2
|
U8G2_DIR = $(LIB_DIR)/u8g2
|
||||||
|
@ -83,7 +83,10 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t*
|
|||||||
|
|
||||||
if(furi_hal_subghz_rx_pipe_not_empty()) {
|
if(furi_hal_subghz_rx_pipe_not_empty()) {
|
||||||
FURI_LOG_I(
|
FURI_LOG_I(
|
||||||
TAG, "RSSI: %03.1fdbm LQI: %d", furi_hal_subghz_get_rssi(), furi_hal_subghz_get_lqi());
|
TAG,
|
||||||
|
"RSSI: %03.1fdbm LQI: %d",
|
||||||
|
(double)furi_hal_subghz_get_rssi(),
|
||||||
|
furi_hal_subghz_get_lqi());
|
||||||
if(furi_hal_subghz_is_rx_data_crc_valid()) {
|
if(furi_hal_subghz_is_rx_data_crc_valid()) {
|
||||||
furi_hal_subghz_read_packet(data, size);
|
furi_hal_subghz_read_packet(data, size);
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@ -26,6 +26,7 @@ UpdateManifest* update_manifest_alloc() {
|
|||||||
string_init(update_manifest->staged_loader_file);
|
string_init(update_manifest->staged_loader_file);
|
||||||
string_init(update_manifest->resource_bundle);
|
string_init(update_manifest->resource_bundle);
|
||||||
update_manifest->target = 0;
|
update_manifest->target = 0;
|
||||||
|
update_manifest->manifest_version = 0;
|
||||||
memset(update_manifest->ob_reference.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
memset(update_manifest->ob_reference.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
||||||
memset(update_manifest->ob_compare_mask.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
memset(update_manifest->ob_compare_mask.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
||||||
memset(update_manifest->ob_write_mask.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
memset(update_manifest->ob_write_mask.bytes, 0, FURI_HAL_FLASH_OB_RAW_SIZE_BYTES);
|
||||||
@ -49,12 +50,11 @@ static bool
|
|||||||
furi_assert(flipper_file);
|
furi_assert(flipper_file);
|
||||||
|
|
||||||
string_t filetype;
|
string_t filetype;
|
||||||
uint32_t version = 0;
|
|
||||||
|
|
||||||
// TODO: compare filetype?
|
// TODO: compare filetype?
|
||||||
string_init(filetype);
|
string_init(filetype);
|
||||||
update_manifest->valid =
|
update_manifest->valid =
|
||||||
flipper_format_read_header(flipper_file, filetype, &version) &&
|
flipper_format_read_header(flipper_file, filetype, &update_manifest->manifest_version) &&
|
||||||
flipper_format_read_string(flipper_file, MANIFEST_KEY_INFO, update_manifest->version) &&
|
flipper_format_read_string(flipper_file, MANIFEST_KEY_INFO, update_manifest->version) &&
|
||||||
flipper_format_read_uint32(
|
flipper_format_read_uint32(
|
||||||
flipper_file, MANIFEST_KEY_TARGET, &update_manifest->target, 1) &&
|
flipper_file, MANIFEST_KEY_TARGET, &update_manifest->target, 1) &&
|
||||||
@ -68,7 +68,7 @@ static bool
|
|||||||
string_clear(filetype);
|
string_clear(filetype);
|
||||||
|
|
||||||
if(update_manifest->valid) {
|
if(update_manifest->valid) {
|
||||||
/* Optional fields - we can have dfu, radio, or both */
|
/* Optional fields - we can have dfu, radio, resources, or any combination */
|
||||||
flipper_format_read_string(
|
flipper_format_read_string(
|
||||||
flipper_file, MANIFEST_KEY_DFU_FILE, update_manifest->firmware_dfu_image);
|
flipper_file, MANIFEST_KEY_DFU_FILE, update_manifest->firmware_dfu_image);
|
||||||
flipper_format_read_string(
|
flipper_format_read_string(
|
||||||
@ -131,8 +131,7 @@ static bool ob_data_check_masked_values_valid(
|
|||||||
const FuriHalFlashRawOptionByteData* mask) {
|
const FuriHalFlashRawOptionByteData* mask) {
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
for(size_t idx = 0; valid && (idx < FURI_HAL_FLASH_OB_TOTAL_VALUES); ++idx) {
|
for(size_t idx = 0; valid && (idx < FURI_HAL_FLASH_OB_TOTAL_VALUES); ++idx) {
|
||||||
valid &= (data->obs[idx]. dword & mask->obs[idx].dword) ==
|
valid &= (data->obs[idx].dword & mask->obs[idx].dword) == data->obs[idx].dword;
|
||||||
data->obs[idx].dword;
|
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ extern "C" {
|
|||||||
/* Paths don't include /ext -- because at startup SD card is mounted as root */
|
/* Paths don't include /ext -- because at startup SD card is mounted as root */
|
||||||
#define UPDATE_DIR_DEFAULT_REL_PATH "/update"
|
#define UPDATE_DIR_DEFAULT_REL_PATH "/update"
|
||||||
#define UPDATE_MANIFEST_DEFAULT_NAME "update.fuf"
|
#define UPDATE_MANIFEST_DEFAULT_NAME "update.fuf"
|
||||||
|
#define UPDATE_MANIFEST_POINTER_FILE_NAME ".fupdate"
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint8_t raw[6];
|
uint8_t raw[6];
|
||||||
@ -27,6 +28,7 @@ typedef union {
|
|||||||
_Static_assert(sizeof(UpdateManifestRadioVersion) == 6, "UpdateManifestRadioVersion size error");
|
_Static_assert(sizeof(UpdateManifestRadioVersion) == 6, "UpdateManifestRadioVersion size error");
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uint32_t manifest_version;
|
||||||
string_t version;
|
string_t version;
|
||||||
uint32_t target;
|
uint32_t target;
|
||||||
string_t staged_loader_file;
|
string_t staged_loader_file;
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#define UPDATE_ROOT_DIR "/ext" UPDATE_DIR_DEFAULT_REL_PATH
|
#define UPDATE_ROOT_DIR "/ext" UPDATE_DIR_DEFAULT_REL_PATH
|
||||||
#define UPDATE_PREFIX "/ext" UPDATE_DIR_DEFAULT_REL_PATH "/"
|
#define UPDATE_PREFIX "/ext" UPDATE_DIR_DEFAULT_REL_PATH "/"
|
||||||
#define UPDATE_SUFFIX "/" UPDATE_MANIFEST_DEFAULT_NAME
|
#define UPDATE_SUFFIX "/" UPDATE_MANIFEST_DEFAULT_NAME
|
||||||
#define MAX_DIR_NAME_LEN 250
|
|
||||||
|
|
||||||
static const char* update_prepare_result_descr[] = {
|
static const char* update_prepare_result_descr[] = {
|
||||||
[UpdatePrepareResultOK] = "OK",
|
[UpdatePrepareResultOK] = "OK",
|
||||||
@ -21,6 +20,8 @@ static const char* update_prepare_result_descr[] = {
|
|||||||
[UpdatePrepareResultManifestInvalid] = "Invalid manifest data",
|
[UpdatePrepareResultManifestInvalid] = "Invalid manifest data",
|
||||||
[UpdatePrepareResultStageMissing] = "Missing Stage2 loader",
|
[UpdatePrepareResultStageMissing] = "Missing Stage2 loader",
|
||||||
[UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader",
|
[UpdatePrepareResultStageIntegrityError] = "Corrupted Stage2 loader",
|
||||||
|
[UpdatePrepareResultManifestPointerError] = "Failed to create update pointer file",
|
||||||
|
[UpdatePrepareResultOutdatedManifestVersion] = "Update package is too old",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value) {
|
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value) {
|
||||||
@ -31,65 +32,7 @@ const char* update_operation_describe_preparation_result(const UpdatePrepareResu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update_operation_get_package_dir_name(const char* full_path, string_t out_manifest_dir) {
|
static bool update_operation_get_current_package_path_rtc(Storage* storage, string_t out_path) {
|
||||||
bool path_ok = false;
|
|
||||||
string_t full_path_str;
|
|
||||||
string_init_set(full_path_str, full_path);
|
|
||||||
string_reset(out_manifest_dir);
|
|
||||||
bool start_end_ok = string_start_with_str_p(full_path_str, UPDATE_PREFIX) &&
|
|
||||||
string_end_with_str_p(full_path_str, UPDATE_SUFFIX);
|
|
||||||
int16_t dir_name_len =
|
|
||||||
strlen(full_path) - strlen(UPDATE_PREFIX) - strlen(UPDATE_MANIFEST_DEFAULT_NAME) - 1;
|
|
||||||
if(dir_name_len == -1) {
|
|
||||||
path_ok = true;
|
|
||||||
} else if(start_end_ok && (dir_name_len > 0)) {
|
|
||||||
string_set_n(out_manifest_dir, full_path_str, strlen(UPDATE_PREFIX), dir_name_len);
|
|
||||||
path_ok = true;
|
|
||||||
if(string_search_char(out_manifest_dir, '/') != STRING_FAILURE) {
|
|
||||||
string_reset(out_manifest_dir);
|
|
||||||
path_ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string_clear(full_path_str);
|
|
||||||
return path_ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t update_operation_get_package_index(Storage* storage, const char* update_package_dir) {
|
|
||||||
furi_assert(storage);
|
|
||||||
furi_assert(update_package_dir);
|
|
||||||
|
|
||||||
if(strlen(update_package_dir) == 0) {
|
|
||||||
return UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
int32_t index = 0;
|
|
||||||
File* dir = storage_file_alloc(storage);
|
|
||||||
FileInfo fi = {0};
|
|
||||||
char* name_buffer = malloc(MAX_DIR_NAME_LEN);
|
|
||||||
do {
|
|
||||||
if(!storage_dir_open(dir, UPDATE_ROOT_DIR)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(storage_dir_read(dir, &fi, name_buffer, MAX_DIR_NAME_LEN)) {
|
|
||||||
index++;
|
|
||||||
if(strcmp(name_buffer, update_package_dir)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
free(name_buffer);
|
|
||||||
storage_file_free(dir);
|
|
||||||
|
|
||||||
return found ? index : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool update_operation_get_current_package_path(Storage* storage, string_t out_path) {
|
|
||||||
const uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex);
|
const uint32_t update_index = furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex);
|
||||||
string_set_str(out_path, UPDATE_ROOT_DIR);
|
string_set_str(out_path, UPDATE_ROOT_DIR);
|
||||||
if(update_index == UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC) {
|
if(update_index == UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC) {
|
||||||
@ -100,13 +43,13 @@ bool update_operation_get_current_package_path(Storage* storage, string_t out_pa
|
|||||||
uint32_t iter_index = 0;
|
uint32_t iter_index = 0;
|
||||||
File* dir = storage_file_alloc(storage);
|
File* dir = storage_file_alloc(storage);
|
||||||
FileInfo fi = {0};
|
FileInfo fi = {0};
|
||||||
char* name_buffer = malloc(MAX_DIR_NAME_LEN);
|
char* name_buffer = malloc(UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN);
|
||||||
do {
|
do {
|
||||||
if(!storage_dir_open(dir, UPDATE_ROOT_DIR)) {
|
if(!storage_dir_open(dir, UPDATE_ROOT_DIR)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(storage_dir_read(dir, &fi, name_buffer, MAX_DIR_NAME_LEN)) {
|
while(storage_dir_read(dir, &fi, name_buffer, UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN)) {
|
||||||
if(++iter_index == update_index) {
|
if(++iter_index == update_index) {
|
||||||
found = true;
|
found = true;
|
||||||
path_append(out_path, name_buffer);
|
path_append(out_path, name_buffer);
|
||||||
@ -124,79 +67,148 @@ bool update_operation_get_current_package_path(Storage* storage, string_t out_pa
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UPDATE_FILE_POINTER_FN "/ext/" UPDATE_MANIFEST_POINTER_FILE_NAME
|
||||||
|
#define UPDATE_MANIFEST_MAX_PATH_LEN 256u
|
||||||
|
|
||||||
|
bool update_operation_get_current_package_manifest_path(Storage* storage, string_t out_path) {
|
||||||
|
string_reset(out_path);
|
||||||
|
if(storage_common_stat(storage, UPDATE_FILE_POINTER_FN, NULL) == FSE_OK) {
|
||||||
|
char* manifest_name_buffer = malloc(UPDATE_MANIFEST_MAX_PATH_LEN);
|
||||||
|
File* upd_file = NULL;
|
||||||
|
do {
|
||||||
|
upd_file = storage_file_alloc(storage);
|
||||||
|
if(!storage_file_open(
|
||||||
|
upd_file, UPDATE_FILE_POINTER_FN, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint16_t bytes_read =
|
||||||
|
storage_file_read(upd_file, manifest_name_buffer, UPDATE_MANIFEST_MAX_PATH_LEN);
|
||||||
|
if((bytes_read == 0) || (bytes_read == UPDATE_MANIFEST_MAX_PATH_LEN)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(storage_common_stat(storage, manifest_name_buffer, NULL) != FSE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
string_set_str(out_path, manifest_name_buffer);
|
||||||
|
} while(0);
|
||||||
|
free(manifest_name_buffer);
|
||||||
|
storage_file_free(upd_file);
|
||||||
|
} else {
|
||||||
|
/* legacy, will be deprecated */
|
||||||
|
string_t rtcpath;
|
||||||
|
string_init(rtcpath);
|
||||||
|
do {
|
||||||
|
if(!update_operation_get_current_package_path_rtc(storage, rtcpath)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path_concat(string_get_cstr(rtcpath), UPDATE_MANIFEST_DEFAULT_NAME, out_path);
|
||||||
|
} while(0);
|
||||||
|
string_clear(rtcpath);
|
||||||
|
}
|
||||||
|
return !string_empty_p(out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool update_operation_persist_manifest_path(Storage* storage, const char* manifest_path) {
|
||||||
|
const uint16_t manifest_path_len = strlen(manifest_path);
|
||||||
|
furi_check(manifest_path && manifest_path_len);
|
||||||
|
bool success = false;
|
||||||
|
File* file = storage_file_alloc(storage);
|
||||||
|
do {
|
||||||
|
if(manifest_path_len >= UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!storage_file_open(file, UPDATE_FILE_POINTER_FN, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(storage_file_write(file, manifest_path, manifest_path_len) != manifest_path_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
} while(0);
|
||||||
|
storage_file_free(file);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
|
UpdatePrepareResult update_operation_prepare(const char* manifest_file_path) {
|
||||||
string_t update_folder;
|
UpdatePrepareResult result = UpdatePrepareResultManifestFolderNotFound;
|
||||||
string_init(update_folder);
|
|
||||||
if(!update_operation_get_package_dir_name(manifest_file_path, update_folder)) {
|
|
||||||
string_clear(update_folder);
|
|
||||||
return UpdatePrepareResultManifestPathInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage* storage = furi_record_open("storage");
|
Storage* storage = furi_record_open("storage");
|
||||||
int32_t update_index =
|
|
||||||
update_operation_get_package_index(storage, string_get_cstr(update_folder));
|
|
||||||
string_clear(update_folder);
|
|
||||||
|
|
||||||
if(update_index < 0) {
|
|
||||||
furi_record_close("storage");
|
|
||||||
return UpdatePrepareResultManifestFolderNotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_t update_dir_path;
|
|
||||||
string_init(update_dir_path);
|
|
||||||
path_extract_dirname(manifest_file_path, update_dir_path);
|
|
||||||
|
|
||||||
UpdatePrepareResult result = UpdatePrepareResultManifestInvalid;
|
|
||||||
UpdateManifest* manifest = update_manifest_alloc();
|
UpdateManifest* manifest = update_manifest_alloc();
|
||||||
if(update_manifest_init(manifest, manifest_file_path)) {
|
File* file = storage_file_alloc(storage);
|
||||||
result = UpdatePrepareResultStageMissing;
|
|
||||||
File* file = storage_file_alloc(storage);
|
string_t stage_path;
|
||||||
|
string_init(stage_path);
|
||||||
|
do {
|
||||||
|
if(storage_common_stat(storage, manifest_file_path, NULL) != FSE_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!update_manifest_init(manifest, manifest_file_path)) {
|
||||||
|
result = UpdatePrepareResultManifestInvalid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(manifest->manifest_version < UPDATE_OPERATION_MIN_MANIFEST_VERSION) {
|
||||||
|
result = UpdatePrepareResultOutdatedManifestVersion;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_hal_version_get_hw_target() != manifest->target) {
|
||||||
|
result = UpdatePrepareResultTargetMismatch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
string_t stage_path;
|
|
||||||
string_init(stage_path);
|
|
||||||
path_extract_dirname(manifest_file_path, stage_path);
|
path_extract_dirname(manifest_file_path, stage_path);
|
||||||
path_append(stage_path, string_get_cstr(manifest->staged_loader_file));
|
path_append(stage_path, string_get_cstr(manifest->staged_loader_file));
|
||||||
|
|
||||||
uint32_t crc = 0;
|
if(!storage_file_open(file, string_get_cstr(stage_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||||
do {
|
result = UpdatePrepareResultStageMissing;
|
||||||
if(!storage_file_open(
|
break;
|
||||||
file, string_get_cstr(stage_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = UpdatePrepareResultStageIntegrityError;
|
|
||||||
crc = crc32_calc_file(file, NULL, NULL);
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
string_clear(stage_path);
|
|
||||||
storage_file_free(file);
|
|
||||||
|
|
||||||
if(crc == manifest->staged_loader_crc) {
|
|
||||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate);
|
|
||||||
update_operation_persist_package_index(update_index);
|
|
||||||
result = UpdatePrepareResultOK;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
furi_record_close("storage");
|
uint32_t crc = crc32_calc_file(file, NULL, NULL);
|
||||||
|
if(crc != manifest->staged_loader_crc) {
|
||||||
|
result = UpdatePrepareResultStageIntegrityError;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!update_operation_persist_manifest_path(storage, manifest_file_path)) {
|
||||||
|
result = UpdatePrepareResultManifestPointerError;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = UpdatePrepareResultOK;
|
||||||
|
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate);
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
string_clear(stage_path);
|
||||||
|
storage_file_free(file);
|
||||||
|
|
||||||
update_manifest_free(manifest);
|
update_manifest_free(manifest);
|
||||||
|
furi_record_close("storage");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update_operation_is_armed() {
|
bool update_operation_is_armed() {
|
||||||
FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode();
|
FuriHalRtcBootMode boot_mode = furi_hal_rtc_get_boot_mode();
|
||||||
|
const uint32_t rtc_upd_index =
|
||||||
|
furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex);
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
const bool upd_fn_ptr_exists =
|
||||||
|
(storage_common_stat(storage, UPDATE_FILE_POINTER_FN, NULL) == FSE_OK);
|
||||||
|
furi_record_close("storage");
|
||||||
return (boot_mode >= FuriHalRtcBootModePreUpdate) &&
|
return (boot_mode >= FuriHalRtcBootModePreUpdate) &&
|
||||||
(boot_mode <= FuriHalRtcBootModePostUpdate) &&
|
(boot_mode <= FuriHalRtcBootModePostUpdate) &&
|
||||||
(furi_hal_rtc_get_register(FuriHalRtcRegisterUpdateFolderFSIndex) > 0);
|
((rtc_upd_index != INT_MAX) || upd_fn_ptr_exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_operation_disarm() {
|
void update_operation_disarm() {
|
||||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal);
|
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeNormal);
|
||||||
furi_hal_rtc_set_register(
|
furi_hal_rtc_set_register(FuriHalRtcRegisterUpdateFolderFSIndex, INT_MAX);
|
||||||
FuriHalRtcRegisterUpdateFolderFSIndex, INT_MAX);
|
Storage* storage = furi_record_open("storage");
|
||||||
}
|
storage_simply_remove(storage, UPDATE_FILE_POINTER_FN);
|
||||||
|
furi_record_close("storage");
|
||||||
void update_operation_persist_package_index(int32_t index) {
|
}
|
||||||
furi_check(index >= 0);
|
|
||||||
furi_hal_rtc_set_register(FuriHalRtcRegisterUpdateFolderFSIndex, index);
|
|
||||||
}
|
|
@ -9,6 +9,8 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC 0
|
#define UPDATE_OPERATION_ROOT_DIR_PACKAGE_MAGIC 0
|
||||||
|
#define UPDATE_OPERATION_MAX_MANIFEST_PATH_LEN 255u
|
||||||
|
#define UPDATE_OPERATION_MIN_MANIFEST_VERSION 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if supplied full manifest path is valid
|
* Checks if supplied full manifest path is valid
|
||||||
@ -19,6 +21,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
bool update_operation_get_package_dir_name(const char* full_path, string_t out_manifest_dir);
|
bool update_operation_get_package_dir_name(const char* full_path, string_t out_manifest_dir);
|
||||||
|
|
||||||
|
/* When updating this enum, also update assets/protobuf/system.proto */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UpdatePrepareResultOK,
|
UpdatePrepareResultOK,
|
||||||
UpdatePrepareResultManifestPathInvalid,
|
UpdatePrepareResultManifestPathInvalid,
|
||||||
@ -26,6 +29,9 @@ typedef enum {
|
|||||||
UpdatePrepareResultManifestInvalid,
|
UpdatePrepareResultManifestInvalid,
|
||||||
UpdatePrepareResultStageMissing,
|
UpdatePrepareResultStageMissing,
|
||||||
UpdatePrepareResultStageIntegrityError,
|
UpdatePrepareResultStageIntegrityError,
|
||||||
|
UpdatePrepareResultManifestPointerError,
|
||||||
|
UpdatePrepareResultTargetMismatch,
|
||||||
|
UpdatePrepareResultOutdatedManifestVersion,
|
||||||
} UpdatePrepareResult;
|
} UpdatePrepareResult;
|
||||||
|
|
||||||
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value);
|
const char* update_operation_describe_preparation_result(const UpdatePrepareResult value);
|
||||||
@ -37,27 +43,13 @@ const char* update_operation_describe_preparation_result(const UpdatePrepareResu
|
|||||||
*/
|
*/
|
||||||
UpdatePrepareResult update_operation_prepare(const char* manifest_file_path);
|
UpdatePrepareResult update_operation_prepare(const char* manifest_file_path);
|
||||||
|
|
||||||
/*
|
|
||||||
* Gets update package index to pass in RTC registers
|
|
||||||
* @param storage Storage API
|
|
||||||
* @param update_package_dir Package directory name
|
|
||||||
* @return int32_t <=0 - error, >0 - update index value
|
|
||||||
*/
|
|
||||||
int32_t update_operation_get_package_index(Storage* storage, const char* update_package_dir);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets filesystem path for current update package
|
* Gets filesystem path for current update package
|
||||||
* @param storage Storage API
|
* @param storage Storage API
|
||||||
* @param out_path Path to directory with manifest & related files. Must be initialized
|
* @param out_path Path to manifest. Must be initialized
|
||||||
* @return true if path was restored successfully
|
* @return true if path was restored successfully
|
||||||
*/
|
*/
|
||||||
bool update_operation_get_current_package_path(Storage* storage, string_t out_path);
|
bool update_operation_get_current_package_manifest_path(Storage* storage, string_t out_path);
|
||||||
|
|
||||||
/*
|
|
||||||
* Stores given update index in RTC registers
|
|
||||||
* @param index Value to store
|
|
||||||
*/
|
|
||||||
void update_operation_persist_package_index(int32_t index);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks if an update operation step is pending after reset
|
* Checks if an update operation step is pending after reset
|
||||||
|
@ -13,6 +13,7 @@ import math
|
|||||||
|
|
||||||
|
|
||||||
class Main(App):
|
class Main(App):
|
||||||
|
UPDATE_MANIFEST_VERSION = 2
|
||||||
UPDATE_MANIFEST_NAME = "update.fuf"
|
UPDATE_MANIFEST_NAME = "update.fuf"
|
||||||
|
|
||||||
# No compression, plain tar
|
# No compression, plain tar
|
||||||
@ -93,7 +94,9 @@ class Main(App):
|
|||||||
)
|
)
|
||||||
|
|
||||||
file = FlipperFormatFile()
|
file = FlipperFormatFile()
|
||||||
file.setHeader("Flipper firmware upgrade configuration", 1)
|
file.setHeader(
|
||||||
|
"Flipper firmware upgrade configuration", self.UPDATE_MANIFEST_VERSION
|
||||||
|
)
|
||||||
file.writeKey("Info", self.args.version)
|
file.writeKey("Info", self.args.version)
|
||||||
file.writeKey("Target", self.args.target[1:]) # dirty 'f' strip
|
file.writeKey("Target", self.args.target[1:]) # dirty 'f' strip
|
||||||
file.writeKey("Loader", stage_basename)
|
file.writeKey("Loader", stage_basename)
|
||||||
@ -102,7 +105,7 @@ class Main(App):
|
|||||||
file.writeKey("Firmware", dfu_basename)
|
file.writeKey("Firmware", dfu_basename)
|
||||||
file.writeKey("Radio", radiobin_basename or "")
|
file.writeKey("Radio", radiobin_basename or "")
|
||||||
file.writeKey("Radio address", self.int2ffhex(radio_addr))
|
file.writeKey("Radio address", self.int2ffhex(radio_addr))
|
||||||
file.writeKey("Radio version", self.int2ffhex(radio_version))
|
file.writeKey("Radio version", self.int2ffhex(radio_version, 12))
|
||||||
if radiobin_basename:
|
if radiobin_basename:
|
||||||
file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin)))
|
file.writeKey("Radio CRC", self.int2ffhex(self.crc(self.args.radiobin)))
|
||||||
else:
|
else:
|
||||||
@ -149,11 +152,10 @@ class Main(App):
|
|||||||
return " ".join(f"{b:02X}" for b in value)
|
return " ".join(f"{b:02X}" for b in value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def int2ffhex(value: int):
|
def int2ffhex(value: int, n_hex_syms=8):
|
||||||
n_hex_bytes = 4
|
|
||||||
if value:
|
if value:
|
||||||
n_hex_bytes = math.ceil(math.ceil(math.log2(value)) / 8) * 2
|
n_hex_syms = math.ceil(math.ceil(math.log2(value)) / 8) * 2
|
||||||
fmtstr = f"%0{n_hex_bytes}X"
|
fmtstr = f"%0{n_hex_syms}X"
|
||||||
hexstr = fmtstr % value
|
hexstr = fmtstr % value
|
||||||
return " ".join(list(Main.batch(hexstr, 2))[::-1])
|
return " ".join(list(Main.batch(hexstr, 2))[::-1])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user