[FL-3847, FL-3513] Thread Signals (#3730)

* Add signal API
* Add signal support to loader
* Add signal support to ViewDispatcher
* Remove extra signal definitions
* Fix typos
  Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
* scripts: runfap: close current app pre-launch
* loader: enable backlight when starting an app
* scripts: removed distfap.py
* Do not expose signal API via ViewDispatcher
* scripts: runfap: iterative retry to launch
* Add a loader signal subcommand
* Furi, Gui: move signal handling from View Dispatcher to Event Loop

Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Georgii Surkov 2024-06-21 23:44:36 +03:00 committed by GitHub
parent a0036d10fc
commit 4cf98867a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 291 additions and 109 deletions

View file

@ -69,11 +69,6 @@ void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) {
view_dispatcher); view_dispatcher);
} }
void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) {
furi_check(view_dispatcher);
view_dispatcher->event_context = context;
}
void view_dispatcher_set_navigation_event_callback( void view_dispatcher_set_navigation_event_callback(
ViewDispatcher* view_dispatcher, ViewDispatcher* view_dispatcher,
ViewDispatcherNavigationEventCallback callback) { ViewDispatcherNavigationEventCallback callback) {
@ -97,6 +92,11 @@ void view_dispatcher_set_tick_event_callback(
view_dispatcher->tick_period = tick_period; view_dispatcher->tick_period = tick_period;
} }
void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) {
furi_check(view_dispatcher);
view_dispatcher->event_context = context;
}
FuriEventLoop* view_dispatcher_get_event_loop(ViewDispatcher* view_dispatcher) { FuriEventLoop* view_dispatcher_get_event_loop(ViewDispatcher* view_dispatcher) {
furi_check(view_dispatcher); furi_check(view_dispatcher);
furi_check(view_dispatcher->event_loop); furi_check(view_dispatcher->event_loop);

View file

@ -107,7 +107,7 @@ void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher,
* in view_dispatcher_run. * in view_dispatcher_run.
* *
* You can add your objects into event_loop instance, but don't run the loop on * You can add your objects into event_loop instance, but don't run the loop on
* your side it will cause issues with input processing on dispatcher stop. * your side as it will cause issues with input processing on dispatcher stop.
* *
* @param view_dispatcher ViewDispatcher instance * @param view_dispatcher ViewDispatcher instance
* *

View file

@ -11,7 +11,7 @@
#include "view_i.h" #include "view_i.h"
#include "gui_i.h" #include "gui_i.h"
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) // NOLINT
struct ViewDispatcher { struct ViewDispatcher {
FuriEventLoop* event_loop; FuriEventLoop* event_loop;

View file

@ -244,6 +244,43 @@ FuriPubSub* loader_get_pubsub(Loader* loader) {
return loader->pubsub; return loader->pubsub;
} }
bool loader_signal(Loader* loader, uint32_t signal, void* arg) {
furi_check(loader);
LoaderMessageBoolResult result;
LoaderMessage message = {
.type = LoaderMessageTypeSignal,
.api_lock = api_lock_alloc_locked(),
.signal.signal = signal,
.signal.arg = arg,
.bool_value = &result,
};
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
return result.value;
}
bool loader_get_application_name(Loader* loader, FuriString* name) {
furi_check(loader);
LoaderMessageBoolResult result;
LoaderMessage message = {
.type = LoaderMessageTypeGetApplicationName,
.api_lock = api_lock_alloc_locked(),
.application_name = name,
.bool_value = &result,
};
furi_message_queue_put(loader->queue, &message, FuriWaitForever);
api_lock_wait_unlock_and_free(message.api_lock);
return result.value;
}
// callbacks // callbacks
static void loader_menu_closed_callback(void* context) { static void loader_menu_closed_callback(void* context) {
@ -654,6 +691,28 @@ static void loader_do_app_closed(Loader* loader) {
furi_pubsub_publish(loader->pubsub, &event); furi_pubsub_publish(loader->pubsub, &event);
} }
static bool loader_is_application_running(Loader* loader) {
FuriThread* app_thread = loader->app.thread;
return app_thread && (app_thread != (FuriThread*)LOADER_MAGIC_THREAD_VALUE);
}
static bool loader_do_signal(Loader* loader, uint32_t signal, void* arg) {
if(loader_is_application_running(loader)) {
return furi_thread_signal(loader->app.thread, signal, arg);
}
return false;
}
static bool loader_do_get_application_name(Loader* loader, FuriString* name) {
if(loader_is_application_running(loader)) {
furi_string_set(name, furi_thread_get_name(loader->app.thread));
return true;
}
return false;
}
// app // app
int32_t loader_srv(void* p) { int32_t loader_srv(void* p) {
@ -714,9 +773,19 @@ int32_t loader_srv(void* p) {
case LoaderMessageTypeApplicationsClosed: case LoaderMessageTypeApplicationsClosed:
loader_do_applications_closed(loader); loader_do_applications_closed(loader);
break; break;
case LoaderMessageTypeSignal:
message.bool_value->value =
loader_do_signal(loader, message.signal.signal, message.signal.arg);
api_lock_unlock(message.api_lock);
break;
case LoaderMessageTypeGetApplicationName:
message.bool_value->value =
loader_do_get_application_name(loader, message.application_name);
api_lock_unlock(message.api_lock);
break;
} }
} }
} }
return 0; return 0;
} }

