mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge branch 'fz-dev' into dev
This commit is contained in:
@@ -4,6 +4,7 @@ App(
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"gpio",
|
||||
"onewire",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"lfrfid",
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#define TAG "fap_loader_app"
|
||||
#define TAG "FapLoader"
|
||||
|
||||
struct FapLoader {
|
||||
FlipperApplication* app;
|
||||
@@ -22,6 +23,8 @@ struct FapLoader {
|
||||
Loading* loading;
|
||||
};
|
||||
|
||||
volatile bool fap_loader_debug_active = false;
|
||||
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
@@ -107,6 +110,14 @@ static bool fap_loader_run_selected_app(FapLoader* loader) {
|
||||
|
||||
FuriThread* thread = flipper_application_spawn(loader->app, NULL);
|
||||
|
||||
/* This flag is set by the debugger - to break on app start */
|
||||
if(fap_loader_debug_active) {
|
||||
FURI_LOG_W(TAG, "Triggering BP for debugger");
|
||||
/* After hitting this, you can set breakpoints in your .fap's code
|
||||
* Note that you have to toggle breakpoints that were set before */
|
||||
__asm volatile("bkpt 0");
|
||||
}
|
||||
|
||||
FuriString* app_name = furi_string_alloc();
|
||||
path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name);
|
||||
furi_thread_set_appid(thread, furi_string_get_cstr(app_name));
|
||||
|
||||
@@ -4,25 +4,20 @@
|
||||
#include <cli/cli.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
#include <one_wire/ibutton/ibutton_key.h>
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/ibutton/ibutton_protocols.h>
|
||||
#include <ibutton/ibutton_key.h>
|
||||
#include <ibutton/ibutton_worker.h>
|
||||
#include <ibutton/ibutton_protocols.h>
|
||||
|
||||
static void ibutton_cli(Cli* cli, FuriString* args, void* context);
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
// app cli function
|
||||
void ibutton_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(ibutton_cli);
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -257,56 +252,3 @@ void ibutton_cli(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
static void onewire_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("onewire search\r\n");
|
||||
};
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
printf("Search started\r\n");
|
||||
|
||||
onewire_host_start(onewire);
|
||||
furi_hal_power_enable_otg();
|
||||
|
||||
while(!done) {
|
||||
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
|
||||
printf("Search finished\r\n");
|
||||
onewire_host_reset_search(onewire);
|
||||
done = true;
|
||||
} else {
|
||||
printf("Found: ");
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
printf("%02X", address[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
furi_hal_power_disable_otg();
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
furi_string_free(cmd);
|
||||
onewire_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "search") == 0) {
|
||||
onewire_cli_search(cli);
|
||||
}
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/ibutton/ibutton_protocols.h>
|
||||
#include <ibutton/ibutton_worker.h>
|
||||
#include <ibutton/ibutton_protocols.h>
|
||||
|
||||
#include <rpc/rpc_app.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
14
applications/main/onewire/application.fam
Normal file
14
applications/main/onewire/application.fam
Normal file
@@ -0,0 +1,14 @@
|
||||
App(
|
||||
appid="onewire",
|
||||
name="1-Wire",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=["onewire_start"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="onewire_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="onewire_on_system_start",
|
||||
requires=["onewire"],
|
||||
order=60,
|
||||
)
|
||||
72
applications/main/onewire/onewire_cli.c
Normal file
72
applications/main/onewire/onewire_cli.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <cli/cli.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
void onewire_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void onewire_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("onewire search\r\n");
|
||||
};
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
printf("Search started\r\n");
|
||||
|
||||
onewire_host_start(onewire);
|
||||
furi_hal_power_enable_otg();
|
||||
|
||||
while(!done) {
|
||||
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
|
||||
printf("Search finished\r\n");
|
||||
onewire_host_reset_search(onewire);
|
||||
done = true;
|
||||
} else {
|
||||
printf("Found: ");
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
printf("%02X", address[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
furi_hal_power_disable_otg();
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
furi_string_free(cmd);
|
||||
onewire_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "search") == 0) {
|
||||
onewire_cli_search(cli);
|
||||
}
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ static void storage_path_change_to_real_storage(FuriString* path, StorageType re
|
||||
}
|
||||
}
|
||||
|
||||
FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
||||
static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
||||
StorageType type = storage_get_type_by_path(path);
|
||||
|
||||
if(storage_type_is_valid(type)) {
|
||||
|
||||
@@ -618,6 +618,8 @@ static const FS_Api fs_api = {
|
||||
};
|
||||
|
||||
void storage_ext_init(StorageData* storage) {
|
||||
fatfs_init();
|
||||
|
||||
SDData* sd_data = malloc(sizeof(SDData));
|
||||
sd_data->fs = &fatfs_object;
|
||||
sd_data->path = "0:/";
|
||||
|
||||
@@ -2,7 +2,6 @@ from dataclasses import dataclass
|
||||
from typing import Optional, Tuple, Dict, ClassVar
|
||||
import struct
|
||||
import posixpath
|
||||
import os
|
||||
import zlib
|
||||
|
||||
import gdb
|
||||
@@ -66,9 +65,9 @@ class AppState:
|
||||
def get_gdb_unload_command(self) -> str:
|
||||
return f"remove-symbol-file -a 0x{self.text_address:08x}"
|
||||
|
||||
def is_loaded_in_gdb(self, gdb_app) -> bool:
|
||||
# Avoid constructing full app wrapper for comparison
|
||||
return self.entry_address == int(gdb_app["state"]["entry"])
|
||||
@staticmethod
|
||||
def get_gdb_app_ep(app) -> int:
|
||||
return int(app["state"]["entry"])
|
||||
|
||||
@staticmethod
|
||||
def parse_debug_link_data(section_data: bytes) -> Tuple[str, int]:
|
||||
@@ -79,10 +78,10 @@ class AppState:
|
||||
crc32 = struct.unpack("<I", section_data[-4:])[0]
|
||||
return (elf_name, crc32)
|
||||
|
||||
@staticmethod
|
||||
def from_gdb(gdb_app: "AppState") -> "AppState":
|
||||
@classmethod
|
||||
def from_gdb(cls, gdb_app: "AppState") -> "AppState":
|
||||
state = AppState(str(gdb_app["manifest"]["name"].string()))
|
||||
state.entry_address = int(gdb_app["state"]["entry"])
|
||||
state.entry_address = cls.get_gdb_app_ep(gdb_app)
|
||||
|
||||
app_state = gdb_app["state"]
|
||||
if debug_link_size := int(app_state["debug_link_info"]["debug_link_size"]):
|
||||
@@ -123,59 +122,83 @@ class SetFapDebugElfRoot(gdb.Command):
|
||||
try:
|
||||
global helper
|
||||
print(f"Set '{arg}' as debug info lookup path for Flipper external apps")
|
||||
helper.attach_fw()
|
||||
helper.attach_to_fw()
|
||||
gdb.events.stop.connect(helper.handle_stop)
|
||||
gdb.events.exited.connect(helper.handle_exit)
|
||||
except gdb.error as e:
|
||||
print(f"Support for Flipper external apps debug is not available: {e}")
|
||||
|
||||
|
||||
SetFapDebugElfRoot()
|
||||
|
||||
|
||||
class FlipperAppDebugHelper:
|
||||
class FlipperAppStateHelper:
|
||||
def __init__(self):
|
||||
self.app_ptr = None
|
||||
self.app_type_ptr = None
|
||||
self.current_app: AppState = None
|
||||
self.app_list_ptr = None
|
||||
self.app_list_entry_type = None
|
||||
self._current_apps: list[AppState] = []
|
||||
|
||||
def attach_fw(self) -> None:
|
||||
self.app_ptr = gdb.lookup_global_symbol("last_loaded_app")
|
||||
self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer()
|
||||
self._check_app_state()
|
||||
def _walk_app_list(self, list_head):
|
||||
while list_head:
|
||||
if app := list_head["data"]:
|
||||
yield app.dereference()
|
||||
list_head = list_head["next"]
|
||||
|
||||
def _check_app_state(self) -> None:
|
||||
app_ptr_value = self.app_ptr.value()
|
||||
if not app_ptr_value and self.current_app:
|
||||
# There is an ELF loaded in GDB, but nothing is running on the device
|
||||
self._unload_debug_elf()
|
||||
elif app_ptr_value:
|
||||
# There is an app running on the device
|
||||
loaded_app = app_ptr_value.cast(self.app_type_ptr).dereference()
|
||||
|
||||
if self.current_app and not self.current_app.is_loaded_in_gdb(loaded_app):
|
||||
# Currently loaded ELF is not the one running on the device
|
||||
self._unload_debug_elf()
|
||||
|
||||
if not self.current_app:
|
||||
# Load ELF for the app running on the device
|
||||
self._load_debug_elf(loaded_app)
|
||||
|
||||
def _unload_debug_elf(self) -> None:
|
||||
def _exec_gdb_command(self, command: str) -> bool:
|
||||
try:
|
||||
gdb.execute(self.current_app.get_gdb_unload_command())
|
||||
gdb.execute(command)
|
||||
return True
|
||||
except gdb.error as e:
|
||||
print(f"Failed to unload debug ELF: {e} (might not be an error)")
|
||||
self.current_app = None
|
||||
print(f"Failed to execute GDB command '{command}': {e}")
|
||||
return False
|
||||
|
||||
def _load_debug_elf(self, app_object) -> None:
|
||||
self.current_app = AppState.from_gdb(app_object)
|
||||
def _sync_apps(self) -> None:
|
||||
self.set_debug_mode(True)
|
||||
if not (app_list := self.app_list_ptr.value()):
|
||||
print("Reset app loader state")
|
||||
for app in self._current_apps:
|
||||
self._exec_gdb_command(app.get_gdb_unload_command())
|
||||
self._current_apps = []
|
||||
return
|
||||
|
||||
if self.current_app.is_debug_available():
|
||||
gdb.execute(self.current_app.get_gdb_load_command())
|
||||
loaded_apps: dict[int, gdb.Value] = dict(
|
||||
(AppState.get_gdb_app_ep(app), app)
|
||||
for app in self._walk_app_list(app_list[0])
|
||||
)
|
||||
|
||||
for app in self._current_apps.copy():
|
||||
if app.entry_address not in loaded_apps:
|
||||
print(f"Application {app.name} is no longer loaded")
|
||||
if not self._exec_gdb_command(app.get_gdb_unload_command()):
|
||||
print(f"Failed to unload debug info for {app.name}")
|
||||
self._current_apps.remove(app)
|
||||
|
||||
for entry_point, app in loaded_apps.items():
|
||||
if entry_point not in set(app.entry_address for app in self._current_apps):
|
||||
new_app_state = AppState.from_gdb(app)
|
||||
print(f"New application loaded. Adding debug info")
|
||||
if self._exec_gdb_command(new_app_state.get_gdb_load_command()):
|
||||
self._current_apps.append(new_app_state)
|
||||
else:
|
||||
print(f"Failed to load debug info for {new_app_state}")
|
||||
|
||||
def attach_to_fw(self) -> None:
|
||||
print("Attaching to Flipper firmware")
|
||||
self.app_list_ptr = gdb.lookup_global_symbol(
|
||||
"flipper_application_loaded_app_list"
|
||||
)
|
||||
self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer()
|
||||
self.app_list_entry_type = gdb.lookup_type("struct FlipperApplicationList_s")
|
||||
|
||||
def handle_stop(self, event) -> None:
|
||||
self._check_app_state()
|
||||
self._sync_apps()
|
||||
|
||||
def handle_exit(self, event) -> None:
|
||||
self.set_debug_mode(False)
|
||||
|
||||
def set_debug_mode(self, mode: bool) -> None:
|
||||
gdb.execute(f"set variable fap_loader_debug_active = {int(mode)}")
|
||||
|
||||
|
||||
helper = FlipperAppDebugHelper()
|
||||
# Init additional 'fap-set-debug-elf-root' command and set up hooks
|
||||
SetFapDebugElfRoot()
|
||||
helper = FlipperAppStateHelper()
|
||||
print("Support for Flipper external apps debug is loaded")
|
||||
|
||||
@@ -32,6 +32,8 @@ Images and animated icons should follow the same [naming convention](../assets/R
|
||||
|
||||
With it, you can debug FAPs as if they were a part of the main firmware — inspect variables, set breakpoints, step through the code, etc.
|
||||
|
||||
If debugging session is active, firmware will trigger a breakpoint after loading a FAP it into memory, but before running any code from it. This allows you to set breakpoints in the FAP's code. Note that any breakpoints set before the FAP is loaded may need re-setting after the FAP is actually loaded, since before loading it debugger cannot know the exact address of the FAP's code.
|
||||
|
||||
### Setting up debugging environment
|
||||
|
||||
The debugging support script looks up debugging information in the latest firmware build directory (`build/latest`). That directory is symlinked by `fbt` to the latest firmware configuration (Debug or Release) build directory when you run `./fbt` for the chosen configuration. See [fbt docs](./fbt.md#nb) for details.
|
||||
|
||||
@@ -151,6 +151,10 @@ Header,+,lib/mlib/m-list.h,,
|
||||
Header,+,lib/mlib/m-rbtree.h,,
|
||||
Header,+,lib/mlib/m-tuple.h,,
|
||||
Header,+,lib/mlib/m-variant.h,,
|
||||
Header,+,lib/one_wire/maxim_crc.h,,
|
||||
Header,+,lib/one_wire/one_wire_host.h,,
|
||||
Header,+,lib/one_wire/one_wire_host_timing.h,,
|
||||
Header,+,lib/one_wire/one_wire_slave.h,,
|
||||
Header,+,lib/print/wrappers.h,,
|
||||
Header,+,lib/toolbox/args.h,,
|
||||
Header,+,lib/toolbox/crc32_calc.h,,
|
||||
@@ -1394,6 +1398,7 @@ Function,+,manchester_advance,_Bool,"ManchesterState, ManchesterEvent, Mancheste
|
||||
Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Bool, ManchesterEncoderResult*"
|
||||
Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState*
|
||||
Function,+,manchester_encoder_reset,void,ManchesterEncoderState*
|
||||
Function,+,maxim_crc8,uint8_t,"const uint8_t*, const uint8_t, const uint8_t"
|
||||
Function,-,mbedtls_des3_crypt_cbc,int,"mbedtls_des3_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*"
|
||||
Function,-,mbedtls_des3_crypt_ecb,int,"mbedtls_des3_context*, const unsigned char[8], unsigned char[8]"
|
||||
Function,-,mbedtls_des3_free,void,mbedtls_des3_context*
|
||||
@@ -1472,6 +1477,32 @@ Function,+,notification_message,void,"NotificationApp*, const NotificationSequen
|
||||
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||
Function,-,nrand48,long,unsigned short[3]
|
||||
Function,-,on_exit,int,"void (*)(int, void*), void*"
|
||||
Function,+,onewire_host_alloc,OneWireHost*,const GpioPin*
|
||||
Function,+,onewire_host_free,void,OneWireHost*
|
||||
Function,+,onewire_host_read,uint8_t,OneWireHost*
|
||||
Function,+,onewire_host_read_bit,_Bool,OneWireHost*
|
||||
Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t"
|
||||
Function,+,onewire_host_reset,_Bool,OneWireHost*
|
||||
Function,+,onewire_host_reset_search,void,OneWireHost*
|
||||
Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode"
|
||||
Function,+,onewire_host_skip,void,OneWireHost*
|
||||
Function,+,onewire_host_start,void,OneWireHost*
|
||||
Function,+,onewire_host_stop,void,OneWireHost*
|
||||
Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t"
|
||||
Function,+,onewire_host_write,void,"OneWireHost*, uint8_t"
|
||||
Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool"
|
||||
Function,+,onewire_host_write_bytes,void,"OneWireHost*, const uint8_t*, uint16_t"
|
||||
Function,+,onewire_slave_alloc,OneWireSlave*,const GpioPin*
|
||||
Function,+,onewire_slave_free,void,OneWireSlave*
|
||||
Function,+,onewire_slave_receive,_Bool,"OneWireSlave*, uint8_t*, size_t"
|
||||
Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave*
|
||||
Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t"
|
||||
Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool"
|
||||
Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*"
|
||||
Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*"
|
||||
Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*"
|
||||
Function,+,onewire_slave_start,void,OneWireSlave*
|
||||
Function,+,onewire_slave_stop,void,OneWireSlave*
|
||||
Function,-,open_memstream,FILE*,"char**, size_t*"
|
||||
Function,+,path_append,void,"FuriString*, const char*"
|
||||
Function,+,path_concat,void,"const char*, const char*, FuriString*"
|
||||
|
||||
|
@@ -3,8 +3,6 @@
|
||||
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <fatfs.h>
|
||||
|
||||
#define TAG "FuriHal"
|
||||
|
||||
void furi_hal_init_early() {
|
||||
@@ -74,10 +72,6 @@ void furi_hal_init() {
|
||||
#endif
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FatFS driver initialization
|
||||
fatfs_init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
}
|
||||
|
||||
void furi_hal_switch(void* address) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"usb_stm32",
|
||||
"appframe",
|
||||
"assets",
|
||||
"one_wire",
|
||||
"misc",
|
||||
"flipper_application",
|
||||
"flipperformat",
|
||||
@@ -45,11 +46,11 @@
|
||||
"furi_hal_subghz_configs.h"
|
||||
],
|
||||
"excluded_modules": [
|
||||
"one_wire",
|
||||
"nfc",
|
||||
"lfrfid",
|
||||
"subghz",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"st25rfal002"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,9 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
|
||||
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
||||
Header,+,lib/flipper_format/flipper_format.h,,
|
||||
Header,+,lib/flipper_format/flipper_format_i.h,,
|
||||
Header,+,lib/ibutton/ibutton_key.h,,
|
||||
Header,+,lib/ibutton/ibutton_protocols.h,,
|
||||
Header,+,lib/ibutton/ibutton_worker.h,,
|
||||
Header,+,lib/infrared/encoder_decoder/infrared.h,,
|
||||
Header,+,lib/infrared/worker/infrared_transmit.h,,
|
||||
Header,+,lib/infrared/worker/infrared_worker.h,,
|
||||
@@ -170,9 +173,6 @@ Header,+,lib/mlib/m-rbtree.h,,
|
||||
Header,+,lib/mlib/m-tuple.h,,
|
||||
Header,+,lib/mlib/m-variant.h,,
|
||||
Header,+,lib/nfc/nfc_device.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_key.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_protocols.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_worker.h,,
|
||||
Header,+,lib/one_wire/maxim_crc.h,,
|
||||
Header,+,lib/one_wire/one_wire_host.h,,
|
||||
Header,+,lib/one_wire/one_wire_host_timing.h,,
|
||||
|
||||
|
@@ -1,21 +1,3 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file fatfs.c
|
||||
* @brief Code for fatfs applications
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "fatfs.h"
|
||||
|
||||
/** logical drive path */
|
||||
@@ -35,5 +17,3 @@ void fatfs_init(void) {
|
||||
DWORD get_fattime(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file fatfs.h
|
||||
* @brief Header for fatfs applications
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fatfs/ff.h"
|
||||
@@ -34,6 +16,4 @@ void fatfs_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
#endif
|
||||
@@ -1,21 +1,3 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file user_diskio.c
|
||||
* @brief This file includes a diskio driver skeleton to be completed by the user.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "user_diskio.h"
|
||||
#include <furi_hal.h>
|
||||
#include "sector_cache.h"
|
||||
@@ -287,5 +269,3 @@ static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file user_diskio.h
|
||||
* @brief This file contains the common defines and functions prototypes for
|
||||
* the user_diskio driver.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <fatfs.h>
|
||||
|
||||
#define TAG "FuriHal"
|
||||
|
||||
void furi_hal_init_early() {
|
||||
@@ -80,10 +78,6 @@ void furi_hal_init() {
|
||||
furi_hal_nfc_init();
|
||||
furi_hal_rfid_init();
|
||||
#endif
|
||||
|
||||
// FatFS driver initialization
|
||||
fatfs_init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
}
|
||||
|
||||
void furi_hal_switch(void* address) {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"appframe",
|
||||
"assets",
|
||||
"one_wire",
|
||||
"ibutton",
|
||||
"misc",
|
||||
"mbedtls",
|
||||
"lfrfid",
|
||||
@@ -42,4 +43,4 @@
|
||||
"flipperformat",
|
||||
"toolbox"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ libs = env.BuildModules(
|
||||
"fatfs",
|
||||
"flipper_format",
|
||||
"one_wire",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"littlefs",
|
||||
"mbedtls",
|
||||
|
||||
@@ -830,8 +830,9 @@ void elf_file_init_debug_info(ELFFile* elf, ELFDebugInfo* debug_info) {
|
||||
|
||||
const void* data_ptr = itref->value.data;
|
||||
if(data_ptr) {
|
||||
debug_info->mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr;
|
||||
debug_info->mmap_entries[mmap_entry_idx].name = itref->key;
|
||||
ELFMemoryMapEntry* entry = &debug_info->mmap_entries[mmap_entry_idx];
|
||||
entry->address = (uint32_t)data_ptr;
|
||||
entry->name = itref->key;
|
||||
mmap_entry_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <notification/notification_messages.h>
|
||||
#include "application_assets.h"
|
||||
|
||||
#define TAG "fapp"
|
||||
#include <m-list.h>
|
||||
|
||||
#define TAG "Fap"
|
||||
|
||||
struct FlipperApplication {
|
||||
ELFDebugInfo state;
|
||||
@@ -13,8 +15,39 @@ struct FlipperApplication {
|
||||
void* ep_thread_args;
|
||||
};
|
||||
|
||||
/* For debugger access to app state */
|
||||
FlipperApplication* last_loaded_app = NULL;
|
||||
/********************** Debugger access to loader state **********************/
|
||||
|
||||
LIST_DEF(FlipperApplicationList, const FlipperApplication*, M_POD_OPLIST);
|
||||
|
||||
FlipperApplicationList_t flipper_application_loaded_app_list = {0};
|
||||
static bool flipper_application_loaded_app_list_initialized = false;
|
||||
|
||||
static void flipper_application_list_add_app(const FlipperApplication* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(!flipper_application_loaded_app_list_initialized) {
|
||||
FlipperApplicationList_init(flipper_application_loaded_app_list);
|
||||
flipper_application_loaded_app_list_initialized = true;
|
||||
}
|
||||
FlipperApplicationList_push_back(flipper_application_loaded_app_list, app);
|
||||
}
|
||||
|
||||
static void flipper_application_list_remove_app(const FlipperApplication* app) {
|
||||
furi_assert(flipper_application_loaded_app_list_initialized);
|
||||
furi_assert(app);
|
||||
|
||||
FlipperApplicationList_it_t it;
|
||||
for(FlipperApplicationList_it(it, flipper_application_loaded_app_list);
|
||||
!FlipperApplicationList_end_p(it);
|
||||
FlipperApplicationList_next(it)) {
|
||||
if(*FlipperApplicationList_ref(it) == app) {
|
||||
FlipperApplicationList_remove(flipper_application_loaded_app_list, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
FlipperApplication*
|
||||
flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) {
|
||||
@@ -37,8 +70,8 @@ void flipper_application_free(FlipperApplication* app) {
|
||||
furi_thread_free(app->thread);
|
||||
}
|
||||
|
||||
if(!flipper_application_is_plugin(app)) {
|
||||
last_loaded_app = NULL;
|
||||
if(app->state.entry) {
|
||||
flipper_application_list_remove_app(app);
|
||||
}
|
||||
|
||||
elf_file_clear_debug_info(&app->state);
|
||||
@@ -153,14 +186,12 @@ const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplic
|
||||
}
|
||||
|
||||
FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) {
|
||||
if(!flipper_application_is_plugin(app)) {
|
||||
last_loaded_app = app;
|
||||
}
|
||||
ELFFileLoadStatus status = elf_file_load_sections(app->elf);
|
||||
|
||||
switch(status) {
|
||||
case ELFFileLoadStatusSuccess:
|
||||
elf_file_init_debug_info(app->elf, &app->state);
|
||||
flipper_application_list_add_app(app);
|
||||
return FlipperApplicationLoadStatusSuccess;
|
||||
case ELFFileLoadStatusNoFreeMemory:
|
||||
return FlipperApplicationLoadStatusNoFreeMemory;
|
||||
|
||||
24
lib/ibutton/SConscript
Normal file
24
lib/ibutton/SConscript
Normal file
@@ -0,0 +1,24 @@
|
||||
Import("env")
|
||||
|
||||
env.Append(
|
||||
LINT_SOURCES=[
|
||||
Dir("."),
|
||||
],
|
||||
CPPPATH=[
|
||||
"#/lib/ibutton",
|
||||
],
|
||||
SDK_HEADERS=[
|
||||
File("ibutton_key.h"),
|
||||
File("ibutton_worker.h"),
|
||||
File("ibutton_protocols.h"),
|
||||
],
|
||||
)
|
||||
|
||||
libenv = env.Clone(FW_LIB_NAME="ibutton")
|
||||
libenv.ApplyLibFlags()
|
||||
|
||||
sources = libenv.GlobRecursive("*.c*")
|
||||
|
||||
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
|
||||
libenv.Install("${LIB_DIST_DIR}", lib)
|
||||
Return("lib")
|
||||
@@ -11,9 +11,6 @@ env.Append(
|
||||
File("one_wire_host_timing.h"),
|
||||
File("one_wire_host.h"),
|
||||
File("one_wire_slave.h"),
|
||||
File("ibutton/ibutton_key.h"),
|
||||
File("ibutton/ibutton_worker.h"),
|
||||
File("ibutton/ibutton_protocols.h"),
|
||||
File("maxim_crc.h"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -455,7 +455,7 @@ uint32_t subghz_setting_get_frequency(SubGhzSetting* instance, size_t idx) {
|
||||
|
||||
uint32_t subghz_setting_get_hopper_frequency(SubGhzSetting* instance, size_t idx) {
|
||||
furi_assert(instance);
|
||||
if(idx < FrequencyList_size(instance->frequencies)) {
|
||||
if(idx < FrequencyList_size(instance->hopper_frequencies)) {
|
||||
return *FrequencyList_get(instance->hopper_frequencies, idx);
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
import os
|
||||
import typing
|
||||
from enum import Enum
|
||||
|
||||
from flipper.utils.programmer import Programmer
|
||||
from flipper.utils.openocd import OpenOCD
|
||||
@@ -8,6 +9,14 @@ from flipper.utils.stm32wb55 import STM32WB55
|
||||
from flipper.assets.obdata import OptionBytesData
|
||||
|
||||
|
||||
class OpenOCDProgrammerResult(Enum):
|
||||
Success = 0
|
||||
ErrorGeneric = 1
|
||||
ErrorAlignment = 2
|
||||
ErrorAlreadyWritten = 3
|
||||
ErrorValidation = 4
|
||||
|
||||
|
||||
class OpenOCDProgrammer(Programmer):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -199,18 +208,18 @@ class OpenOCDProgrammer(Programmer):
|
||||
|
||||
return True
|
||||
|
||||
def otp_write(self, address: int, file_path: str) -> bool:
|
||||
def otp_write(self, address: int, file_path: str) -> OpenOCDProgrammerResult:
|
||||
# Open file, check that it aligned to 8 bytes
|
||||
with open(file_path, "rb") as f:
|
||||
data = f.read()
|
||||
if len(data) % 8 != 0:
|
||||
self.logger.error(f"File {file_path} is not aligned to 8 bytes")
|
||||
return False
|
||||
return OpenOCDProgrammerResult.ErrorAlignment
|
||||
|
||||
# Check that address is aligned to 8 bytes
|
||||
if address % 8 != 0:
|
||||
self.logger.error(f"Address {address} is not aligned to 8 bytes")
|
||||
return False
|
||||
return OpenOCDProgrammerResult.ErrorAlignment
|
||||
|
||||
# Get size of data
|
||||
data_size = len(data)
|
||||
@@ -218,7 +227,7 @@ class OpenOCDProgrammer(Programmer):
|
||||
# Check that data size is aligned to 8 bytes
|
||||
if data_size % 8 != 0:
|
||||
self.logger.error(f"Data size {data_size} is not aligned to 8 bytes")
|
||||
return False
|
||||
return OpenOCDProgrammerResult.ErrorAlignment
|
||||
|
||||
self.logger.debug(f"Writing {data_size} bytes to OTP at {address:08X}")
|
||||
self.logger.debug(f"Data: {data.hex().upper()}")
|
||||
@@ -241,14 +250,14 @@ class OpenOCDProgrammer(Programmer):
|
||||
self.logger.error(
|
||||
f"OTP memory at {address + i:08X} is not empty: {device_word:08X}"
|
||||
)
|
||||
raise Exception("OTP memory is not empty")
|
||||
return OpenOCDProgrammerResult.ErrorAlreadyWritten
|
||||
|
||||
if device_word != file_word:
|
||||
already_written = False
|
||||
|
||||
if already_written:
|
||||
self.logger.info(f"OTP memory is already written with the given data")
|
||||
return True
|
||||
return OpenOCDProgrammerResult.Success
|
||||
|
||||
self.reset(self.RunMode.Stop)
|
||||
stm32.clear_flash_errors(oocd)
|
||||
@@ -278,4 +287,8 @@ class OpenOCDProgrammer(Programmer):
|
||||
stm32.reset(oocd, stm32.RunMode.Run)
|
||||
oocd.stop()
|
||||
|
||||
return validation_result
|
||||
return (
|
||||
OpenOCDProgrammerResult.Success
|
||||
if validation_result
|
||||
else OpenOCDProgrammerResult.ErrorValidation
|
||||
)
|
||||
|
||||
@@ -34,8 +34,16 @@ OTP_DISPLAYS = {
|
||||
}
|
||||
|
||||
from flipper.app import App
|
||||
from flipper.cube import CubeProgrammer
|
||||
from flipper.utils.programmer_openocd import OpenOCDProgrammer
|
||||
from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult
|
||||
|
||||
|
||||
class OTPException(Exception):
|
||||
def __init__(self, message: str, result: OpenOCDProgrammerResult):
|
||||
self.message = message
|
||||
self.result = result
|
||||
|
||||
def get_exit_code(self) -> int:
|
||||
return int(self.result.value)
|
||||
|
||||
|
||||
class Main(App):
|
||||
@@ -183,13 +191,14 @@ class Main(App):
|
||||
self.args.serial,
|
||||
)
|
||||
|
||||
if not openocd.otp_write(0x1FFF7000, filename):
|
||||
raise Exception("Failed to flash OTP")
|
||||
programmer_result = openocd.otp_write(0x1FFF7000, filename)
|
||||
if programmer_result != OpenOCDProgrammerResult.Success:
|
||||
raise OTPException("Failed to flash OTP", programmer_result)
|
||||
|
||||
self.logger.info(f"Flashed Successfully")
|
||||
except Exception as e:
|
||||
except OTPException as e:
|
||||
self.logger.exception(e)
|
||||
return 1
|
||||
return e.get_exit_code()
|
||||
finally:
|
||||
os.remove(filename)
|
||||
|
||||
@@ -215,13 +224,14 @@ class Main(App):
|
||||
self.args.serial,
|
||||
)
|
||||
|
||||
if not openocd.otp_write(0x1FFF7010, filename):
|
||||
raise Exception("Failed to flash OTP")
|
||||
programmer_result = openocd.otp_write(0x1FFF7010, filename)
|
||||
if programmer_result != OpenOCDProgrammerResult.Success:
|
||||
raise OTPException("Failed to flash OTP", programmer_result)
|
||||
|
||||
self.logger.info(f"Flashed Successfully")
|
||||
except Exception as e:
|
||||
except OTPException as e:
|
||||
self.logger.exception(e)
|
||||
return 1
|
||||
return e.get_exit_code()
|
||||
finally:
|
||||
os.remove(filename)
|
||||
|
||||
@@ -249,13 +259,14 @@ class Main(App):
|
||||
self.args.serial,
|
||||
)
|
||||
|
||||
if not openocd.otp_write(0x1FFF7000, filename):
|
||||
raise Exception("Failed to flash OTP")
|
||||
programmer_result = openocd.otp_write(0x1FFF7000, filename)
|
||||
if programmer_result != OpenOCDProgrammerResult.Success:
|
||||
raise OTPException("Failed to flash OTP", programmer_result)
|
||||
|
||||
self.logger.info(f"Flashed Successfully")
|
||||
except Exception as e:
|
||||
except OTPException as e:
|
||||
self.logger.exception(e)
|
||||
return 1
|
||||
return e.get_exit_code()
|
||||
finally:
|
||||
os.remove(filename)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user