mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-17 04:34:44 -07:00
Merge branch 'ofwdev' into 420
This commit is contained in:
30
SConstruct
30
SConstruct
@@ -43,6 +43,7 @@ distenv = coreenv.Clone(
|
||||
"jflash",
|
||||
],
|
||||
ENV=os.environ,
|
||||
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
|
||||
)
|
||||
|
||||
firmware_env = distenv.AddFwProject(
|
||||
@@ -140,21 +141,28 @@ distenv.Default(basic_dist)
|
||||
dist_dir = distenv.GetProjetDirName()
|
||||
fap_dist = [
|
||||
distenv.Install(
|
||||
f"#/dist/{dist_dir}/apps/debug_elf",
|
||||
firmware_env["FW_EXTAPPS"]["debug"].values(),
|
||||
distenv.Dir(f"#/dist/{dist_dir}/apps/debug_elf"),
|
||||
list(
|
||||
app_artifact.debug
|
||||
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
|
||||
),
|
||||
),
|
||||
*(
|
||||
distenv.Install(f"#/dist/{dist_dir}/apps/{dist_entry[0]}", dist_entry[1])
|
||||
for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values()
|
||||
distenv.Install(
|
||||
f"#/dist/{dist_dir}/apps",
|
||||
"#/assets/resources/apps",
|
||||
),
|
||||
]
|
||||
Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values())
|
||||
Depends(
|
||||
fap_dist,
|
||||
list(
|
||||
app_artifact.validator
|
||||
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
|
||||
),
|
||||
)
|
||||
Alias("fap_dist", fap_dist)
|
||||
# distenv.Default(fap_dist)
|
||||
|
||||
distenv.Depends(
|
||||
firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"]["resources_dist"]
|
||||
)
|
||||
distenv.Depends(firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"].resources_dist)
|
||||
|
||||
|
||||
# Target for bundling core2 package for qFlipper
|
||||
@@ -192,6 +200,7 @@ firmware_debug = distenv.PhonyTarget(
|
||||
source=firmware_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT"),
|
||||
)
|
||||
distenv.Depends(firmware_debug, firmware_flash)
|
||||
|
||||
@@ -201,6 +210,7 @@ distenv.PhonyTarget(
|
||||
source=firmware_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT"),
|
||||
)
|
||||
|
||||
# Debug alien elf
|
||||
@@ -209,7 +219,7 @@ distenv.PhonyTarget(
|
||||
"${GDBPYCOM}",
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
GDBPYOPTS='-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ',
|
||||
GDBPYOPTS='-ex "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py" ',
|
||||
)
|
||||
|
||||
distenv.PhonyTarget(
|
||||
|
||||
@@ -14,4 +14,5 @@ App(
|
||||
fap_category="Main",
|
||||
fap_icon="badusb_10px.png",
|
||||
fap_icon_assets="images",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -347,10 +347,6 @@ static int32_t
|
||||
furi_hal_hid_kb_release(key);
|
||||
return (0);
|
||||
}
|
||||
if(error != NULL) {
|
||||
strncpy(error, "Unknown error", error_len);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
|
||||
@@ -679,7 +675,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
|
||||
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
|
||||
furi_assert(file_path);
|
||||
|
||||
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
|
||||
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); //-V773
|
||||
bad_usb->file_path = furi_string_alloc();
|
||||
furi_string_set(bad_usb->file_path, file_path);
|
||||
bad_usb_script_set_default_keyboard_layout(bad_usb);
|
||||
|
||||
@@ -168,7 +168,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
||||
}
|
||||
|
||||
static FapLoader* fap_loader_alloc(const char* path) {
|
||||
FapLoader* loader = malloc(sizeof(FapLoader));
|
||||
FapLoader* loader = malloc(sizeof(FapLoader)); //-V773
|
||||
|
||||
char* tmp = malloc(strlen(path) + 1);
|
||||
strcpy(tmp, path);
|
||||
|
||||
@@ -11,4 +11,5 @@ App(
|
||||
fap_icon="gpioIcon.png",
|
||||
fap_category="Main",
|
||||
fap_icon_assets="images",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -184,7 +184,7 @@ static int32_t usb_uart_worker(void* context) {
|
||||
while(1) {
|
||||
uint32_t events =
|
||||
furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_check((events & FuriFlagError) == 0);
|
||||
furi_check(!(events & FuriFlagError));
|
||||
if(events & WorkerEvtStop) break;
|
||||
if(events & WorkerEvtRxDone) {
|
||||
size_t len = furi_stream_buffer_receive(
|
||||
@@ -288,7 +288,7 @@ static int32_t usb_uart_tx_thread(void* context) {
|
||||
while(1) {
|
||||
uint32_t events =
|
||||
furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_check((events & FuriFlagError) == 0);
|
||||
furi_check(!(events & FuriFlagError));
|
||||
if(events & WorkerEvtTxStop) break;
|
||||
if(events & WorkerEvtCdcRx) {
|
||||
furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
@@ -14,4 +14,5 @@ App(
|
||||
fap_icon="iBIcon.png",
|
||||
fap_category="Main",
|
||||
fap_icon_assets="images",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -15,4 +15,5 @@ App(
|
||||
fap_category="Main",
|
||||
fap_icon="ir_10px.png",
|
||||
fap_icon_assets="images",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -15,12 +15,5 @@ App(
|
||||
fap_category="Main",
|
||||
fap_icon="125_10px.png",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
|
||||
App(
|
||||
appid="lfrfid_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="lfrfid_on_system_start",
|
||||
requires=["lfrfid"],
|
||||
order=50,
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
|
||||
}
|
||||
|
||||
static LfRfid* lfrfid_alloc() {
|
||||
LfRfid* lfrfid = malloc(sizeof(LfRfid));
|
||||
LfRfid* lfrfid = malloc(sizeof(LfRfid)); //-V773
|
||||
|
||||
lfrfid->storage = furi_record_open(RECORD_STORAGE);
|
||||
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
@@ -24,7 +24,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) {
|
||||
widget_add_button_element(
|
||||
widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc);
|
||||
|
||||
FuriString* temp_str;
|
||||
FuriString* temp_str = NULL;
|
||||
if(furi_string_size(nfc->dev->dev_data.parsed_data)) {
|
||||
temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data);
|
||||
} else {
|
||||
|
||||
@@ -31,7 +31,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
|
||||
nfc_scene_mf_ultralight_read_success_widget_callback,
|
||||
nfc);
|
||||
|
||||
FuriString* temp_str;
|
||||
FuriString* temp_str = NULL;
|
||||
if(furi_string_size(nfc->dev->dev_data.parsed_data)) {
|
||||
temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data);
|
||||
} else {
|
||||
|
||||
@@ -520,12 +520,6 @@ bool subghz_path_is_file(FuriString* path) {
|
||||
}
|
||||
|
||||
uint32_t subghz_random_serial(void) {
|
||||
static bool rand_generator_inited = false;
|
||||
|
||||
if(!rand_generator_inited) {
|
||||
srand(DWT->CYCCNT);
|
||||
rand_generator_inited = true;
|
||||
}
|
||||
return (uint32_t)rand();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,4 +14,5 @@ App(
|
||||
fap_icon="U2FIcon.png",
|
||||
fap_category="Main",
|
||||
fap_icon_assets="images",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -203,7 +203,7 @@ static int32_t u2f_hid_worker(void* context) {
|
||||
WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest,
|
||||
FuriFlagWaitAny,
|
||||
FuriWaitForever);
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
furi_check(!(flags & FuriFlagError));
|
||||
if(flags & WorkerEvtStop) break;
|
||||
if(flags & WorkerEvtConnect) {
|
||||
u2f_set_state(u2f_hid->u2f_instance, 1);
|
||||
|
||||
@@ -294,7 +294,6 @@ static void
|
||||
|
||||
int32_t snake_game_app(void* p) {
|
||||
UNUSED(p);
|
||||
srand(DWT->CYCCNT);
|
||||
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SnakeEvent));
|
||||
|
||||
|
||||
@@ -200,7 +200,6 @@ void ws_protocol_decoder_ambient_weather_feed(void* context, bool level, uint32_
|
||||
((instance->decoder.decode_data & AMBIENT_WEATHER_PACKET_HEADER_MASK) ==
|
||||
AMBIENT_WEATHER_PACKET_HEADER_2)) {
|
||||
if(ws_protocol_ambient_weather_check_crc(instance)) {
|
||||
instance->decoder.decode_data = instance->decoder.decode_data;
|
||||
instance->generic.data = instance->decoder.decode_data;
|
||||
instance->generic.data_count_bit =
|
||||
ws_protocol_ambient_weather_const.min_count_bit_for_found;
|
||||
|
||||
@@ -61,15 +61,20 @@ static void gpio_print_pins(void) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum { OK, ERR_CMD_SYNTAX, ERR_PIN, ERR_VALUE } GpioParseError;
|
||||
typedef enum {
|
||||
GpioParseReturnOk,
|
||||
GpioParseReturnCmdSyntaxError,
|
||||
GpioParseReturnPinError,
|
||||
GpioParseReturnValueError
|
||||
} GpioParseReturn;
|
||||
|
||||
static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
|
||||
static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
|
||||
FuriString* pin_name;
|
||||
pin_name = furi_string_alloc();
|
||||
|
||||
size_t ws = furi_string_search_char(args, ' ');
|
||||
if(ws == FURI_STRING_FAILURE) {
|
||||
return ERR_CMD_SYNTAX;
|
||||
return GpioParseReturnCmdSyntaxError;
|
||||
}
|
||||
|
||||
furi_string_set_n(pin_name, args, 0, ws);
|
||||
@@ -78,7 +83,7 @@ static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint
|
||||
|
||||
if(!pin_name_to_int(pin_name, pin_num)) {
|
||||
furi_string_free(pin_name);
|
||||
return ERR_PIN;
|
||||
return GpioParseReturnPinError;
|
||||
}
|
||||
|
||||
furi_string_free(pin_name);
|
||||
@@ -88,10 +93,10 @@ static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint
|
||||
} else if(!furi_string_cmp(args, "1")) {
|
||||
*value = 1;
|
||||
} else {
|
||||
return ERR_VALUE;
|
||||
return GpioParseReturnValueError;
|
||||
}
|
||||
|
||||
return OK;
|
||||
return GpioParseReturnOk;
|
||||
}
|
||||
|
||||
void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
|
||||
@@ -101,15 +106,15 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
|
||||
size_t num = 0;
|
||||
uint8_t value = 255;
|
||||
|
||||
GpioParseError err = gpio_command_parse(args, &num, &value);
|
||||
GpioParseReturn err = gpio_command_parse(args, &num, &value);
|
||||
|
||||
if(ERR_CMD_SYNTAX == err) {
|
||||
if(err == GpioParseReturnCmdSyntaxError) {
|
||||
cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args));
|
||||
return;
|
||||
} else if(ERR_PIN == err) {
|
||||
} else if(err == GpioParseReturnPinError) {
|
||||
gpio_print_pins();
|
||||
return;
|
||||
} else if(ERR_VALUE == err) {
|
||||
} else if(err == GpioParseReturnValueError) {
|
||||
printf("Value is invalid. Enter 1 for input or 0 for output");
|
||||
return;
|
||||
}
|
||||
@@ -161,15 +166,15 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
size_t num = 0;
|
||||
uint8_t value = 0;
|
||||
GpioParseError err = gpio_command_parse(args, &num, &value);
|
||||
GpioParseReturn err = gpio_command_parse(args, &num, &value);
|
||||
|
||||
if(ERR_CMD_SYNTAX == err) {
|
||||
if(err == GpioParseReturnCmdSyntaxError) {
|
||||
cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args));
|
||||
return;
|
||||
} else if(ERR_PIN == err) {
|
||||
} else if(err == GpioParseReturnPinError) {
|
||||
gpio_print_pins();
|
||||
return;
|
||||
} else if(ERR_VALUE == err) {
|
||||
} else if(err == GpioParseReturnValueError) {
|
||||
printf("Value is invalid. Enter 1 for high or 0 for low");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ static int32_t vcp_worker(void* context) {
|
||||
while(1) {
|
||||
uint32_t flags =
|
||||
furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_assert((flags & FuriFlagError) == 0);
|
||||
furi_assert(!(flags & FuriFlagError));
|
||||
|
||||
// VCP session opened
|
||||
if(flags & VcpEvtConnect) {
|
||||
@@ -303,7 +303,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
||||
static void vcp_on_cdc_rx(void* context) {
|
||||
UNUSED(context);
|
||||
uint32_t ret = furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtRx);
|
||||
furi_check((ret & FuriFlagError) == 0);
|
||||
furi_check(!(ret & FuriFlagError));
|
||||
}
|
||||
|
||||
static void vcp_on_cdc_tx_complete(void* context) {
|
||||
|
||||
@@ -167,7 +167,7 @@ void crypto_cli_decrypt(Cli* cli, FuriString* args) {
|
||||
void crypto_cli_has_key(Cli* cli, FuriString* args) {
|
||||
UNUSED(cli);
|
||||
int key_slot = 0;
|
||||
uint8_t iv[16];
|
||||
uint8_t iv[16] = {0};
|
||||
|
||||
do {
|
||||
if(!args_read_int_and_trim(args, &key_slot) || !(key_slot > 0 && key_slot <= 100)) {
|
||||
@@ -249,7 +249,7 @@ void crypto_cli_store_key(Cli* cli, FuriString* args) {
|
||||
}
|
||||
|
||||
if(key_slot > 0) {
|
||||
uint8_t iv[16];
|
||||
uint8_t iv[16] = {0};
|
||||
if(key_slot > 1) {
|
||||
if(!furi_hal_crypto_store_load_key(key_slot - 1, iv)) {
|
||||
printf(
|
||||
|
||||
@@ -419,7 +419,7 @@ void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, vo
|
||||
const CanvasCallbackPair p = {callback, context};
|
||||
|
||||
gui_lock(gui);
|
||||
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0);
|
||||
furi_assert(!CanvasCallbackPairArray_count(gui->canvas_callback_pair, p));
|
||||
CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p);
|
||||
gui_unlock(gui);
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ static int32_t browser_worker(void* context) {
|
||||
|
||||
BrowserWorker*
|
||||
file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets) {
|
||||
BrowserWorker* browser = malloc(sizeof(BrowserWorker));
|
||||
BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
|
||||
|
||||
idx_last_array_init(browser->idx_last);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ WidgetElement* widget_element_button_create(
|
||||
ButtonCallback callback,
|
||||
void* context) {
|
||||
// Allocate and init model
|
||||
GuiButtonModel* model = malloc(sizeof(GuiButtonModel));
|
||||
GuiButtonModel* model = malloc(sizeof(GuiButtonModel)); //-V773
|
||||
model->button_type = button_type;
|
||||
model->callback = callback;
|
||||
model->context = context;
|
||||
|
||||
@@ -23,7 +23,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
|
||||
gui_remove_view_port(view_dispatcher->gui, view_dispatcher->view_port);
|
||||
}
|
||||
// Crash if not all views were freed
|
||||
furi_assert(ViewDict_size(view_dispatcher->views) == 0);
|
||||
furi_assert(!ViewDict_size(view_dispatcher->views));
|
||||
|
||||
ViewDict_clear(view_dispatcher->views);
|
||||
// Free ViewPort
|
||||
@@ -157,7 +157,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
|
||||
view_dispatcher->ongoing_input_view = NULL;
|
||||
}
|
||||
// Remove view
|
||||
ViewDict_erase(view_dispatcher->views, view_id);
|
||||
furi_check(ViewDict_erase(view_dispatcher->views, view_id));
|
||||
|
||||
view_set_update_callback(view, NULL);
|
||||
view_set_update_callback_context(view, NULL);
|
||||
|
||||
@@ -280,7 +280,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
|
||||
event.type = LoaderEventTypeApplicationStarted;
|
||||
furi_pubsub_publish(loader_instance->pubsub, &event);
|
||||
|
||||
if(!loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe) {
|
||||
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
|
||||
furi_hal_power_insomnia_enter();
|
||||
}
|
||||
} else if(thread_state == FuriThreadStateStopped) {
|
||||
@@ -295,7 +295,7 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
|
||||
loader_instance->application_arguments = NULL;
|
||||
}
|
||||
|
||||
if(!loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe) {
|
||||
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
|
||||
furi_hal_power_insomnia_exit();
|
||||
}
|
||||
loader_unlock(instance);
|
||||
|
||||
@@ -275,7 +275,7 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args
|
||||
uint32_t buffer_size;
|
||||
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
|
||||
|
||||
if(parsed_count == EOF || parsed_count != 1) {
|
||||
if(parsed_count != 1) {
|
||||
storage_cli_print_usage();
|
||||
} else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint64_t file_size = storage_file_size(file);
|
||||
@@ -315,7 +315,7 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args
|
||||
uint32_t buffer_size;
|
||||
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
|
||||
|
||||
if(parsed_count == EOF || parsed_count != 1) {
|
||||
if(parsed_count != 1) {
|
||||
storage_cli_print_usage();
|
||||
} else {
|
||||
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
|
||||
|
||||
@@ -545,8 +545,8 @@ static FS_Error
|
||||
|
||||
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) {
|
||||
FS_Error error;
|
||||
const char* new_path_tmp;
|
||||
FuriString* new_path_next;
|
||||
const char* new_path_tmp = NULL;
|
||||
FuriString* new_path_next = NULL;
|
||||
new_path_next = furi_string_alloc();
|
||||
|
||||
FileInfo fileinfo;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Tuple, Dict
|
||||
from typing import Optional, Tuple, Dict, ClassVar
|
||||
import struct
|
||||
import posixpath
|
||||
import os
|
||||
@@ -22,14 +22,18 @@ class AppState:
|
||||
debug_link_elf: str = ""
|
||||
debug_link_crc: int = 0
|
||||
|
||||
DEBUG_ELF_ROOT: ClassVar[Optional[str]] = None
|
||||
|
||||
def __post_init__(self):
|
||||
if self.other_sections is None:
|
||||
self.other_sections = {}
|
||||
|
||||
def get_original_elf_path(self, elf_path="build/latest/.extapps") -> str:
|
||||
def get_original_elf_path(self) -> str:
|
||||
if self.DEBUG_ELF_ROOT is None:
|
||||
raise ValueError("DEBUG_ELF_ROOT not set; call fap-set-debug-elf-root")
|
||||
return (
|
||||
posixpath.join(elf_path, self.debug_link_elf)
|
||||
if elf_path
|
||||
posixpath.join(self.DEBUG_ELF_ROOT, self.debug_link_elf)
|
||||
if self.DEBUG_ELF_ROOT
|
||||
else self.debug_link_elf
|
||||
)
|
||||
|
||||
@@ -84,7 +88,9 @@ class AppState:
|
||||
if debug_link_size := int(app_state["debug_link_info"]["debug_link_size"]):
|
||||
debug_link_data = (
|
||||
gdb.selected_inferior()
|
||||
.read_memory(int(app_state["debug_link_info"]["debug_link"]), debug_link_size)
|
||||
.read_memory(
|
||||
int(app_state["debug_link_info"]["debug_link"]), debug_link_size
|
||||
)
|
||||
.tobytes()
|
||||
)
|
||||
state.debug_link_elf, state.debug_link_crc = AppState.parse_debug_link_data(
|
||||
@@ -103,6 +109,29 @@ class AppState:
|
||||
return state
|
||||
|
||||
|
||||
class SetFapDebugElfRoot(gdb.Command):
|
||||
"""Set path to original ELF files for debug info"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
"fap-set-debug-elf-root", gdb.COMMAND_FILES, gdb.COMPLETE_FILENAME
|
||||
)
|
||||
self.dont_repeat()
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
AppState.DEBUG_ELF_ROOT = arg
|
||||
try:
|
||||
global helper
|
||||
print(f"Set '{arg}' as debug info lookup path for Flipper external apps")
|
||||
helper.attach_fw()
|
||||
gdb.events.stop.connect(helper.handle_stop)
|
||||
except gdb.error as e:
|
||||
print(f"Support for Flipper external apps debug is not available: {e}")
|
||||
|
||||
|
||||
SetFapDebugElfRoot()
|
||||
|
||||
|
||||
class FlipperAppDebugHelper:
|
||||
def __init__(self):
|
||||
self.app_ptr = None
|
||||
@@ -149,9 +178,4 @@ class FlipperAppDebugHelper:
|
||||
|
||||
|
||||
helper = FlipperAppDebugHelper()
|
||||
try:
|
||||
helper.attach_fw()
|
||||
print("Support for Flipper external apps debug is enabled")
|
||||
gdb.events.stop.connect(helper.handle_stop)
|
||||
except gdb.error as e:
|
||||
print(f"Support for Flipper external apps debug is not available: {e}")
|
||||
print("Support for Flipper external apps debug is loaded")
|
||||
|
||||
@@ -49,12 +49,12 @@ OPENOCD_OPTS = [
|
||||
"-c",
|
||||
"transport select hla_swd",
|
||||
"-f",
|
||||
"debug/stm32wbx.cfg",
|
||||
"${FBT_DEBUG_DIR}/stm32wbx.cfg",
|
||||
"-c",
|
||||
"stm32wbx.cpu configure -rtos auto",
|
||||
]
|
||||
|
||||
SVD_FILE = "debug/STM32WB55_CM4.svd"
|
||||
SVD_FILE = "${FBT_DEBUG_DIR}/STM32WB55_CM4.svd"
|
||||
|
||||
# Look for blackmagic probe on serial ports and local network
|
||||
BLACKMAGIC = "auto"
|
||||
|
||||
@@ -20,8 +20,7 @@ env = ENV.Clone(
|
||||
BUILD_DIR=fw_build_meta["build_dir"],
|
||||
IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware",
|
||||
FW_FLAVOR=fw_build_meta["flavor"],
|
||||
PLUGIN_ELF_DIR="${BUILD_DIR}",
|
||||
LIB_DIST_DIR="${BUILD_DIR}/lib",
|
||||
LIB_DIST_DIR=fw_build_meta["build_dir"].Dir("lib"),
|
||||
LINT_SOURCES=[
|
||||
"applications",
|
||||
],
|
||||
@@ -142,12 +141,14 @@ for app_dir, _ in env["APPDIRS"]:
|
||||
|
||||
fwenv.PrepareApplicationsBuild()
|
||||
|
||||
# Build external apps
|
||||
# Build external apps + configure SDK
|
||||
if env["IS_BASE_FIRMWARE"]:
|
||||
extapps = fwenv["FW_EXTAPPS"] = SConscript(
|
||||
"site_scons/extapps.scons", exports={"ENV": fwenv}
|
||||
fwenv.SetDefault(FBT_FAP_DEBUG_ELF_ROOT="${BUILD_DIR}/.extapps")
|
||||
fwenv["FW_EXTAPPS"] = SConscript(
|
||||
"site_scons/extapps.scons",
|
||||
exports={"ENV": fwenv},
|
||||
)
|
||||
fw_artifacts.append(extapps["sdk_tree"])
|
||||
fw_artifacts.append(fwenv["FW_EXTAPPS"].sdk_tree)
|
||||
|
||||
|
||||
# Add preprocessor definitions for current set of apps
|
||||
|
||||
@@ -179,7 +179,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
|
||||
|
||||
case EVT_BLUE_GAP_PASS_KEY_REQUEST: {
|
||||
// Generate random PIN code
|
||||
uint32_t pin = rand() % 999999;
|
||||
uint32_t pin = rand() % 999999; //-V1064
|
||||
aci_gap_pass_key_resp(gap->service.connection_handle, pin);
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
|
||||
FURI_LOG_I(TAG, "Pass key request event. Pin: ******");
|
||||
@@ -478,7 +478,6 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
|
||||
|
||||
gap = malloc(sizeof(Gap));
|
||||
gap->config = config;
|
||||
srand(DWT->CYCCNT);
|
||||
// Create advertising timer
|
||||
gap->advertise_timer = furi_timer_alloc(gap_advetise_timer_callback, FuriTimerTypeOnce, NULL);
|
||||
// Initialization of GATT & GAP layer
|
||||
|
||||
@@ -91,7 +91,7 @@ bool furi_hal_crypto_verify_key(uint8_t key_slot) {
|
||||
uint8_t keys_nb = 0;
|
||||
uint8_t valid_keys_nb = 0;
|
||||
uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS;
|
||||
uint8_t empty_iv[16];
|
||||
uint8_t empty_iv[16] = {0};
|
||||
furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb);
|
||||
if(key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key
|
||||
if(key_slot > keys_nb) return false;
|
||||
|
||||
@@ -46,7 +46,7 @@ FURI_NORETURN void __furi_halt();
|
||||
/** Check condition and crash if check failed */
|
||||
#define furi_check(__e) \
|
||||
do { \
|
||||
if((__e) == 0) { \
|
||||
if(!(__e)) { \
|
||||
furi_crash("furi_check failed\r\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
@@ -55,7 +55,7 @@ FURI_NORETURN void __furi_halt();
|
||||
#ifdef FURI_DEBUG
|
||||
#define furi_assert(__e) \
|
||||
do { \
|
||||
if((__e) == 0) { \
|
||||
if(!(__e)) { \
|
||||
furi_crash("furi_assert failed\r\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
@@ -25,7 +25,7 @@ uint32_t furi_event_flag_set(FuriEventFlag* instance, uint32_t flags) {
|
||||
uint32_t rflags;
|
||||
BaseType_t yield;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
yield = pdFALSE;
|
||||
if(xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) {
|
||||
rflags = (uint32_t)FuriStatusErrorResource;
|
||||
@@ -48,7 +48,7 @@ uint32_t furi_event_flag_clear(FuriEventFlag* instance, uint32_t flags) {
|
||||
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)instance;
|
||||
uint32_t rflags;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
rflags = xEventGroupGetBitsFromISR(hEventGroup);
|
||||
|
||||
if(xEventGroupClearBitsFromISR(hEventGroup, (EventBits_t)flags) == pdFAIL) {
|
||||
@@ -73,7 +73,7 @@ uint32_t furi_event_flag_get(FuriEventFlag* instance) {
|
||||
EventGroupHandle_t hEventGroup = (EventGroupHandle_t)instance;
|
||||
uint32_t rflags;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
rflags = xEventGroupGetBitsFromISR(hEventGroup);
|
||||
} else {
|
||||
rflags = xEventGroupGetBits(hEventGroup);
|
||||
|
||||
@@ -150,8 +150,7 @@ void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) {
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
memmgr_heap_thread_trace_depth++;
|
||||
furi_check(MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id) != NULL);
|
||||
MemmgrHeapThreadDict_erase(memmgr_heap_thread_dict, (uint32_t)thread_id);
|
||||
furi_check(MemmgrHeapThreadDict_erase(memmgr_heap_thread_dict, (uint32_t)thread_id));
|
||||
memmgr_heap_thread_trace_depth--;
|
||||
}
|
||||
(void)xTaskResumeAll();
|
||||
@@ -212,7 +211,8 @@ static inline void traceFREE(void* pointer, size_t size) {
|
||||
MemmgrHeapAllocDict_t* alloc_dict =
|
||||
MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id);
|
||||
if(alloc_dict) {
|
||||
MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer);
|
||||
// In some cases thread may want to release memory that was not allocated by it
|
||||
(void)MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer);
|
||||
}
|
||||
memmgr_heap_thread_trace_depth--;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ FuriStatus furi_mutex_acquire(FuriMutex* instance, uint32_t timeout) {
|
||||
|
||||
stat = FuriStatusOk;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
stat = FuriStatusErrorISR;
|
||||
} else if(hMutex == NULL) {
|
||||
stat = FuriStatusErrorParameter;
|
||||
@@ -85,7 +85,7 @@ FuriStatus furi_mutex_release(FuriMutex* instance) {
|
||||
|
||||
stat = FuriStatusOk;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
stat = FuriStatusErrorISR;
|
||||
} else if(hMutex == NULL) {
|
||||
stat = FuriStatusErrorParameter;
|
||||
@@ -111,7 +111,7 @@ FuriThreadId furi_mutex_get_owner(FuriMutex* instance) {
|
||||
|
||||
hMutex = (SemaphoreHandle_t)((uint32_t)instance & ~1U);
|
||||
|
||||
if((FURI_IS_IRQ_MODE() != 0U) || (hMutex == NULL)) {
|
||||
if((FURI_IS_IRQ_MODE()) || (hMutex == NULL)) {
|
||||
owner = 0;
|
||||
} else {
|
||||
owner = (FuriThreadId)xSemaphoreGetMutexHolder(hMutex);
|
||||
|
||||
@@ -45,7 +45,7 @@ FuriStatus furi_semaphore_acquire(FuriSemaphore* instance, uint32_t timeout) {
|
||||
|
||||
stat = FuriStatusOk;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
if(timeout != 0U) {
|
||||
stat = FuriStatusErrorParameter;
|
||||
} else {
|
||||
@@ -80,7 +80,7 @@ FuriStatus furi_semaphore_release(FuriSemaphore* instance) {
|
||||
|
||||
stat = FuriStatusOk;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
yield = pdFALSE;
|
||||
|
||||
if(xSemaphoreGiveFromISR(hSemaphore, &yield) != pdTRUE) {
|
||||
@@ -104,7 +104,7 @@ uint32_t furi_semaphore_get_count(FuriSemaphore* instance) {
|
||||
SemaphoreHandle_t hSemaphore = (SemaphoreHandle_t)instance;
|
||||
uint32_t count;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
count = (uint32_t)uxSemaphoreGetCountFromISR(hSemaphore);
|
||||
} else {
|
||||
count = (uint32_t)uxSemaphoreGetCount(hSemaphore);
|
||||
|
||||
@@ -23,7 +23,7 @@ size_t furi_stream_buffer_send(
|
||||
uint32_t timeout) {
|
||||
size_t ret;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
BaseType_t yield;
|
||||
ret = xStreamBufferSendFromISR(stream_buffer, data, length, &yield);
|
||||
portYIELD_FROM_ISR(yield);
|
||||
@@ -41,7 +41,7 @@ size_t furi_stream_buffer_receive(
|
||||
uint32_t timeout) {
|
||||
size_t ret;
|
||||
|
||||
if(FURI_IS_IRQ_MODE() != 0U) {
|
||||
if(FURI_IS_IRQ_MODE()) {
|
||||
BaseType_t yield;
|
||||
ret = xStreamBufferReceiveFromISR(stream_buffer, data, length, &yield);
|
||||
portYIELD_FROM_ISR(yield);
|
||||
|
||||
@@ -29,13 +29,13 @@ FuriString* furi_string_alloc() {
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_set(const FuriString* s) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
FuriString* string = malloc(sizeof(FuriString)); //-V773
|
||||
string_init_set(string->string, s->string);
|
||||
return string;
|
||||
}
|
||||
|
||||
FuriString* furi_string_alloc_set_str(const char cstr[]) {
|
||||
FuriString* string = malloc(sizeof(FuriString));
|
||||
FuriString* string = malloc(sizeof(FuriString)); //-V773
|
||||
string_init_set(string->string, cstr);
|
||||
return string;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread);
|
||||
__attribute__((__noreturn__)) void furi_thread_catch() {
|
||||
asm volatile("nop"); // extra magic
|
||||
furi_crash("You are doing it wrong");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static void furi_thread_set_state(FuriThread* thread, FuriThreadState state) {
|
||||
@@ -112,6 +113,12 @@ FuriThread* furi_thread_alloc() {
|
||||
FuriThread* thread = malloc(sizeof(FuriThread));
|
||||
thread->output.buffer = furi_string_alloc();
|
||||
thread->is_service = false;
|
||||
|
||||
if(furi_thread_get_current_id()) {
|
||||
FuriThread* parent = pvTaskGetThreadLocalStoragePointer(NULL, 0);
|
||||
if(parent) thread->heap_trace_enabled = parent->heap_trace_enabled;
|
||||
}
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
@@ -313,7 +313,7 @@ bool flipper_format_stream_write_value_line(Stream* stream, FlipperStreamWriteDa
|
||||
furi_crash("Unknown FF type");
|
||||
}
|
||||
|
||||
if((size_t)(i + 1) < write_data->data_size) {
|
||||
if(((size_t)i + 1) < write_data->data_size) {
|
||||
furi_string_cat(value, " ");
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,8 @@ static InfraredStatus infrared_common_decode_bits(InfraredCommonDecoder* decoder
|
||||
if(timings->min_split_time && !level) {
|
||||
if(timing > timings->min_split_time) {
|
||||
/* long low timing - check if we're ready for any of protocol modification */
|
||||
for(size_t i = 0; decoder->protocol->databit_len[i] &&
|
||||
(i < COUNT_OF(decoder->protocol->databit_len));
|
||||
for(size_t i = 0; i < COUNT_OF(decoder->protocol->databit_len) &&
|
||||
decoder->protocol->databit_len[i];
|
||||
++i) {
|
||||
if(decoder->protocol->databit_len[i] == decoder->databit_cnt) {
|
||||
return InfraredStatusReady;
|
||||
@@ -199,7 +199,7 @@ InfraredMessage* infrared_common_decoder_check_ready(InfraredCommonDecoder* deco
|
||||
bool found_length = false;
|
||||
|
||||
for(size_t i = 0;
|
||||
decoder->protocol->databit_len[i] && (i < COUNT_OF(decoder->protocol->databit_len));
|
||||
i < COUNT_OF(decoder->protocol->databit_len) && decoder->protocol->databit_len[i];
|
||||
++i) {
|
||||
if(decoder->protocol->databit_len[i] == decoder->databit_cnt) {
|
||||
found_length = true;
|
||||
|
||||
@@ -140,9 +140,8 @@ size_t lfrfid_worker_dict_get_data_size(LFRFIDWorker* worker, LFRFIDProtocol pro
|
||||
|
||||
static int32_t lfrfid_worker_thread(void* thread_context) {
|
||||
LFRFIDWorker* worker = thread_context;
|
||||
bool running = true;
|
||||
|
||||
while(running) {
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(LFRFIDEventAll, FuriFlagWaitAny, FuriWaitForever);
|
||||
if(flags != FuriFlagErrorTimeout) {
|
||||
// stop thread
|
||||
|
||||
@@ -541,7 +541,7 @@ static size_t _etoa(
|
||||
exp2 = (int)(expval * 3.321928094887362 + 0.5);
|
||||
const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
|
||||
const double z2 = z * z;
|
||||
conv.U = (uint64_t)(exp2 + 1023) << 52U;
|
||||
conv.U = ((uint64_t)exp2 + 1023) << 52U;
|
||||
// compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
|
||||
conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
|
||||
// correct for rounding errors
|
||||
|
||||
@@ -312,7 +312,6 @@ void subghz_protocol_decoder_power_smart_feed(
|
||||
if((instance->decoder.decode_data & POWER_SMART_PACKET_HEADER_MASK) ==
|
||||
POWER_SMART_PACKET_HEADER) {
|
||||
if(subghz_protocol_power_smart_chek_valid(instance->decoder.decode_data)) {
|
||||
instance->decoder.decode_data = instance->decoder.decode_data;
|
||||
instance->generic.data = instance->decoder.decode_data;
|
||||
instance->generic.data_count_bit =
|
||||
subghz_protocol_power_smart_const.min_count_bit_for_found;
|
||||
|
||||
@@ -464,7 +464,7 @@ bool subghz_keystore_raw_encrypted_save(
|
||||
}
|
||||
stream_write_cstring(output_stream, encrypted_line);
|
||||
|
||||
} while(ret > 0 && result);
|
||||
} while(result);
|
||||
|
||||
flipper_format_free(output_flipper_format);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import struct
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from .appmanifest import FlipperApplication
|
||||
from flipper.assets.icon import file2image
|
||||
|
||||
|
||||
_MANIFEST_MAGIC = 0x52474448
|
||||
@@ -53,8 +54,6 @@ def assemble_manifest_data(
|
||||
):
|
||||
image_data = b""
|
||||
if app_manifest.fap_icon:
|
||||
from flipper.assets.icon import file2image
|
||||
|
||||
image = file2image(os.path.join(app_manifest._apppath, app_manifest.fap_icon))
|
||||
if (image.width, image.height) != (10, 10):
|
||||
raise ValueError(
|
||||
|
||||
@@ -89,6 +89,9 @@ class SdkCache:
|
||||
syms.update(map(lambda e: e.name, self.get_variables()))
|
||||
return syms
|
||||
|
||||
def get_disabled_names(self):
|
||||
return set(map(lambda e: e.name, self.disabled_entries))
|
||||
|
||||
def get_functions(self):
|
||||
return self._filter_enabled(self.sdk.functions)
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ def generate(env):
|
||||
BUILDERS={
|
||||
"IconBuilder": Builder(
|
||||
action=Action(
|
||||
'${PYTHON3} "${ASSETS_COMPILER}" icons ${ABSPATHGETTERFUNC(SOURCE)} ${TARGET.dir} --filename ${ICON_FILE_NAME}',
|
||||
'${PYTHON3} "${ASSETS_COMPILER}" icons "${ABSPATHGETTERFUNC(SOURCE)}" "${TARGET.dir}" --filename ${ICON_FILE_NAME}',
|
||||
"${ICONSCOMSTR}",
|
||||
),
|
||||
emitter=icons_emitter,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from re import search
|
||||
|
||||
from SCons.Errors import UserError
|
||||
from fbt_options import OPENOCD_OPTS
|
||||
|
||||
|
||||
def _get_device_serials(search_str="STLink"):
|
||||
@@ -20,6 +19,9 @@ def GetDevices(env):
|
||||
|
||||
def generate(env, **kw):
|
||||
env.AddMethod(GetDevices)
|
||||
env.SetDefault(
|
||||
FBT_DEBUG_DIR="${ROOT_DIR}/debug",
|
||||
)
|
||||
|
||||
if (adapter_serial := env.subst("$OPENOCD_ADAPTER_SERIAL")) != "auto":
|
||||
env.Append(
|
||||
@@ -36,7 +38,7 @@ def generate(env, **kw):
|
||||
|
||||
env.SetDefault(
|
||||
OPENOCD_GDB_PIPE=[
|
||||
"|openocd -c 'gdb_port pipe; log_output debug/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||
],
|
||||
GDBOPTS_BASE=[
|
||||
"-ex",
|
||||
@@ -58,17 +60,19 @@ def generate(env, **kw):
|
||||
],
|
||||
GDBPYOPTS=[
|
||||
"-ex",
|
||||
"source debug/FreeRTOS/FreeRTOS.py",
|
||||
"source ${FBT_DEBUG_DIR}/FreeRTOS/FreeRTOS.py",
|
||||
"-ex",
|
||||
"source debug/flipperapps.py",
|
||||
"source ${FBT_DEBUG_DIR}/flipperapps.py",
|
||||
"-ex",
|
||||
"source debug/PyCortexMDebug/PyCortexMDebug.py",
|
||||
"fap-set-debug-elf-root ${FBT_FAP_DEBUG_ELF_ROOT}",
|
||||
"-ex",
|
||||
"source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py",
|
||||
"-ex",
|
||||
"svd_load ${SVD_FILE}",
|
||||
"-ex",
|
||||
"compare-sections",
|
||||
],
|
||||
JFLASHPROJECT="${ROOT_DIR.abspath}/debug/fw.jflash",
|
||||
JFLASHPROJECT="${FBT_DEBUG_DIR}/fw.jflash",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ def GetProjetDirName(env, project=None):
|
||||
|
||||
def create_fw_build_targets(env, configuration_name):
|
||||
flavor = GetProjetDirName(env, configuration_name)
|
||||
build_dir = env.Dir("build").Dir(flavor).abspath
|
||||
build_dir = env.Dir("build").Dir(flavor)
|
||||
return env.SConscript(
|
||||
"firmware.scons",
|
||||
variant_dir=build_dir,
|
||||
@@ -131,7 +131,7 @@ def generate(env):
|
||||
"UsbInstall": Builder(
|
||||
action=[
|
||||
Action(
|
||||
'${PYTHON3} "${SELFUPDATE_SCRIPT}" dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}/update.fuf'
|
||||
'${PYTHON3} "${SELFUPDATE_SCRIPT}" ${UPDATE_BUNDLE_DIR}/update.fuf'
|
||||
),
|
||||
Touch("${TARGET}"),
|
||||
]
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Action import Action
|
||||
from SCons.Errors import UserError
|
||||
from SCons.Node import NodeList
|
||||
import SCons.Warnings
|
||||
|
||||
from fbt.elfmanifest import assemble_manifest_data
|
||||
@@ -16,6 +19,15 @@ import shutil
|
||||
from ansi.color import fg
|
||||
|
||||
|
||||
@dataclass
|
||||
class FlipperExternalAppInfo:
|
||||
app: FlipperApplication
|
||||
compact: NodeList = field(default_factory=NodeList)
|
||||
debug: NodeList = field(default_factory=NodeList)
|
||||
validator: NodeList = field(default_factory=NodeList)
|
||||
installer: NodeList = field(default_factory=NodeList)
|
||||
|
||||
|
||||
def BuildAppElf(env, app):
|
||||
ext_apps_work_dir = env.subst("$EXT_APPS_WORK_DIR")
|
||||
app_work_dir = os.path.join(ext_apps_work_dir, app.appid)
|
||||
@@ -26,15 +38,7 @@ def BuildAppElf(env, app):
|
||||
|
||||
app_alias = f"fap_{app.appid}"
|
||||
|
||||
# Deprecation stub
|
||||
legacy_app_taget_name = f"{app_env['FIRMWARE_BUILD_CFG']}_{app.appid}"
|
||||
|
||||
def legacy_app_build_stub(**kw):
|
||||
raise UserError(
|
||||
f"Target name '{legacy_app_taget_name}' is deprecated, use '{app_alias}' instead"
|
||||
)
|
||||
|
||||
app_env.PhonyTarget(legacy_app_taget_name, Action(legacy_app_build_stub, None))
|
||||
app_artifacts = FlipperExternalAppInfo(app)
|
||||
|
||||
externally_built_files = []
|
||||
if app.fap_extbuild:
|
||||
@@ -115,20 +119,22 @@ def BuildAppElf(env, app):
|
||||
CPPPATH=env.Dir(app_work_dir),
|
||||
)
|
||||
|
||||
app_elf_raw = app_env.Program(
|
||||
app_artifacts.debug = app_env.Program(
|
||||
os.path.join(ext_apps_work_dir, f"{app.appid}_d"),
|
||||
app_sources,
|
||||
APP_ENTRY=app.entry_point,
|
||||
)
|
||||
|
||||
app_env.Clean(app_elf_raw, [*externally_built_files, app_env.Dir(app_work_dir)])
|
||||
app_env.Clean(
|
||||
app_artifacts.debug, [*externally_built_files, app_env.Dir(app_work_dir)]
|
||||
)
|
||||
|
||||
app_elf_dump = app_env.ObjDump(app_elf_raw)
|
||||
app_elf_dump = app_env.ObjDump(app_artifacts.debug)
|
||||
app_env.Alias(f"{app_alias}_list", app_elf_dump)
|
||||
|
||||
app_elf_augmented = app_env.EmbedAppMetadata(
|
||||
app_artifacts.compact = app_env.EmbedAppMetadata(
|
||||
os.path.join(ext_apps_work_dir, app.appid),
|
||||
app_elf_raw,
|
||||
app_artifacts.debug,
|
||||
APP=app,
|
||||
)
|
||||
|
||||
@@ -139,19 +145,21 @@ def BuildAppElf(env, app):
|
||||
}
|
||||
|
||||
app_env.Depends(
|
||||
app_elf_augmented,
|
||||
app_artifacts.compact,
|
||||
[app_env["SDK_DEFINITION"], app_env.Value(manifest_vals)],
|
||||
)
|
||||
if app.fap_icon:
|
||||
app_env.Depends(
|
||||
app_elf_augmented,
|
||||
app_artifacts.compact,
|
||||
app_env.File(f"{app._apppath}/{app.fap_icon}"),
|
||||
)
|
||||
|
||||
app_elf_import_validator = app_env.ValidateAppImports(app_elf_augmented)
|
||||
app_env.AlwaysBuild(app_elf_import_validator)
|
||||
app_env.Alias(app_alias, app_elf_import_validator)
|
||||
return (app_elf_augmented, app_elf_raw, app_elf_import_validator)
|
||||
app_artifacts.validator = app_env.ValidateAppImports(app_artifacts.compact)
|
||||
app_env.AlwaysBuild(app_artifacts.validator)
|
||||
app_env.Alias(app_alias, app_artifacts.validator)
|
||||
|
||||
env["EXT_APPS"][app.appid] = app_artifacts
|
||||
return app_artifacts
|
||||
|
||||
|
||||
def prepare_app_metadata(target, source, env):
|
||||
@@ -182,11 +190,17 @@ def validate_app_imports(target, source, env):
|
||||
app_syms.add(line.split()[0])
|
||||
unresolved_syms = app_syms - sdk_cache.get_valid_names()
|
||||
if unresolved_syms:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.LinkWarning,
|
||||
fg.brightyellow(f"{source[0].path}: app won't run. Unresolved symbols: ")
|
||||
+ fg.brightmagenta(f"{unresolved_syms}"),
|
||||
)
|
||||
warning_msg = fg.brightyellow(
|
||||
f"{source[0].path}: app won't run. Unresolved symbols: "
|
||||
) + fg.brightmagenta(f"{unresolved_syms}")
|
||||
disabled_api_syms = unresolved_syms.intersection(sdk_cache.get_disabled_names())
|
||||
if disabled_api_syms:
|
||||
warning_msg += (
|
||||
fg.brightyellow(" (in API, but disabled: ")
|
||||
+ fg.brightmagenta(f"{disabled_api_syms}")
|
||||
+ fg.brightyellow(")")
|
||||
)
|
||||
SCons.Warnings.warn(SCons.Warnings.LinkWarning, warning_msg),
|
||||
|
||||
|
||||
def GetExtAppFromPath(env, app_dir):
|
||||
@@ -208,26 +222,26 @@ def GetExtAppFromPath(env, app_dir):
|
||||
if not app:
|
||||
raise UserError(f"Failed to resolve application for given APPSRC={app_dir}")
|
||||
|
||||
app_elf = env["_extapps"]["compact"].get(app.appid, None)
|
||||
if not app_elf:
|
||||
app_artifacts = env["EXT_APPS"].get(app.appid, None)
|
||||
if not app_artifacts:
|
||||
raise UserError(
|
||||
f"Application {app.appid} is not configured for building as external"
|
||||
)
|
||||
|
||||
app_validator = env["_extapps"]["validators"].get(app.appid, None)
|
||||
|
||||
return (app, app_elf[0], app_validator[0])
|
||||
return app_artifacts
|
||||
|
||||
|
||||
def fap_dist_emitter(target, source, env):
|
||||
target_dir = target[0]
|
||||
|
||||
target = []
|
||||
for dist_entry in env["_extapps"]["dist"].values():
|
||||
target.append(target_dir.Dir(dist_entry[0]).File(dist_entry[1][0].name))
|
||||
|
||||
for compact_entry in env["_extapps"]["compact"].values():
|
||||
source.extend(compact_entry)
|
||||
for _, app_artifacts in env["EXT_APPS"].items():
|
||||
source.extend(app_artifacts.compact)
|
||||
target.append(
|
||||
target_dir.Dir(app_artifacts.app.fap_category).File(
|
||||
app_artifacts.compact[0].name
|
||||
)
|
||||
)
|
||||
|
||||
return (target, source)
|
||||
|
||||
@@ -244,10 +258,9 @@ def fap_dist_action(target, source, env):
|
||||
|
||||
def generate(env, **kw):
|
||||
env.SetDefault(
|
||||
EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR"),
|
||||
EXT_APPS_WORK_DIR="${FBT_FAP_DEBUG_ELF_ROOT}",
|
||||
APP_RUN_SCRIPT="${FBT_SCRIPT_DIR}/runfap.py",
|
||||
)
|
||||
|
||||
if not env["VERBOSE"]:
|
||||
env.SetDefault(
|
||||
FAPDISTCOMSTR="\tFAPDIST\t${TARGET}",
|
||||
@@ -256,6 +269,10 @@ def generate(env, **kw):
|
||||
APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}",
|
||||
)
|
||||
|
||||
env.SetDefault(
|
||||
EXT_APPS={}, # appid -> FlipperExternalAppInfo
|
||||
)
|
||||
|
||||
env.AddMethod(BuildAppElf)
|
||||
env.AddMethod(GetExtAppFromPath)
|
||||
env.Append(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
pyserial==3.5
|
||||
ansi==0.3.6
|
||||
black==22.6.0
|
||||
colorlog==6.7.0
|
||||
heatshrink2==0.11.0
|
||||
Pillow==9.1.1
|
||||
grpcio==1.47.0
|
||||
grpcio-tools==1.47.0
|
||||
protobuf==3.20.2
|
||||
protobuf==3.20.1
|
||||
pyserial==3.5
|
||||
python3-protobuf==2.5.0
|
||||
SCons==4.4.0
|
||||
|
||||
@@ -152,7 +152,7 @@ vars.AddVariables(
|
||||
PathVariable(
|
||||
"SVD_FILE",
|
||||
help="Path to SVD file",
|
||||
validator=PathVariable.PathIsFile,
|
||||
validator=PathVariable.PathAccept,
|
||||
default="",
|
||||
),
|
||||
PathVariable(
|
||||
|
||||
@@ -62,8 +62,8 @@ coreenv = VAR_ENV.Clone(
|
||||
ABSPATHGETTERFUNC=extract_abs_dir_path,
|
||||
# Setting up temp file parameters - to overcome command line length limits
|
||||
TEMPFILEARGESCFUNC=tempfile_arg_esc_func,
|
||||
FBT_SCRIPT_DIR=Dir("#/scripts"),
|
||||
ROOT_DIR=Dir("#"),
|
||||
FBT_SCRIPT_DIR="${ROOT_DIR}/scripts",
|
||||
)
|
||||
|
||||
# If DIST_SUFFIX is set in environment, is has precedence (set by CI)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from dataclasses import dataclass, field
|
||||
from SCons.Errors import UserError
|
||||
from SCons.Node import NodeList
|
||||
|
||||
|
||||
Import("ENV")
|
||||
@@ -7,14 +9,7 @@ from fbt.appmanifest import FlipperAppType
|
||||
|
||||
appenv = ENV["APPENV"] = ENV.Clone(
|
||||
tools=[
|
||||
(
|
||||
"fbt_extapps",
|
||||
{
|
||||
"EXT_APPS_WORK_DIR": ENV.subst(
|
||||
"${BUILD_DIR}/.extapps",
|
||||
)
|
||||
},
|
||||
),
|
||||
"fbt_extapps",
|
||||
"fbt_assets",
|
||||
"fbt_sdk",
|
||||
]
|
||||
@@ -60,22 +55,11 @@ appenv.AppendUnique(
|
||||
)
|
||||
|
||||
|
||||
extapps = appenv["_extapps"] = {
|
||||
"compact": {},
|
||||
"debug": {},
|
||||
"validators": {},
|
||||
"dist": {},
|
||||
"resources_dist": None,
|
||||
"sdk_tree": None,
|
||||
}
|
||||
|
||||
|
||||
def build_app_as_external(env, appdef):
|
||||
compact_elf, debug_elf, validator = env.BuildAppElf(appdef)
|
||||
extapps["compact"][appdef.appid] = compact_elf
|
||||
extapps["debug"][appdef.appid] = debug_elf
|
||||
extapps["validators"][appdef.appid] = validator
|
||||
extapps["dist"][appdef.appid] = (appdef.fap_category, compact_elf)
|
||||
@dataclass
|
||||
class FlipperExtAppBuildArtifacts:
|
||||
applications: dict = field(default_factory=dict)
|
||||
resources_dist: NodeList = field(default_factory=NodeList)
|
||||
sdk_tree: NodeList = field(default_factory=NodeList)
|
||||
|
||||
|
||||
apps_to_build_as_faps = [
|
||||
@@ -85,38 +69,39 @@ apps_to_build_as_faps = [
|
||||
if appenv["DEBUG_TOOLS"]:
|
||||
apps_to_build_as_faps.append(FlipperAppType.DEBUG)
|
||||
|
||||
for apptype in apps_to_build_as_faps:
|
||||
for app in appenv["APPBUILD"].get_apps_of_type(apptype, True):
|
||||
build_app_as_external(appenv, app)
|
||||
known_extapps = [
|
||||
app
|
||||
for apptype in apps_to_build_as_faps
|
||||
for app in appenv["APPBUILD"].get_apps_of_type(apptype, True)
|
||||
]
|
||||
|
||||
# Ugly access to global option
|
||||
if extra_app_list := GetOption("extra_ext_apps"):
|
||||
for extra_app in extra_app_list.split(","):
|
||||
build_app_as_external(appenv, appenv["APPMGR"].get(extra_app))
|
||||
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
|
||||
|
||||
for app in known_extapps:
|
||||
appenv.BuildAppElf(app)
|
||||
|
||||
|
||||
if appenv["FORCE"]:
|
||||
appenv.AlwaysBuild(extapps["compact"].values())
|
||||
appenv.AlwaysBuild(
|
||||
list(app_artifact.compact for app_artifact in appenv["EXT_APPS"].values())
|
||||
)
|
||||
|
||||
|
||||
# Deprecation stub
|
||||
def legacy_app_build_stub(**kw):
|
||||
raise UserError(f"Target name 'firmware_extapps' is deprecated, use 'faps' instead")
|
||||
Alias(
|
||||
"faps", list(app_artifact.validator for app_artifact in appenv["EXT_APPS"].values())
|
||||
)
|
||||
|
||||
|
||||
appenv.PhonyTarget("firmware_extapps", appenv.Action(legacy_app_build_stub, None))
|
||||
|
||||
|
||||
Alias("faps", extapps["compact"].values())
|
||||
Alias("faps", extapps["validators"].values())
|
||||
|
||||
extapps["resources_dist"] = appenv.FapDist(appenv.Dir("#/assets/resources/apps"), [])
|
||||
extapps = FlipperExtAppBuildArtifacts()
|
||||
extapps.applications = appenv["EXT_APPS"]
|
||||
extapps.resources_dist = appenv.FapDist(appenv.Dir("#/assets/resources/apps"), [])
|
||||
|
||||
if appsrc := appenv.subst("$APPSRC"):
|
||||
app_manifest, fap_file, app_validator = appenv.GetExtAppFromPath(appsrc)
|
||||
appenv.PhonyTarget(
|
||||
"launch_app",
|
||||
'${PYTHON3} "${APP_RUN_SCRIPT}" ${SOURCE} --fap_dst_dir "/ext/apps/${FAP_CATEGORY}"',
|
||||
'${PYTHON3} "${APP_RUN_SCRIPT}" "${SOURCE}" --fap_dst_dir "/ext/apps/${FAP_CATEGORY}"',
|
||||
source=fap_file,
|
||||
FAP_CATEGORY=app_manifest.fap_category,
|
||||
)
|
||||
@@ -131,12 +116,14 @@ sdk_source = appenv.SDKPrebuilder(
|
||||
(appenv["SDK_HEADERS"], appenv["FW_ASSETS_HEADERS"]),
|
||||
)
|
||||
# Extra deps on headers included in deeper levels
|
||||
# Available on second and subsequent builds
|
||||
Depends(sdk_source, appenv.ProcessSdkDepends(f"{sdk_origin_path}.d"))
|
||||
|
||||
appenv["SDK_DIR"] = appenv.Dir("${BUILD_DIR}/sdk")
|
||||
sdk_tree = extapps["sdk_tree"] = appenv.SDKTree(appenv["SDK_DIR"], sdk_origin_path)
|
||||
sdk_tree = appenv.SDKTree(appenv["SDK_DIR"], sdk_origin_path)
|
||||
# AlwaysBuild(sdk_tree)
|
||||
Alias("sdk_tree", sdk_tree)
|
||||
extapps.sdk_tree = sdk_tree
|
||||
|
||||
sdk_apicheck = appenv.SDKSymUpdater(appenv["SDK_DEFINITION"], sdk_origin_path)
|
||||
Precious(sdk_apicheck)
|
||||
|
||||
Reference in New Issue
Block a user