View file

@ -88,6 +88,26 @@ void loader_show_menu(Loader* instance);
*/ */
FuriPubSub* loader_get_pubsub(Loader* instance); FuriPubSub* loader_get_pubsub(Loader* instance);
/**
* @brief Send a signal to the currently running application
*
* @param[in] instance pointer to the loader instance
* @param[in] signal signal value to be sent
* @param[in,out] arg optional argument (can be of any value, including NULL)
*
* @return true if the signal was handled by the application, false otherwise
*/
bool loader_signal(Loader* instance, uint32_t signal, void* arg);
/**
* @brief Get the name of the currently running application
*
* @param[in] instance pointer to the loader instance
* @param[in,out] name pointer to the string to contain the name (must be allocated)
* @return true if it was possible to get an application name, false otherwise
*/
bool loader_get_application_name(Loader* instance, FuriString* name);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -1,8 +1,10 @@
#include "loader.h"
#include <furi.h> #include <furi.h>
#include <cli/cli.h> #include <cli/cli.h>
#include <applications.h> #include <applications.h>
#include <lib/toolbox/args.h> #include <lib/toolbox/args.h>
#include "loader.h" #include <notification/notification_messages.h>
static void loader_cli_print_usage(void) { static void loader_cli_print_usage(void) {
printf("Usage:\r\n"); printf("Usage:\r\n");
@ -11,6 +13,8 @@ static void loader_cli_print_usage(void) {
printf("\tlist\t - List available applications\r\n"); printf("\tlist\t - List available applications\r\n");
printf("\topen <Application Name:string>\t - Open application by name\r\n"); printf("\topen <Application Name:string>\t - Open application by name\r\n");
printf("\tinfo\t - Show loader state\r\n"); printf("\tinfo\t - Show loader state\r\n");
printf("\tclose\t - Close the current application\r\n");
printf("\tsignal <signal:number> [arg:hex]\t - Send a signal with an optional argument\r\n");
} }
static void loader_cli_list(void) { static void loader_cli_list(void) {
@ -25,12 +29,15 @@ static void loader_cli_list(void) {
} }
static void loader_cli_info(Loader* loader) { static void loader_cli_info(Loader* loader) {
if(!loader_is_locked(loader)) { FuriString* app_name = furi_string_alloc();
if(!loader_get_application_name(loader, app_name)) {
printf("No application is running\r\n"); printf("No application is running\r\n");
} else { } else {
// TODO FL-3513: print application name ??? printf("Application \"%s\" is running\r\n", furi_string_get_cstr(app_name));
printf("Application is running\r\n");
} }
furi_string_free(app_name);
} }
static void loader_cli_open(FuriString* args, Loader* loader) { static void loader_cli_open(FuriString* args, Loader* loader) {
@ -53,6 +60,12 @@ static void loader_cli_open(FuriString* args, Loader* loader) {
FuriString* error_message = furi_string_alloc(); FuriString* error_message = furi_string_alloc();
if(loader_start(loader, app_name_str, args_str, error_message) != LoaderStatusOk) { if(loader_start(loader, app_name_str, args_str, error_message) != LoaderStatusOk) {
printf("%s\r\n", furi_string_get_cstr(error_message)); printf("%s\r\n", furi_string_get_cstr(error_message));
} else {
#ifdef SRV_NOTIFICATION
NotificationApp* notification_srv = furi_record_open(RECORD_NOTIFICATION);
notification_message(notification_srv, &sequence_display_backlight_on);
furi_record_close(RECORD_NOTIFICATION);
#endif
} }
furi_string_free(error_message); furi_string_free(error_message);
} while(false); } while(false);
@ -60,6 +73,38 @@ static void loader_cli_open(FuriString* args, Loader* loader) {
furi_string_free(app_name); furi_string_free(app_name);
} }
static void loader_cli_close(Loader* loader) {
FuriString* app_name = furi_string_alloc();
if(!loader_get_application_name(loader, app_name)) {
printf("No application is running\r\n");
} else if(!loader_signal(loader, FuriSignalExit, NULL)) {
printf("Application \"%s\" has to be closed manually\r\n", furi_string_get_cstr(app_name));
} else {
printf("Application \"%s\" was closed\r\n", furi_string_get_cstr(app_name));
}
furi_string_free(app_name);
}
static void loader_cli_signal(FuriString* args, Loader* loader) {
uint32_t signal;
void* arg = NULL;
if(!sscanf(furi_string_get_cstr(args), "%lu %p", &signal, &arg)) {
printf("Signal must be a decimal number\r\n");
} else if(!loader_is_locked(loader)) {
printf("No application is running\r\n");
} else {
const bool is_handled = loader_signal(loader, signal, arg);
printf(
"Signal %lu with argument 0x%p was %s\r\n",
signal,
arg,
is_handled ? "handled" : "ignored");
}
}
static void loader_cli(Cli* cli, FuriString* args, void* context) { static void loader_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli); UNUSED(cli);
UNUSED(context); UNUSED(context);
@ -68,29 +113,21 @@ static void loader_cli(Cli* cli, FuriString* args, void* context) {
FuriString* cmd; FuriString* cmd;
cmd = furi_string_alloc(); cmd = furi_string_alloc();
do { if(!args_read_string_and_trim(args, cmd)) {
if(!args_read_string_and_trim(args, cmd)) {
loader_cli_print_usage();
break;
}
if(furi_string_cmp_str(cmd, "list") == 0) {
loader_cli_list();
break;
}
if(furi_string_cmp_str(cmd, "open") == 0) {
loader_cli_open(args, loader);
break;
}
if(furi_string_cmp_str(cmd, "info") == 0) {
loader_cli_info(loader);
break;
}
loader_cli_print_usage(); loader_cli_print_usage();
} while(false); } else if(furi_string_equal(cmd, "list")) {
loader_cli_list();
} else if(furi_string_equal(cmd, "open")) {
loader_cli_open(args, loader);
} else if(furi_string_equal(cmd, "info")) {
loader_cli_info(loader);
} else if(furi_string_equal(cmd, "close")) {
loader_cli_close(loader);
} else if(furi_string_equal(cmd, "signal")) {
loader_cli_signal(args, loader);
} else {
loader_cli_print_usage();
}
furi_string_free(cmd); furi_string_free(cmd);
furi_record_close(RECORD_LOADER); furi_record_close(RECORD_LOADER);
@ -104,4 +141,4 @@ void loader_on_system_start(void) {
#else #else
UNUSED(loader_cli); UNUSED(loader_cli);
#endif #endif
} }

View file

@ -31,6 +31,8 @@ typedef enum {
LoaderMessageTypeUnlock, LoaderMessageTypeUnlock,
LoaderMessageTypeIsLocked, LoaderMessageTypeIsLocked,
LoaderMessageTypeStartByNameDetachedWithGuiError, LoaderMessageTypeStartByNameDetachedWithGuiError,
LoaderMessageTypeSignal,
LoaderMessageTypeGetApplicationName,
} LoaderMessageType; } LoaderMessageType;
typedef struct { typedef struct {
@ -39,6 +41,11 @@ typedef struct {
FuriString* error_message; FuriString* error_message;
} LoaderMessageStartByName; } LoaderMessageStartByName;
typedef struct {
uint32_t signal;
void* arg;
} LoaderMessageSignal;
typedef enum { typedef enum {
LoaderStatusErrorUnknown, LoaderStatusErrorUnknown,
LoaderStatusErrorInvalidFile, LoaderStatusErrorInvalidFile,
@ -65,6 +72,8 @@ typedef struct {
union { union {
LoaderMessageStartByName start; LoaderMessageStartByName start;
LoaderMessageSignal signal;
FuriString* application_name;
}; };
union { union {

View file

@ -40,6 +40,12 @@ typedef enum {
FuriStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization. FuriStatusReserved = 0x7FFFFFFF ///< Prevents enum down-size compiler optimization.
} FuriStatus; } FuriStatus;
typedef enum {
FuriSignalExit, /**< Request (graceful) exit. */
// Other standard signals may be added in the future
FuriSignalCustom = 100, /**< Custom signal values start from here. */
} FuriSignal;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -149,6 +149,9 @@ void furi_event_loop_run(FuriEventLoop* instance) {
furi_check(instance); furi_check(instance);
furi_check(instance->thread_id == furi_thread_get_current_id()); furi_check(instance->thread_id == furi_thread_get_current_id());
furi_thread_set_signal_callback(
instance->thread_id, furi_event_loop_signal_callback, instance);
uint32_t timeout = instance->tick_callback ? instance->tick_interval : FuriWaitForever; uint32_t timeout = instance->tick_callback ? instance->tick_interval : FuriWaitForever;
while(true) { while(true) {
@ -194,11 +197,12 @@ void furi_event_loop_run(FuriEventLoop* instance) {
} }
instance->state = FuriEventLoopStateIdle; instance->state = FuriEventLoopStateIdle;
} }
furi_thread_set_signal_callback(instance->thread_id, NULL, NULL);
} }
void furi_event_loop_stop(FuriEventLoop* instance) { void furi_event_loop_stop(FuriEventLoop* instance) {
furi_check(instance); furi_check(instance);
furi_check(instance->thread_id == furi_thread_get_current_id());
xTaskNotifyIndexed( xTaskNotifyIndexed(
instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagStop, eSetBits); instance->thread_id, FURI_EVENT_LOOP_FLAG_NOTIFY_INDEX, FuriEventLoopFlagStop, eSetBits);
@ -366,4 +370,19 @@ void furi_event_loop_link_notify(FuriEventLoopLink* instance, FuriEventLoopEvent
} }
FURI_CRITICAL_EXIT(); FURI_CRITICAL_EXIT();
} }
bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context) {
furi_assert(context);
FuriEventLoop* instance = context;
UNUSED(arg);
switch(signal) {
case FuriSignalExit:
furi_event_loop_stop(instance);
return true;
// Room for possible other standard signal handlers
default:
return false;
}
}

View file

@ -28,6 +28,8 @@ typedef struct {
const FuriEventLoopContractGetLevel get_level; const FuriEventLoopContractGetLevel get_level;
} FuriEventLoopContract; } FuriEventLoopContract;
bool furi_event_loop_signal_callback(uint32_t signal, void* arg, void* context);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -42,6 +42,9 @@ struct FuriThread {
FuriThreadStateCallback state_callback; FuriThreadStateCallback state_callback;
void* state_context; void* state_context;
FuriThreadSignalCallback signal_callback;
void* signal_context;
char* name; char* name;
char* appid; char* appid;
@ -304,6 +307,29 @@ FuriThreadState furi_thread_get_state(FuriThread* thread) {
return thread->state; return thread->state;
} }
void furi_thread_set_signal_callback(
FuriThread* thread,
FuriThreadSignalCallback callback,
void* context) {
furi_check(thread);
furi_check(thread->state == FuriThreadStateStopped || thread == furi_thread_get_current());
thread->signal_callback = callback;
thread->signal_context = context;
}
bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg) {
furi_check(thread);
bool is_consumed = false;
if(thread->signal_callback) {
is_consumed = thread->signal_callback(signal, arg, thread->signal_context);
}
return is_consumed;
}
void furi_thread_start(FuriThread* thread) { void furi_thread_start(FuriThread* thread) {
furi_check(thread); furi_check(thread);
furi_check(thread->callback); furi_check(thread->callback);

View file

@ -86,6 +86,18 @@ typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size);
*/ */
typedef void (*FuriThreadStateCallback)(FuriThreadState state, void* context); typedef void (*FuriThreadStateCallback)(FuriThreadState state, void* context);
/**
* @brief Signal handler callback function pointer type.
*
* The function to be used as a signal handler callback MUS follow this signature.
*
* @param[in] signal value of the signal to be handled by the recipient
* @param[in,out] arg optional argument (can be of any value, including NULL)
* @param[in,out] context pointer to a user-specified object
* @returns true if the signal was handled, false otherwise
*/
typedef bool (*FuriThreadSignalCallback)(uint32_t signal, void* arg, void* context);
/** /**
* @brief Create a FuriThread instance. * @brief Create a FuriThread instance.
* *
@ -255,6 +267,29 @@ void furi_thread_set_state_context(FuriThread* thread, void* context);
*/ */
FuriThreadState furi_thread_get_state(FuriThread* thread); FuriThreadState furi_thread_get_state(FuriThread* thread);
/**
* @brief Set a signal handler callback for a FuriThread instance.
*
* The thread MUST be stopped when calling this function.
*
* @param[in,out] thread pointer to the FuriThread instance to be modified
* @param[in] callback pointer to a user-specified callback function
* @param[in] context pointer to a user-specified object (will be passed to the callback, can be NULL)
*/
void furi_thread_set_signal_callback(
FuriThread* thread,
FuriThreadSignalCallback callback,
void* context);
/**
* @brief Send a signal to a FuriThread instance.
*
* @param[in] thread pointer to the FuriThread instance to be signaled
* @param[in] signal signal value to be sent
* @param[in,out] arg optional argument (can be of any value, including NULL)
*/
bool furi_thread_signal(const FuriThread* thread, uint32_t signal, void* arg);
/** /**
* @brief Start a FuriThread instance. * @brief Start a FuriThread instance.
* *

View file

@ -1,69 +0,0 @@
#!/usr/bin/env python3
import os
import posixpath
from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port
class Main(App):
def init(self):
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
self.parser.add_argument(
"-n",
"--no-launch",
dest="launch_app",
action="store_false",
help="Don't launch app",
)
self.parser.add_argument("fap_src_path", help="App file to upload")
self.parser.add_argument(
"--fap_dst_dir", help="Upload path", default="/ext/apps", required=False
)
self.parser.set_defaults(func=self.install)
def install(self):
if not (port := resolve_port(self.logger, self.args.port)):
return 1
try:
with FlipperStorage(port) as storage:
storage_ops = FlipperStorageOperations(storage)
fap_local_path = self.args.fap_src_path
self.args.fap_dst_dir = self.args.fap_dst_dir.rstrip("/\\")
if not os.path.isfile(fap_local_path):
self.logger.error(
f"Error: source .fap ({fap_local_path}) not found"
)
return 2
fap_dst_path = posixpath.join(
self.args.fap_dst_dir, os.path.basename(fap_local_path)
)
self.logger.info(f'Installing "{fap_local_path}" to {fap_dst_path}')
storage_ops.recursive_send(fap_dst_path, fap_local_path, False)
if not self.args.launch_app:
return 0
storage.send_and_wait_eol(f"loader open {fap_dst_path}\r")
if len(result := storage.read.until(storage.CLI_EOL)):
self.logger.error(f"Unexpected response: {result.decode('ascii')}")
return 3
return 0
except Exception as e:
self.logger.error(f"Error: {e}")
# raise
return 4
if __name__ == "__main__":
Main()()

View file

@ -2,6 +2,7 @@
import operator import operator
from functools import reduce from functools import reduce
import time
from flipper.app import App from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.storage import FlipperStorage, FlipperStorageOperations
@ -9,6 +10,8 @@ from flipper.utils.cdc import resolve_port
class Main(App): class Main(App):
APP_POST_CLOSE_DELAY_SEC = 0.2
def init(self): def init(self):
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
self.parser.add_argument( self.parser.add_argument(
@ -67,6 +70,23 @@ class Main(App):
if self.args.host_app: if self.args.host_app:
startup_command = self.args.host_app startup_command = self.args.host_app
self.logger.info("Closing current app, if any")
for _ in range(10):
storage.send_and_wait_eol("loader close\r")
result = storage.read.until(storage.CLI_EOL)
if b"was closed" in result:
self.logger.info("App closed")
storage.read.until(storage.CLI_EOL)
time.sleep(self.APP_POST_CLOSE_DELAY_SEC)
elif result.startswith(b"No application"):
storage.read.until(storage.CLI_EOL)
break
else:
self.logger.error(
f"Unexpected response: {result.decode('ascii')}"
)
return 4
self.logger.info(f"Launching app: {startup_command}") self.logger.info(f"Launching app: {startup_command}")
storage.send_and_wait_eol(f"loader open {startup_command}\r") storage.send_and_wait_eol(f"loader open {startup_command}\r")

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,66.0,, Version,+,66.2,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@ -1627,10 +1627,12 @@ Function,+,furi_thread_set_context,void,"FuriThread*, void*"
Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_current_priority,void,FuriThreadPriority
Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_name,void,"FuriThread*, const char*"
Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority"
Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCallback, void*"
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback
Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*"
Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_start,void,FuriThread*
Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_flush,int32_t,
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
@ -1782,10 +1784,12 @@ Function,-,llrintl,long long int,long double
Function,-,llround,long long int,double Function,-,llround,long long int,double
Function,-,llroundf,long long int,float Function,-,llroundf,long long int,float
Function,-,llroundl,long long int,long double Function,-,llroundl,long long int,long double
Function,+,loader_get_application_name,_Bool,"Loader*, FuriString*"
Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_get_pubsub,FuriPubSub*,Loader*
Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_is_locked,_Bool,Loader*
Function,+,loader_lock,_Bool,Loader* Function,+,loader_lock,_Bool,Loader*
Function,+,loader_show_menu,void,Loader* Function,+,loader_show_menu,void,Loader*
Function,+,loader_signal,_Bool,"Loader*, uint32_t, void*"
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*"
Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*" Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*"
Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*"

1 entry status name type params
2 Version + 66.0 66.2
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h
1627 Function + furi_thread_set_current_priority void FuriThreadPriority
1628 Function + furi_thread_set_name void FuriThread*, const char*
1629 Function + furi_thread_set_priority void FuriThread*, FuriThreadPriority
1630 Function + furi_thread_set_signal_callback void FuriThread*, FuriThreadSignalCallback, void*
1631 Function + furi_thread_set_stack_size void FuriThread*, size_t
1632 Function + furi_thread_set_state_callback void FuriThread*, FuriThreadStateCallback
1633 Function + furi_thread_set_state_context void FuriThread*, void*
1634 Function + furi_thread_set_stdout_callback void FuriThreadStdoutWriteCallback
1635 Function + furi_thread_signal _Bool const FuriThread*, uint32_t, void*
1636 Function + furi_thread_start void FuriThread*
1637 Function + furi_thread_stdout_flush int32_t
1638 Function + furi_thread_stdout_write size_t const char*, size_t
1784 Function - llround long long int double
1785 Function - llroundf long long int float
1786 Function - llroundl long long int long double
1787 Function + loader_get_application_name _Bool Loader*, FuriString*
1788 Function + loader_get_pubsub FuriPubSub* Loader*
1789 Function + loader_is_locked _Bool Loader*
1790 Function + loader_lock _Bool Loader*
1791 Function + loader_show_menu void Loader*
1792 Function + loader_signal _Bool Loader*, uint32_t, void*
1793 Function + loader_start LoaderStatus Loader*, const char*, const char*, FuriString*
1794 Function + loader_start_detached_with_gui_error void Loader*, const char*, const char*
1795 Function + loader_start_with_gui_error LoaderStatus Loader*, const char*, const char*

View file

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,66.0,, Version,+,66.2,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
@ -1841,10 +1841,12 @@ Function,+,furi_thread_set_context,void,"FuriThread*, void*"
Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_current_priority,void,FuriThreadPriority
Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_name,void,"FuriThread*, const char*"
Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority"
Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCallback, void*"
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback
Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*"
Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_start,void,FuriThread*
Function,+,furi_thread_stdout_flush,int32_t, Function,+,furi_thread_stdout_flush,int32_t,
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
@ -2200,10 +2202,12 @@ Function,-,llrintl,long long int,long double
Function,-,llround,long long int,double Function,-,llround,long long int,double
Function,-,llroundf,long long int,float Function,-,llroundf,long long int,float
Function,-,llroundl,long long int,long double Function,-,llroundl,long long int,long double
Function,+,loader_get_application_name,_Bool,"Loader*, FuriString*"
Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_get_pubsub,FuriPubSub*,Loader*
Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_is_locked,_Bool,Loader*
Function,+,loader_lock,_Bool,Loader* Function,+,loader_lock,_Bool,Loader*
Function,+,loader_show_menu,void,Loader* Function,+,loader_show_menu,void,Loader*
Function,+,loader_signal,_Bool,"Loader*, uint32_t, void*"
Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*"
Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*" Function,+,loader_start_detached_with_gui_error,void,"Loader*, const char*, const char*"
Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*"

1 entry status name type params
2 Version + 66.0 66.2
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/bt/bt_service/bt_keys_storage.h
1841 Function + furi_thread_set_current_priority void FuriThreadPriority
1842 Function + furi_thread_set_name void FuriThread*, const char*
1843 Function + furi_thread_set_priority void FuriThread*, FuriThreadPriority
1844 Function + furi_thread_set_signal_callback void FuriThread*, FuriThreadSignalCallback, void*
1845 Function + furi_thread_set_stack_size void FuriThread*, size_t
1846 Function + furi_thread_set_state_callback void FuriThread*, FuriThreadStateCallback
1847 Function + furi_thread_set_state_context void FuriThread*, void*
1848 Function + furi_thread_set_stdout_callback void FuriThreadStdoutWriteCallback
1849 Function + furi_thread_signal _Bool const FuriThread*, uint32_t, void*
1850 Function + furi_thread_start void FuriThread*
1851 Function + furi_thread_stdout_flush int32_t
1852 Function + furi_thread_stdout_write size_t const char*, size_t
2202 Function - llround long long int double
2203 Function - llroundf long long int float
2204 Function - llroundl long long int long double
2205 Function + loader_get_application_name _Bool Loader*, FuriString*
2206 Function + loader_get_pubsub FuriPubSub* Loader*
2207 Function + loader_is_locked _Bool Loader*
2208 Function + loader_lock _Bool Loader*
2209 Function + loader_show_menu void Loader*
2210 Function + loader_signal _Bool Loader*, uint32_t, void*
2211 Function + loader_start LoaderStatus Loader*, const char*, const char*, FuriString*
2212 Function + loader_start_detached_with_gui_error void Loader*, const char*, const char*
2213 Function + loader_start_with_gui_error LoaderStatus Loader*, const char*, const char*