mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
Merge branch 'fz-dev' into dev
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,4 +1,4 @@
|
|||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
*.bat eol=crlf
|
*.bat eol=crlf
|
||||||
*.ps1 eol=crlf
|
*.ps1 eol=crlf
|
||||||
*.cmd eol=crlf
|
*.cmd eol=crlf
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -48,3 +48,6 @@ build/
|
|||||||
|
|
||||||
# Toolchain
|
# Toolchain
|
||||||
/toolchain
|
/toolchain
|
||||||
|
|
||||||
|
# openocd output file
|
||||||
|
openocd.log
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
EnsurePythonVersion(3, 8)
|
||||||
|
|
||||||
DefaultEnvironment(tools=[])
|
DefaultEnvironment(tools=[])
|
||||||
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
# Progress(["OwO\r", "owo\r", "uwu\r", "owo\r"], interval=15)
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ coreenv["ROOT_DIR"] = Dir(".")
|
|||||||
# Create a separate "dist" environment and add construction envs to it
|
# Create a separate "dist" environment and add construction envs to it
|
||||||
distenv = coreenv.Clone(
|
distenv = coreenv.Clone(
|
||||||
tools=["fbt_dist", "openocd", "blackmagic"],
|
tools=["fbt_dist", "openocd", "blackmagic"],
|
||||||
OPENOCD_GDB_PIPE=["|openocd -c 'gdb_port pipe' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"],
|
OPENOCD_GDB_PIPE=["|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"],
|
||||||
GDBOPTS_BASE=[
|
GDBOPTS_BASE=[
|
||||||
"-ex",
|
"-ex",
|
||||||
"target extended-remote ${GDBREMOTE}",
|
"target extended-remote ${GDBREMOTE}",
|
||||||
|
|||||||
@@ -239,4 +239,4 @@ int32_t about_settings_app(void* p) {
|
|||||||
furi_record_close("gui");
|
furi_record_close("gui");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,6 @@ Import("ENV")
|
|||||||
|
|
||||||
from fbt.appmanifest import FlipperAppType
|
from fbt.appmanifest import FlipperAppType
|
||||||
|
|
||||||
|
|
||||||
appenv = ENV.Clone(tools=["fbt_extapps"])
|
appenv = ENV.Clone(tools=["fbt_extapps"])
|
||||||
|
|
||||||
appenv.Replace(
|
appenv.Replace(
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ void elements_string_fit_width(Canvas* canvas, string_t string, uint8_t width);
|
|||||||
* @param[in] text Formatted text. The following formats are available:
|
* @param[in] text Formatted text. The following formats are available:
|
||||||
* "\e#Bold text\e#" - bold font is used
|
* "\e#Bold text\e#" - bold font is used
|
||||||
* "\e*Monospaced text\e*" - monospaced font is used
|
* "\e*Monospaced text\e*" - monospaced font is used
|
||||||
* "\e#Inversed text\e#" - white text on black background
|
* "\e!Inversed text\e!" - white text on black background
|
||||||
* @param strip_to_dots Strip text to ... if does not fit to width
|
* @param strip_to_dots Strip text to ... if does not fit to width
|
||||||
*/
|
*/
|
||||||
void elements_text_box(
|
void elements_text_box(
|
||||||
|
|||||||
@@ -190,6 +190,14 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha
|
|||||||
*/
|
*/
|
||||||
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path);
|
FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path);
|
||||||
|
|
||||||
|
/** Copy one folder contents into another with rename of all conflicting files
|
||||||
|
* @param app pointer to the api
|
||||||
|
* @param old_path old path
|
||||||
|
* @param new_path new path
|
||||||
|
* @return FS_Error operation result
|
||||||
|
*/
|
||||||
|
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path);
|
||||||
|
|
||||||
/** Creates a directory
|
/** Creates a directory
|
||||||
* @param app pointer to the api
|
* @param app pointer to the api
|
||||||
* @param path directory path
|
* @param path directory path
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "furi/log.h"
|
||||||
#include <furi/record.h>
|
#include <furi/record.h>
|
||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
@@ -5,8 +6,10 @@
|
|||||||
#include "storage_message.h"
|
#include "storage_message.h"
|
||||||
#include <toolbox/stream/file_stream.h>
|
#include <toolbox/stream/file_stream.h>
|
||||||
#include <toolbox/dir_walk.h>
|
#include <toolbox/dir_walk.h>
|
||||||
|
#include "toolbox/path.h"
|
||||||
|
|
||||||
#define MAX_NAME_LENGTH 256
|
#define MAX_NAME_LENGTH 256
|
||||||
|
#define MAX_EXT_LEN 16
|
||||||
|
|
||||||
#define TAG "StorageAPI"
|
#define TAG "StorageAPI"
|
||||||
|
|
||||||
@@ -436,6 +439,131 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char*
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FS_Error
|
||||||
|
storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) {
|
||||||
|
FS_Error error = storage_common_mkdir(storage, new_path);
|
||||||
|
DirWalk* dir_walk = dir_walk_alloc(storage);
|
||||||
|
string_t path;
|
||||||
|
string_t tmp_new_path;
|
||||||
|
string_t tmp_old_path;
|
||||||
|
FileInfo fileinfo;
|
||||||
|
string_init(path);
|
||||||
|
string_init(tmp_new_path);
|
||||||
|
string_init(tmp_old_path);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if((error != FSE_OK) && (error != FSE_EXIST)) break;
|
||||||
|
|
||||||
|
if(!dir_walk_open(dir_walk, old_path)) {
|
||||||
|
error = dir_walk_get_error(dir_walk);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
DirWalkResult res = dir_walk_read(dir_walk, path, &fileinfo);
|
||||||
|
|
||||||
|
if(res == DirWalkError) {
|
||||||
|
error = dir_walk_get_error(dir_walk);
|
||||||
|
break;
|
||||||
|
} else if(res == DirWalkLast) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
string_set(tmp_old_path, path);
|
||||||
|
string_right(path, strlen(old_path));
|
||||||
|
string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path));
|
||||||
|
|
||||||
|
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||||
|
if(storage_common_stat(storage, string_get_cstr(tmp_new_path), &fileinfo) ==
|
||||||
|
FSE_OK) {
|
||||||
|
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||||
|
error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = storage_common_merge(
|
||||||
|
storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error != FSE_OK) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
string_clear(tmp_new_path);
|
||||||
|
string_clear(tmp_old_path);
|
||||||
|
string_clear(path);
|
||||||
|
dir_walk_free(dir_walk);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) {
|
||||||
|
FS_Error error;
|
||||||
|
const char* new_path_tmp;
|
||||||
|
string_t new_path_next;
|
||||||
|
string_init(new_path_next);
|
||||||
|
|
||||||
|
FileInfo fileinfo;
|
||||||
|
error = storage_common_stat(storage, old_path, &fileinfo);
|
||||||
|
|
||||||
|
if(error == FSE_OK) {
|
||||||
|
if(fileinfo.flags & FSF_DIRECTORY) {
|
||||||
|
error = storage_merge_recursive(storage, old_path, new_path);
|
||||||
|
} else {
|
||||||
|
error = storage_common_stat(storage, new_path, &fileinfo);
|
||||||
|
if(error == FSE_OK) {
|
||||||
|
string_set_str(new_path_next, new_path);
|
||||||
|
string_t dir_path;
|
||||||
|
string_t filename;
|
||||||
|
char extension[MAX_EXT_LEN];
|
||||||
|
|
||||||
|
string_init(dir_path);
|
||||||
|
string_init(filename);
|
||||||
|
|
||||||
|
path_extract_filename(new_path_next, filename, true);
|
||||||
|
path_extract_dirname(new_path, dir_path);
|
||||||
|
path_extract_extension(new_path_next, extension, MAX_EXT_LEN);
|
||||||
|
|
||||||
|
storage_get_next_filename(
|
||||||
|
storage,
|
||||||
|
string_get_cstr(dir_path),
|
||||||
|
string_get_cstr(filename),
|
||||||
|
extension,
|
||||||
|
new_path_next,
|
||||||
|
255);
|
||||||
|
string_cat_printf(dir_path, "/%s%s", string_get_cstr(new_path_next), extension);
|
||||||
|
string_set(new_path_next, dir_path);
|
||||||
|
|
||||||
|
string_clear(dir_path);
|
||||||
|
string_clear(filename);
|
||||||
|
new_path_tmp = string_get_cstr(new_path_next);
|
||||||
|
} else {
|
||||||
|
new_path_tmp = new_path;
|
||||||
|
}
|
||||||
|
Stream* stream_from = file_stream_alloc(storage);
|
||||||
|
Stream* stream_to = file_stream_alloc(storage);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!file_stream_open(stream_from, old_path, FSAM_READ, FSOM_OPEN_EXISTING)) break;
|
||||||
|
if(!file_stream_open(stream_to, new_path_tmp, FSAM_WRITE, FSOM_CREATE_NEW)) break;
|
||||||
|
stream_copy_full(stream_from, stream_to);
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
error = file_stream_get_error(stream_from);
|
||||||
|
if(error == FSE_OK) {
|
||||||
|
error = file_stream_get_error(stream_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_free(stream_from);
|
||||||
|
stream_free(stream_to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(new_path_next);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
FS_Error storage_common_mkdir(Storage* storage, const char* path) {
|
FS_Error storage_common_mkdir(Storage* storage, const char* path) {
|
||||||
S_API_PROLOGUE;
|
S_API_PROLOGUE;
|
||||||
S_API_DATA_PATH;
|
S_API_DATA_PATH;
|
||||||
|
|||||||
19
applications/storage_move_to_sd/application.fam
Normal file
19
applications/storage_move_to_sd/application.fam
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
App(
|
||||||
|
appid="storage_move_to_sd",
|
||||||
|
name="StorageMoveToSd",
|
||||||
|
apptype=FlipperAppType.SYSTEM,
|
||||||
|
entry_point="storage_move_to_sd_app",
|
||||||
|
requires=["gui","storage"],
|
||||||
|
provides=["storage_move_to_sd_start"],
|
||||||
|
stack_size=2 * 1024,
|
||||||
|
order=30,
|
||||||
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="storage_move_to_sd_start",
|
||||||
|
apptype=FlipperAppType.STARTUP,
|
||||||
|
entry_point="storage_move_to_sd_start",
|
||||||
|
requires=["storage"],
|
||||||
|
order=120,
|
||||||
|
)
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#include "storage_move_to_sd_scene.h"
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||||
|
void (*const storage_move_to_sd_on_enter_handlers[])(void*) = {
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_event handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||||
|
bool (*const storage_move_to_sd_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_exit handlers array
|
||||||
|
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||||
|
void (*const storage_move_to_sd_on_exit_handlers[])(void* context) = {
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
};
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Initialize scene handlers configuration structure
|
||||||
|
const SceneManagerHandlers storage_move_to_sd_scene_handlers = {
|
||||||
|
.on_enter_handlers = storage_move_to_sd_on_enter_handlers,
|
||||||
|
.on_event_handlers = storage_move_to_sd_on_event_handlers,
|
||||||
|
.on_exit_handlers = storage_move_to_sd_on_exit_handlers,
|
||||||
|
.scene_num = StorageMoveToSdSceneNum,
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
|
||||||
|
// Generate scene id and total number
|
||||||
|
#define ADD_SCENE(prefix, name, id) StorageMoveToSd##id,
|
||||||
|
typedef enum {
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
StorageMoveToSdSceneNum,
|
||||||
|
} StorageMoveToSdScene;
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
extern const SceneManagerHandlers storage_move_to_sd_scene_handlers;
|
||||||
|
|
||||||
|
// Generate scene on_enter handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_event handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) \
|
||||||
|
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
|
|
||||||
|
// Generate scene on_exit handlers declaration
|
||||||
|
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||||
|
#include "storage_move_to_sd_scene_config.h"
|
||||||
|
#undef ADD_SCENE
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ADD_SCENE(storage_move_to_sd, confirm, Confirm)
|
||||||
|
ADD_SCENE(storage_move_to_sd, progress, Progress)
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include "../storage_move_to_sd.h"
|
||||||
|
#include "gui/canvas.h"
|
||||||
|
#include "gui/modules/widget_elements/widget_element_i.h"
|
||||||
|
#include "storage/storage.h"
|
||||||
|
|
||||||
|
static void storage_move_to_sd_scene_confirm_widget_callback(
|
||||||
|
GuiButtonType result,
|
||||||
|
InputType type,
|
||||||
|
void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
furi_assert(app);
|
||||||
|
if(type == InputTypeShort) {
|
||||||
|
if(result == GuiButtonTypeRight) {
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm);
|
||||||
|
} else if(result == GuiButtonTypeLeft) {
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void storage_move_to_sd_scene_confirm_on_enter(void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
|
||||||
|
widget_add_button_element(
|
||||||
|
app->widget,
|
||||||
|
GuiButtonTypeLeft,
|
||||||
|
"Cancel",
|
||||||
|
storage_move_to_sd_scene_confirm_widget_callback,
|
||||||
|
app);
|
||||||
|
widget_add_button_element(
|
||||||
|
app->widget,
|
||||||
|
GuiButtonTypeRight,
|
||||||
|
"Confirm",
|
||||||
|
storage_move_to_sd_scene_confirm_widget_callback,
|
||||||
|
app);
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD card inserted");
|
||||||
|
widget_add_string_multiline_element(
|
||||||
|
app->widget,
|
||||||
|
64,
|
||||||
|
32,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter,
|
||||||
|
FontSecondary,
|
||||||
|
"Move data from\ninternal storage to SD card?");
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storage_move_to_sd_scene_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
if(event.event == MoveToSdCustomEventConfirm) {
|
||||||
|
scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress);
|
||||||
|
consumed = true;
|
||||||
|
} else if(event.event == MoveToSdCustomEventExit) {
|
||||||
|
view_dispatcher_stop(app->view_dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storage_move_to_sd_scene_confirm_on_exit(void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
widget_reset(app->widget);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "../storage_move_to_sd.h"
|
||||||
|
#include "cmsis_os2.h"
|
||||||
|
|
||||||
|
void storage_move_to_sd_scene_progress_on_enter(void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
|
||||||
|
widget_add_string_element(
|
||||||
|
app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving...");
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget);
|
||||||
|
|
||||||
|
storage_move_to_sd_perform();
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storage_move_to_sd_scene_progress_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
view_dispatcher_stop(app->view_dispatcher);
|
||||||
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
|
consumed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void storage_move_to_sd_scene_progress_on_exit(void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
widget_reset(app->widget);
|
||||||
|
}
|
||||||
177
applications/storage_move_to_sd/storage_move_to_sd.c
Normal file
177
applications/storage_move_to_sd/storage_move_to_sd.c
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#include "storage_move_to_sd.h"
|
||||||
|
#include "cmsis_os2.h"
|
||||||
|
#include "furi/common_defines.h"
|
||||||
|
#include "furi/log.h"
|
||||||
|
#include "loader/loader.h"
|
||||||
|
#include "m-string.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define TAG "MoveToSd"
|
||||||
|
|
||||||
|
#define MOVE_SRC "/int"
|
||||||
|
#define MOVE_DST "/ext"
|
||||||
|
|
||||||
|
static const char* app_dirs[] = {
|
||||||
|
"subghz",
|
||||||
|
"lfrfid",
|
||||||
|
"nfc",
|
||||||
|
"infrared",
|
||||||
|
"ibutton",
|
||||||
|
"badusb",
|
||||||
|
};
|
||||||
|
|
||||||
|
bool storage_move_to_sd_perform(void) {
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
string_t path_src;
|
||||||
|
string_t path_dst;
|
||||||
|
string_init(path_src);
|
||||||
|
string_init(path_dst);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) {
|
||||||
|
string_printf(path_src, "%s/%s", MOVE_SRC, app_dirs[i]);
|
||||||
|
string_printf(path_dst, "%s/%s", MOVE_DST, app_dirs[i]);
|
||||||
|
storage_common_merge(storage, string_get_cstr(path_src), string_get_cstr(path_dst));
|
||||||
|
storage_simply_remove_recursive(storage, string_get_cstr(path_src));
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(path_src);
|
||||||
|
string_clear(path_dst);
|
||||||
|
|
||||||
|
furi_record_close("storage");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool storage_move_to_sd_check(void) {
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
|
||||||
|
FileInfo file_info;
|
||||||
|
bool state = false;
|
||||||
|
string_t path;
|
||||||
|
string_init(path);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) {
|
||||||
|
string_printf(path, "%s/%s", MOVE_SRC, app_dirs[i]);
|
||||||
|
if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) {
|
||||||
|
if((file_info.flags & FSF_DIRECTORY) != 0) {
|
||||||
|
state = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string_clear(path);
|
||||||
|
|
||||||
|
furi_record_close("storage");
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool storage_move_to_sd_custom_event_callback(void* context, uint32_t event) {
|
||||||
|
furi_assert(context);
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool storage_move_to_sd_back_event_callback(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
return scene_manager_handle_back_event(app->scene_manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void storage_move_to_sd_unmount_callback(const void* message, void* context) {
|
||||||
|
StorageMoveToSd* app = context;
|
||||||
|
furi_assert(app);
|
||||||
|
const StorageEvent* storage_event = message;
|
||||||
|
|
||||||
|
if((storage_event->type == StorageEventTypeCardUnmount) ||
|
||||||
|
(storage_event->type == StorageEventTypeCardMountError)) {
|
||||||
|
view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static StorageMoveToSd* storage_move_to_sd_alloc() {
|
||||||
|
StorageMoveToSd* app = malloc(sizeof(StorageMoveToSd));
|
||||||
|
|
||||||
|
app->gui = furi_record_open("gui");
|
||||||
|
app->notifications = furi_record_open("notification");
|
||||||
|
|
||||||
|
app->view_dispatcher = view_dispatcher_alloc();
|
||||||
|
app->scene_manager = scene_manager_alloc(&storage_move_to_sd_scene_handlers, app);
|
||||||
|
|
||||||
|
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||||
|
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||||
|
|
||||||
|
view_dispatcher_set_custom_event_callback(
|
||||||
|
app->view_dispatcher, storage_move_to_sd_custom_event_callback);
|
||||||
|
view_dispatcher_set_navigation_event_callback(
|
||||||
|
app->view_dispatcher, storage_move_to_sd_back_event_callback);
|
||||||
|
|
||||||
|
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
app->widget = widget_alloc();
|
||||||
|
view_dispatcher_add_view(
|
||||||
|
app->view_dispatcher, StorageMoveToSdViewWidget, widget_get_view(app->widget));
|
||||||
|
|
||||||
|
scene_manager_next_scene(app->scene_manager, StorageMoveToSdConfirm);
|
||||||
|
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
app->sub = furi_pubsub_subscribe(
|
||||||
|
storage_get_pubsub(storage), storage_move_to_sd_unmount_callback, app);
|
||||||
|
furi_record_close("storage");
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void storage_move_to_sd_free(StorageMoveToSd* app) {
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub);
|
||||||
|
furi_record_close("storage");
|
||||||
|
furi_record_close("notification");
|
||||||
|
|
||||||
|
view_dispatcher_remove_view(app->view_dispatcher, StorageMoveToSdViewWidget);
|
||||||
|
widget_free(app->widget);
|
||||||
|
view_dispatcher_free(app->view_dispatcher);
|
||||||
|
scene_manager_free(app->scene_manager);
|
||||||
|
|
||||||
|
furi_record_close("gui");
|
||||||
|
|
||||||
|
free(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t storage_move_to_sd_app(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
|
||||||
|
if(storage_move_to_sd_check()) {
|
||||||
|
StorageMoveToSd* app = storage_move_to_sd_alloc();
|
||||||
|
notification_message(app->notifications, &sequence_display_backlight_on);
|
||||||
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
storage_move_to_sd_free(app);
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(TAG, "Nothing to move");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void storage_move_to_sd_mount_callback(const void* message, void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
|
||||||
|
const StorageEvent* storage_event = message;
|
||||||
|
|
||||||
|
if(storage_event->type == StorageEventTypeCardMount) {
|
||||||
|
Loader* loader = furi_record_open("loader");
|
||||||
|
loader_start(loader, "StorageMoveToSd", NULL);
|
||||||
|
furi_record_close("loader");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t storage_move_to_sd_start(void* p) {
|
||||||
|
UNUSED(p);
|
||||||
|
Storage* storage = furi_record_open("storage");
|
||||||
|
|
||||||
|
furi_pubsub_subscribe(storage_get_pubsub(storage), storage_move_to_sd_mount_callback, NULL);
|
||||||
|
|
||||||
|
furi_record_close("storage");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
49
applications/storage_move_to_sd/storage_move_to_sd.h
Normal file
49
applications/storage_move_to_sd/storage_move_to_sd.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "gui/modules/widget_elements/widget_element_i.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include <gui/gui.h>
|
||||||
|
#include <gui/view.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
#include <notification/notification_messages.h>
|
||||||
|
|
||||||
|
#include <gui/modules/widget.h>
|
||||||
|
#include <gui/modules/popup.h>
|
||||||
|
|
||||||
|
#include <storage/storage.h>
|
||||||
|
#include <storage/storage_sd_api.h>
|
||||||
|
|
||||||
|
#include "scenes/storage_move_to_sd_scene.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MoveToSdCustomEventExit,
|
||||||
|
MoveToSdCustomEventConfirm,
|
||||||
|
} MoveToSdCustomEvent;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// records
|
||||||
|
Gui* gui;
|
||||||
|
Widget* widget;
|
||||||
|
NotificationApp* notifications;
|
||||||
|
|
||||||
|
// view managment
|
||||||
|
SceneManager* scene_manager;
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
|
||||||
|
FuriPubSubSubscription* sub;
|
||||||
|
|
||||||
|
} StorageMoveToSd;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
StorageMoveToSdViewWidget,
|
||||||
|
} StorageMoveToSdView;
|
||||||
|
|
||||||
|
bool storage_move_to_sd_perform(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
30
fbt
30
fbt
@@ -1,18 +1,22 @@
|
|||||||
#!/bin/bash
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
# shellcheck disable=SC2086 source=/dev/null
|
||||||
|
# unofficial strict mode
|
||||||
|
set -eu;
|
||||||
|
|
||||||
SCRIPTDIR="$( dirname -- "$0"; )";
|
SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built";
|
||||||
SCONS_EP=${SCRIPTDIR}/lib/scons/scripts/scons.py
|
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)";
|
||||||
|
|
||||||
if [[ -z "${FBT_NO_SYNC:-}" ]] ; then
|
if [ -z "${FBT_NOENV:-}" ]; then
|
||||||
if [[ -d .git ]]; then
|
. "$SCRIPT_PATH/scripts/toolchain/fbtenv.sh";
|
||||||
git submodule update --init
|
|
||||||
else
|
|
||||||
echo Not in a git repo, please clone with git clone --recursive
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"
|
if [ -z "${FBT_NO_SYNC:-}" ]; then
|
||||||
python3 ${SCONS_EP} ${SCONS_DEFAULT_FLAGS} "$@"
|
if [ ! -d "$SCRIPT_PATH/.git" ]; then
|
||||||
|
echo "\".git\" directory not found, please clone repo via \"git clone --recursive\"";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
git submodule update --init;
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 "$SCRIPT_PATH/lib/scons/scripts/scons.py" $SCONS_DEFAULT_FLAGS "$@"
|
||||||
29
fbt.cmd
29
fbt.cmd
@@ -1,27 +1,16 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
call %~dp0scripts\toolchain\fbtenv.cmd env
|
||||||
|
|
||||||
set SCONS_EP=%~dp0\lib\scons\scripts\scons.py
|
set SCONS_EP=%~dp0\lib\scons\scripts\scons.py
|
||||||
|
|
||||||
if [%FBT_NO_SYNC%] == [] (
|
if [%FBT_NO_SYNC%] == [] (
|
||||||
if exist ".git" (
|
if exist ".git" (
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
) else (
|
) else (
|
||||||
echo Not in a git repo, please clone with git clone --recursive
|
echo Not in a git repo, please clone with git clone --recursive
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
set "flipper_toolchain_version=2"
|
|
||||||
set "toolchainRoot=%~dp0toolchain\i686-windows"
|
|
||||||
set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built"
|
|
||||||
|
|
||||||
if not exist "%toolchainRoot%" (
|
set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built"
|
||||||
powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*
|
||||||
)
|
|
||||||
if not exist "%toolchainRoot%\VERSION" (
|
|
||||||
powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
|
||||||
)
|
|
||||||
set /p real_toolchain_version=<%toolchainRoot%\VERSION
|
|
||||||
if not "%real_toolchain_version%" == "%flipper_toolchain_version%" (
|
|
||||||
powershell -ExecutionPolicy Bypass -File %~dp0scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
|
||||||
)
|
|
||||||
cmd /V /C "set "PATH=%toolchainRoot%\python;%toolchainRoot%\bin;%toolchainRoot%\protoc\bin;%toolchainRoot%\openocd\bin;%PATH%" && python lib\scons\scripts\scons.py %SCONS_DEFAULT_FLAGS% %*"
|
|
||||||
@@ -10,8 +10,8 @@ COMPACT = 0
|
|||||||
## Optimize for debugging experience
|
## Optimize for debugging experience
|
||||||
DEBUG = 1
|
DEBUG = 1
|
||||||
|
|
||||||
# Suffix to add to files when building distribution.
|
# Suffix to add to files when building distribution
|
||||||
# If OS environment has DIST_SUFFIX set, it will be used instead..
|
# If OS environment has DIST_SUFFIX set, it will be used instead
|
||||||
DIST_SUFFIX = "local"
|
DIST_SUFFIX = "local"
|
||||||
|
|
||||||
# Coprocessor firmware
|
# Coprocessor firmware
|
||||||
@@ -27,7 +27,7 @@ COPRO_STACK_BIN = "stm32wb5x_BLE_Stack_light_fw.bin"
|
|||||||
# Firmware also supports "ble_full", but it might not fit into debug builds
|
# Firmware also supports "ble_full", but it might not fit into debug builds
|
||||||
COPRO_STACK_TYPE = "ble_light"
|
COPRO_STACK_TYPE = "ble_light"
|
||||||
|
|
||||||
# Leave 0 to lets scripts automatically calculate it
|
# Leave 0 to let scripts automatically calculate it
|
||||||
COPRO_STACK_ADDR = "0x0"
|
COPRO_STACK_ADDR = "0x0"
|
||||||
|
|
||||||
# If you override COPRO_CUBE_DIR on commandline, override this aswell
|
# If you override COPRO_CUBE_DIR on commandline, override this aswell
|
||||||
@@ -56,7 +56,7 @@ OPENOCD_OPTS = [
|
|||||||
|
|
||||||
SVD_FILE = "debug/STM32WB55_CM4.svd"
|
SVD_FILE = "debug/STM32WB55_CM4.svd"
|
||||||
|
|
||||||
# Look for blackmagic probe on serial ports
|
# Look for blackmagic probe on serial ports and local network
|
||||||
BLACKMAGIC = "auto"
|
BLACKMAGIC = "auto"
|
||||||
|
|
||||||
FIRMWARE_APPS = {
|
FIRMWARE_APPS = {
|
||||||
@@ -67,6 +67,7 @@ FIRMWARE_APPS = {
|
|||||||
# Apps
|
# Apps
|
||||||
"basic_apps",
|
"basic_apps",
|
||||||
"updater_app",
|
"updater_app",
|
||||||
|
"storage_move_to_sd",
|
||||||
"archive",
|
"archive",
|
||||||
# Custom Apps
|
# Custom Apps
|
||||||
"custom_apps",
|
"custom_apps",
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Make it depend on everything child builders returned
|
||||||
# Firmware depends on everything child builders returned
|
# Firmware depends on everything child builders returned
|
||||||
Depends(fwelf, lib_targets)
|
Depends(fwelf, lib_targets)
|
||||||
# Output extra details after building firmware
|
# Output extra details after building firmware
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_TIMINGS_AMOUNT 512
|
#define MAX_TIMINGS_AMOUNT 1024
|
||||||
|
|
||||||
/** Interface struct of infrared worker */
|
/** Interface struct of infrared worker */
|
||||||
typedef struct InfraredWorker InfraredWorker;
|
typedef struct InfraredWorker InfraredWorker;
|
||||||
|
|||||||
45
scripts/toolchain/fbtenv.cmd
Normal file
45
scripts/toolchain/fbtenv.cmd
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
if not [%FBT_ROOT%] == [] (
|
||||||
|
goto already_set
|
||||||
|
)
|
||||||
|
|
||||||
|
set "FBT_ROOT=%~dp0\..\..\"
|
||||||
|
pushd %FBT_ROOT%
|
||||||
|
set "FBT_ROOT=%cd%"
|
||||||
|
popd
|
||||||
|
|
||||||
|
if not [%FBT_NOENV%] == [] (
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
|
||||||
|
set "FLIPPER_TOOLCHAIN_VERSION=3"
|
||||||
|
set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\i686-windows"
|
||||||
|
|
||||||
|
|
||||||
|
if not exist "%FBT_TOOLCHAIN_ROOT%" (
|
||||||
|
powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
||||||
|
)
|
||||||
|
if not exist "%FBT_TOOLCHAIN_ROOT%\VERSION" (
|
||||||
|
powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
||||||
|
)
|
||||||
|
set /p REAL_TOOLCHAIN_VERSION=<%FBT_TOOLCHAIN_ROOT%\VERSION
|
||||||
|
if not "%REAL_TOOLCHAIN_VERSION%" == "%FLIPPER_TOOLCHAIN_VERSION%" (
|
||||||
|
powershell -ExecutionPolicy Bypass -File %FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1 "%flipper_toolchain_version%"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set "HOME=%USERPROFILE%"
|
||||||
|
set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python"
|
||||||
|
set "PATH=%FBT_TOOLCHAIN_ROOT%\python;%FBT_TOOLCHAIN_ROOT%\bin;%FBT_TOOLCHAIN_ROOT%\protoc\bin;%FBT_TOOLCHAIN_ROOT%\openocd\bin;%PATH%"
|
||||||
|
set "PROMPT=(fbt) %PROMPT%"
|
||||||
|
|
||||||
|
:already_set
|
||||||
|
|
||||||
|
if not "%1" == "env" (
|
||||||
|
echo *********************************
|
||||||
|
echo * fbt build environment *
|
||||||
|
echo *********************************
|
||||||
|
cd %FBT_ROOT%
|
||||||
|
cmd /k
|
||||||
|
)
|
||||||
54
scripts/toolchain/fbtenv.sh
Executable file
54
scripts/toolchain/fbtenv.sh
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# unofficial strict mode
|
||||||
|
set -eu;
|
||||||
|
|
||||||
|
FLIPPER_TOOLCHAIN_VERSION="3";
|
||||||
|
|
||||||
|
get_kernel_type()
|
||||||
|
{
|
||||||
|
SYS_TYPE="$(uname -s)"
|
||||||
|
if [ "$SYS_TYPE" = "Darwin" ]; then
|
||||||
|
TOOLCHAIN_PATH="toolchain/x86_64-darwin";
|
||||||
|
elif [ "$SYS_TYPE" = "Linux" ]; then
|
||||||
|
TOOLCHAIN_PATH="toolchain/x86_64-linux";
|
||||||
|
elif echo "$SYS_TYPE" | grep -q "MINGW"; then
|
||||||
|
echo "In MinGW shell use \"fbt.cmd\" instead of \"fbt\"";
|
||||||
|
exit 1;
|
||||||
|
else
|
||||||
|
echo "Your system is not supported. Sorry. Please report us your configuration.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_download_toolchain()
|
||||||
|
{
|
||||||
|
if [ ! -d "$SCRIPT_PATH/$TOOLCHAIN_PATH" ]; then
|
||||||
|
download_toolchain;
|
||||||
|
elif [ ! -f "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION" ]; then
|
||||||
|
download_toolchain;
|
||||||
|
elif [ "$(cat "$SCRIPT_PATH/$TOOLCHAIN_PATH/VERSION")" -ne "$FLIPPER_TOOLCHAIN_VERSION" ]; then
|
||||||
|
download_toolchain;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
download_toolchain()
|
||||||
|
{
|
||||||
|
chmod 755 "$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh";
|
||||||
|
"$SCRIPT_PATH/scripts/toolchain/unix-toolchain-download.sh" "$FLIPPER_TOOLCHAIN_VERSION" || exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
if [ -z "${SCRIPT_PATH:-}" ]; then
|
||||||
|
echo "Mannual running this script is now allowed.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
get_kernel_type; # sets TOOLCHAIN_PATH
|
||||||
|
check_download_toolchain;
|
||||||
|
PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/python/bin:$PATH";
|
||||||
|
PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/bin:$PATH";
|
||||||
|
PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/protobuf/bin:$PATH";
|
||||||
|
PATH="$SCRIPT_PATH/$TOOLCHAIN_PATH/openocd/bin:$PATH";
|
||||||
|
}
|
||||||
|
main;
|
||||||
135
scripts/toolchain/unix-toolchain-download.sh
Executable file
135
scripts/toolchain/unix-toolchain-download.sh
Executable file
@@ -0,0 +1,135 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2086,SC2034
|
||||||
|
|
||||||
|
# unofficial strict mode
|
||||||
|
set -eu;
|
||||||
|
|
||||||
|
check_system()
|
||||||
|
{
|
||||||
|
VER="$1"; # toolchain version
|
||||||
|
printf "Checking kernel type..";
|
||||||
|
SYS_TYPE="$(uname -s)"
|
||||||
|
if [ "$SYS_TYPE" = "Darwin" ]; then
|
||||||
|
echo "darwin";
|
||||||
|
TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-darwin-flipper-$VER.tar.gz";
|
||||||
|
TOOLCHAIN_PATH="toolchain/x86_64-darwin";
|
||||||
|
elif [ "$SYS_TYPE" = "Linux" ]; then
|
||||||
|
echo "linux";
|
||||||
|
TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-linux-flipper-$VER.tar.gz";
|
||||||
|
TOOLCHAIN_PATH="toolchain/x86_64-linux";
|
||||||
|
else
|
||||||
|
echo "unsupported.";
|
||||||
|
echo "Your system is unsupported.. sorry..";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_tar()
|
||||||
|
{
|
||||||
|
printf "Checking tar..";
|
||||||
|
if ! tar --version > /dev/null 2>&1; then
|
||||||
|
echo "no";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
echo "yes";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
curl_wget_check()
|
||||||
|
{
|
||||||
|
printf "Checking curl..";
|
||||||
|
if ! curl --version > /dev/null 2>&1; then
|
||||||
|
echo "no";
|
||||||
|
printf "Checking wget..";
|
||||||
|
if ! wget --version > /dev/null 2>&1; then
|
||||||
|
echo "no";
|
||||||
|
echo "No curl or wget found in your PATH.";
|
||||||
|
echo "Please provide it or download this file:";
|
||||||
|
echo;
|
||||||
|
echo "$TOOLCHAIN_URL";
|
||||||
|
echo;
|
||||||
|
echo "And place in repo root dir mannualy.";
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
echo "yes"
|
||||||
|
DOWNLOADER="wget";
|
||||||
|
DOWNLOADER_ARGS="--show-progress --progress=bar:force -qO";
|
||||||
|
return;
|
||||||
|
fi
|
||||||
|
echo "yes"
|
||||||
|
DOWNLOADER="curl";
|
||||||
|
DOWNLOADER_ARGS="--progress-bar -SLo";
|
||||||
|
}
|
||||||
|
|
||||||
|
check_downloaded_toolchain()
|
||||||
|
{
|
||||||
|
printf "Checking downloaded toolchain tgz..";
|
||||||
|
if [ -f "$REPO_ROOT/$TOOLCHAIN_TAR" ]; then
|
||||||
|
echo "yes";
|
||||||
|
return 0;
|
||||||
|
fi
|
||||||
|
echo "no";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
download_toolchain()
|
||||||
|
{
|
||||||
|
echo "Downloading toolchain:";
|
||||||
|
"$DOWNLOADER" $DOWNLOADER_ARGS "$REPO_ROOT/$TOOLCHAIN_TAR" "$TOOLCHAIN_URL";
|
||||||
|
echo "done";
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_old_tooclhain()
|
||||||
|
{
|
||||||
|
printf "Removing old toolchain (if exist)..";
|
||||||
|
rm -rf "${REPO_ROOT:?}/$TOOLCHAIN_PATH";
|
||||||
|
echo "done";
|
||||||
|
}
|
||||||
|
|
||||||
|
show_unpack_percentage()
|
||||||
|
{
|
||||||
|
LINE=0;
|
||||||
|
while read -r line; do
|
||||||
|
LINE=$(( LINE + 1 ));
|
||||||
|
if [ $(( LINE % 300 )) -eq 0 ]; then
|
||||||
|
printf "#";
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo " 100.0%";
|
||||||
|
}
|
||||||
|
|
||||||
|
unpack_toolchain()
|
||||||
|
{
|
||||||
|
echo "Unpacking toolchain:";
|
||||||
|
tar -xvf "$REPO_ROOT/$TOOLCHAIN_TAR" -C "$REPO_ROOT/" 2>&1 | show_unpack_percentage;
|
||||||
|
mkdir -p "$REPO_ROOT/toolchain";
|
||||||
|
mv "$REPO_ROOT/$TOOLCHAIN_DIR" "$REPO_ROOT/$TOOLCHAIN_PATH/";
|
||||||
|
echo "done";
|
||||||
|
}
|
||||||
|
|
||||||
|
clearing()
|
||||||
|
{
|
||||||
|
printf "Clearing..";
|
||||||
|
rm -rf "${REPO_ROOT:?}/$TOOLCHAIN_TAR";
|
||||||
|
echo "done";
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_PATH/../../" && pwd)";
|
||||||
|
check_system "$1"; # recives TOOLCHAIN_VERSION, defines TOOLCHAIN_URL and TOOLCHAIN_PATH
|
||||||
|
check_tar;
|
||||||
|
TOOLCHAIN_TAR="$(basename "$TOOLCHAIN_URL")";
|
||||||
|
TOOLCHAIN_DIR="$(echo "$TOOLCHAIN_TAR" | sed "s/-$VER.tar.gz//g")";
|
||||||
|
if ! check_downloaded_toolchain; then
|
||||||
|
curl_wget_check;
|
||||||
|
download_toolchain;
|
||||||
|
fi
|
||||||
|
remove_old_tooclhain;
|
||||||
|
unpack_toolchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
trap clearing EXIT;
|
||||||
|
trap clearing 2; # SIGINT not coverable by EXIT
|
||||||
|
main "$1"; # toochain version
|
||||||
@@ -31,4 +31,4 @@ Write-Host "done!"
|
|||||||
|
|
||||||
Write-Host -NoNewline "Clearing temporary files.."
|
Write-Host -NoNewline "Clearing temporary files.."
|
||||||
Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force
|
Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force
|
||||||
Write-Host "done!"
|
Write-Host "done!"
|
||||||
|
|||||||
@@ -64,8 +64,13 @@ class AppManager:
|
|||||||
nonlocal app_manifests
|
nonlocal app_manifests
|
||||||
app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name))
|
app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name))
|
||||||
|
|
||||||
with open(app_manifest_path, "rt") as manifest_file:
|
try:
|
||||||
exec(manifest_file.read())
|
with open(app_manifest_path, "rt") as manifest_file:
|
||||||
|
exec(manifest_file.read())
|
||||||
|
except Exception as e:
|
||||||
|
raise FlipperManifestException(
|
||||||
|
f"Failed parsing manifest '{app_manifest_path}' : {e}"
|
||||||
|
)
|
||||||
|
|
||||||
if len(app_manifests) == 0:
|
if len(app_manifests) == 0:
|
||||||
raise FlipperManifestException(
|
raise FlipperManifestException(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import SCons
|
import SCons
|
||||||
from SCons.Subst import quote_spaces
|
from SCons.Subst import quote_spaces
|
||||||
|
from SCons.Errors import StopError
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
@@ -30,7 +31,7 @@ def link_dir(target_path, source_path, is_windows):
|
|||||||
import _winapi
|
import _winapi
|
||||||
|
|
||||||
if not os.path.isdir(source_path):
|
if not os.path.isdir(source_path):
|
||||||
raise Exception(f"Source directory {source_path} is not a directory")
|
raise StopError(f"Source directory {source_path} is not a directory")
|
||||||
|
|
||||||
if not os.path.exists(target_path):
|
if not os.path.exists(target_path):
|
||||||
_winapi.CreateJunction(source_path, target_path)
|
_winapi.CreateJunction(source_path, target_path)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from SCons.Errors import StopError
|
||||||
from SCons.Tool import asm
|
from SCons.Tool import asm
|
||||||
from SCons.Tool import gcc
|
from SCons.Tool import gcc
|
||||||
from SCons.Tool import gxx
|
from SCons.Tool import gxx
|
||||||
@@ -65,7 +66,7 @@ def generate(env, **kw):
|
|||||||
# print("CC version =", cc_version)
|
# print("CC version =", cc_version)
|
||||||
# print(list(filter(lambda v: v in cc_version, whitelisted_versions)))
|
# print(list(filter(lambda v: v in cc_version, whitelisted_versions)))
|
||||||
if not any(filter(lambda v: v in cc_version, whitelisted_versions)):
|
if not any(filter(lambda v: v in cc_version, whitelisted_versions)):
|
||||||
raise Exception(
|
raise StopError(
|
||||||
f"Toolchain version is not supported. Allowed: {whitelisted_versions}, toolchain: {cc_version} "
|
f"Toolchain version is not supported. Allowed: {whitelisted_versions}, toolchain: {cc_version} "
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
from SCons.Builder import Builder
|
from SCons.Builder import Builder
|
||||||
from SCons.Action import Action
|
from SCons.Action import Action
|
||||||
|
from SCons.Errors import UserError
|
||||||
|
|
||||||
import SCons
|
import SCons
|
||||||
from fbt.appmanifest import FlipperAppType, AppManager, ApplicationsCGenerator
|
from fbt.appmanifest import (
|
||||||
|
FlipperAppType,
|
||||||
|
AppManager,
|
||||||
|
ApplicationsCGenerator,
|
||||||
|
FlipperManifestException,
|
||||||
|
)
|
||||||
|
|
||||||
# Adding objects for application management to env
|
# Adding objects for application management to env
|
||||||
# AppManager env["APPMGR"] - loads all manifests; manages list of known apps
|
# AppManager env["APPMGR"] - loads all manifests; manages list of known apps
|
||||||
@@ -13,7 +19,10 @@ def LoadApplicationManifests(env):
|
|||||||
appmgr = env["APPMGR"] = AppManager()
|
appmgr = env["APPMGR"] = AppManager()
|
||||||
for entry in env.Glob("#/applications/*"):
|
for entry in env.Glob("#/applications/*"):
|
||||||
if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."):
|
if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."):
|
||||||
appmgr.load_manifest(entry.File("application.fam").abspath, entry.name)
|
try:
|
||||||
|
appmgr.load_manifest(entry.File("application.fam").abspath, entry.name)
|
||||||
|
except FlipperManifestException as e:
|
||||||
|
raise UserError(e)
|
||||||
|
|
||||||
|
|
||||||
def PrepareApplicationsBuild(env):
|
def PrepareApplicationsBuild(env):
|
||||||
|
|||||||
Reference in New Issue
Block a user