1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Merge branch 'fz-dev' into dev

This commit is contained in:
Eng1n33r
2022-07-14 20:24:33 +03:00
29 changed files with 843 additions and 51 deletions

3
.gitignore vendored
View File

@@ -48,3 +48,6 @@ build/
# Toolchain # Toolchain
/toolchain /toolchain
# openocd output file
openocd.log

View File

@@ -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}",

View File

@@ -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(

View File

@@ -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(

View File

@@ -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

View File

@@ -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;

View 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,
)

View File

@@ -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,
};

View File

@@ -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

View File

@@ -0,0 +1,2 @@
ADD_SCENE(storage_move_to_sd, confirm, Confirm)
ADD_SCENE(storage_move_to_sd, progress, Progress)

View File

@@ -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);
}

View File

@@ -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);
}

View 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;
}

View 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
View File

@@ -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
View File

@@ -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% %*"

View File

@@ -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",

View File

@@ -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

View File

@@ -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;

View 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
View 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;

View 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

View File

@@ -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(

View File

@@ -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)

View File

@@ -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} "
) )

View File

@@ -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):