Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX 2024-03-25 14:23:44 +03:00
commit 7c0939ad52
No known key found for this signature in database
GPG Key ID: 7CCC66B7DBDD1C83
58 changed files with 2159 additions and 1328 deletions

View File

@ -42,6 +42,7 @@ distenv = coreenv.Clone(
"openocd",
"blackmagic",
"jflash",
"doxygen",
],
ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
@ -417,3 +418,18 @@ distenv.PhonyTarget(
"env",
"@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)",
)
doxy_build = distenv.DoxyBuild(
"documentation/doxygen/build/html/index.html",
"documentation/doxygen/Doxyfile-awesome.cfg",
doxy_env_variables={
"DOXY_SRC_ROOT": Dir(".").abspath,
"DOXY_BUILD_DIR": Dir("documentation/doxygen/build").abspath,
"DOXY_CONFIG_DIR": "documentation/doxygen",
},
)
distenv.Alias("doxygen", doxy_build)
distenv.AlwaysBuild(doxy_build)
# Open generated documentation in browser
distenv.PhonyTarget("doxy", open_browser_action, source=doxy_build)

View File

@ -12,7 +12,7 @@ void subghz_test_scene_show_only_rx_on_enter(void* context) {
// Setup view
Popup* popup = app->popup;
const char* header_text = "Transmission is blocked";
const char* header_text = "Transmission is Blocked";
const char* message_text = "Transmission on\nthis frequency is\nrestricted in\nyour region";
if(!furi_hal_region_is_provisioned()) {
header_text = "Firmware update needed";

View File

@ -7,7 +7,7 @@ App(
icon="A_BadUsb_14",
order=70,
resources="resources",
fap_libs=["assets"],
fap_libs=["assets", "ble_profile"],
fap_icon="icon.png",
fap_category="USB",
)

View File

@ -1,11 +1,14 @@
#include "bad_usb_app_i.h"
#include "bad_usb_settings_filename.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format.h>
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badusb.settings"
#define BAD_USB_SETTINGS_FILE_TYPE "Flipper BadUSB Settings File"
#define BAD_USB_SETTINGS_VERSION 1
#define BAD_USB_SETTINGS_DEFAULT_LAYOUT BAD_USB_APP_PATH_LAYOUT_FOLDER "/en-US.kl"
static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
@ -26,46 +29,69 @@ static void bad_usb_app_tick_event_callback(void* context) {
}
static void bad_usb_load_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
char chr;
while((storage_file_read(settings_file, &chr, 1) == 1) &&
!storage_file_eof(settings_file) && !isspace(chr)) {
furi_string_push_back(app->keyboard_layout, chr);
}
} else {
furi_string_reset(app->keyboard_layout);
}
storage_file_close(settings_file);
storage_file_free(settings_file);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
bool state = false;
FuriString* temp_str = furi_string_alloc();
uint32_t version = 0;
uint32_t interface = 0;
if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_read_header(fff, temp_str, &version)) break;
if((strcmp(furi_string_get_cstr(temp_str), BAD_USB_SETTINGS_FILE_TYPE) != 0) ||
(version != BAD_USB_SETTINGS_VERSION))
break;
if(!flipper_format_read_string(fff, "layout", temp_str)) break;
if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break;
if(interface > BadUsbHidInterfaceBle) break;
state = true;
} while(0);
}
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
if(state) {
furi_string_set(app->keyboard_layout, temp_str);
app->interface = interface;
if(!furi_string_empty(app->keyboard_layout)) {
Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info;
FS_Error file_check_err = storage_common_stat(
fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
furi_record_close(RECORD_STORAGE);
if(file_check_err != FSE_OK) {
furi_string_reset(app->keyboard_layout);
return;
}
if(layout_file_info.size != 256) {
furi_string_reset(app->keyboard_layout);
if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) {
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
}
} else {
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
app->interface = BadUsbHidInterfaceUsb;
}
furi_string_free(temp_str);
}
static void bad_usb_save_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
storage_file_write(
settings_file,
furi_string_get_cstr(app->keyboard_layout),
furi_string_size(app->keyboard_layout));
storage_file_write(settings_file, "\n", 1);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_write_header_cstr(
fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION))
break;
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
uint32_t interface_id = app->interface;
if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1))
break;
} while(0);
}
storage_file_close(settings_file);
storage_file_free(settings_file);
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
}
BadUsbApp* bad_usb_app_alloc(char* arg) {
@ -103,13 +129,15 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));
app->submenu = submenu_alloc();
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu));
app->view_dispatcher,
BadUsbAppViewConfig,
variable_item_list_get_view(app->var_item_list));
app->bad_usb_view = bad_usb_alloc();
app->bad_usb_view = bad_usb_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view));
app->view_dispatcher, BadUsbAppViewWork, bad_usb_view_get_view(app->bad_usb_view));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
@ -122,8 +150,6 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
furi_check(furi_hal_usb_set_config(NULL, NULL));
if(!furi_string_empty(app->file_path)) {
app->bad_usb_script = bad_usb_script_open(app->file_path);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else {
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
@ -144,15 +170,15 @@ void bad_usb_app_free(BadUsbApp* app) {
// Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view);
bad_usb_view_free(app->bad_usb_view);
// Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
widget_free(app->widget);
// Submenu
// Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
submenu_free(app->submenu);
variable_item_list_free(app->var_item_list);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);

View File

@ -3,12 +3,12 @@
#include "bad_usb_app.h"
#include "scenes/bad_usb_scene.h"
#include "helpers/ducky_script.h"
#include "helpers/bad_usb_hid.h"
#include <gui/gui.h>
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include <gui/modules/variable_item_list.h>
@ -33,7 +33,7 @@ struct BadUsbApp {
NotificationApp* notifications;
DialogsApp* dialogs;
Widget* widget;
Submenu* submenu;
VariableItemList* var_item_list;
BadUsbAppError error;
FuriString* file_path;
@ -41,6 +41,7 @@ struct BadUsbApp {
BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script;
BadUsbHidInterface interface;
FuriHalUsbInterface* usb_if_prev;
};

View File

@ -1,3 +0,0 @@
#pragma once
#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings"

View File

@ -0,0 +1,226 @@
#include "bad_usb_hid.h"
#include <extra_profiles/hid_profile.h>
#include <bt/bt_service/bt.h>
#include <storage/storage.h>
#define TAG "BadUSB HID"
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) {
furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg));
return NULL;
}
void hid_usb_deinit(void* inst) {
UNUSED(inst);
furi_check(furi_hal_usb_set_config(NULL, NULL));
}
void hid_usb_set_state_callback(void* inst, HidStateCallback cb, void* context) {
UNUSED(inst);
furi_hal_hid_set_state_callback(cb, context);
}
bool hid_usb_is_connected(void* inst) {
UNUSED(inst);
return furi_hal_hid_is_connected();
}
bool hid_usb_kb_press(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_kb_press(button);
}
bool hid_usb_kb_release(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_kb_release(button);
}
bool hid_usb_consumer_press(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_consumer_key_press(button);
}
bool hid_usb_consumer_release(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_consumer_key_release(button);
}
bool hid_usb_release_all(void* inst) {
UNUSED(inst);
bool state = furi_hal_hid_kb_release_all();
state &= furi_hal_hid_consumer_key_release_all();
return state;
}
uint8_t hid_usb_get_led_state(void* inst) {
UNUSED(inst);
return furi_hal_hid_get_led_state();
}
static const BadUsbHidApi hid_api_usb = {
.init = hid_usb_init,
.deinit = hid_usb_deinit,
.set_state_callback = hid_usb_set_state_callback,
.is_connected = hid_usb_is_connected,
.kb_press = hid_usb_kb_press,
.kb_release = hid_usb_kb_release,
.consumer_press = hid_usb_consumer_press,
.consumer_release = hid_usb_consumer_release,
.release_all = hid_usb_release_all,
.get_led_state = hid_usb_get_led_state,
};
typedef struct {
Bt* bt;
FuriHalBleProfileBase* profile;
HidStateCallback state_callback;
void* callback_context;
bool is_connected;
} BleHidInstance;
static const BleProfileHidParams ble_hid_params = {
.device_name_prefix = "BadUSB",
.mac_xor = 0x0002,
};
static void hid_ble_connection_status_callback(BtStatus status, void* context) {
furi_assert(context);
BleHidInstance* ble_hid = context;
ble_hid->is_connected = (status == BtStatusConnected);
if(ble_hid->state_callback) {
ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
}
}
void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) {
UNUSED(hid_cfg);
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
ble_hid->bt = furi_record_open(RECORD_BT);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params);
furi_check(ble_hid->profile);
furi_hal_bt_start_advertising();
bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid);
return ble_hid;
}
void hid_ble_deinit(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bt_set_status_changed_callback(ble_hid->bt, NULL, NULL);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(ble_hid->bt);
furi_check(bt_profile_restore_default(ble_hid->bt));
furi_record_close(RECORD_BT);
free(ble_hid);
}
void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
ble_hid->state_callback = cb;
ble_hid->callback_context = context;
}
bool hid_ble_is_connected(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_hid->is_connected;
}
bool hid_ble_kb_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_press(ble_hid->profile, button);
}
bool hid_ble_kb_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_release(ble_hid->profile, button);
}
bool hid_ble_consumer_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_press(ble_hid->profile, button);
}
bool hid_ble_consumer_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_release(ble_hid->profile, button);
}
bool hid_ble_release_all(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
return state;
}
uint8_t hid_ble_get_led_state(void* inst) {
UNUSED(inst);
FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented");
return 0;
}
static const BadUsbHidApi hid_api_ble = {
.init = hid_ble_init,
.deinit = hid_ble_deinit,
.set_state_callback = hid_ble_set_state_callback,
.is_connected = hid_ble_is_connected,
.kb_press = hid_ble_kb_press,
.kb_release = hid_ble_kb_release,
.consumer_press = hid_ble_consumer_press,
.consumer_release = hid_ble_consumer_release,
.release_all = hid_ble_release_all,
.get_led_state = hid_ble_get_led_state,
};
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) {
if(interface == BadUsbHidInterfaceUsb) {
return &hid_api_usb;
} else {
return &hid_api_ble;
}
}
void bad_usb_hid_ble_remove_pairing(void) {
Bt* bt = furi_record_open(RECORD_BT);
bt_disconnect(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
furi_hal_bt_stop_advertising();
bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
bt_forget_bonded_devices(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(bt);
furi_check(bt_profile_restore_default(bt));
furi_record_close(RECORD_BT);
}

View File

@ -0,0 +1,35 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
typedef enum {
BadUsbHidInterfaceUsb,
BadUsbHidInterfaceBle,
} BadUsbHidInterface;
typedef struct {
void* (*init)(FuriHalUsbHidConfig* hid_cfg);
void (*deinit)(void* inst);
void (*set_state_callback)(void* inst, HidStateCallback cb, void* context);
bool (*is_connected)(void* inst);
bool (*kb_press)(void* inst, uint16_t button);
bool (*kb_release)(void* inst, uint16_t button);
bool (*consumer_press)(void* inst, uint16_t button);
bool (*consumer_release)(void* inst, uint16_t button);
bool (*release_all)(void* inst);
uint8_t (*get_led_state)(void* inst);
} BadUsbHidApi;
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface);
void bad_usb_hid_ble_remove_pairing(void);
#ifdef __cplusplus
}
#endif

View File

@ -3,7 +3,6 @@
#include <gui/gui.h>
#include <input/input.h>
#include <lib/toolbox/args.h>
#include <furi_hal_usb_hid.h>
#include <storage/storage.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
@ -71,39 +70,40 @@ bool ducky_get_number(const char* param, uint32_t* val) {
return false;
}
void ducky_numlock_on(void) {
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
void ducky_numlock_on(BadUsbScript* bad_usb) {
if((bad_usb->hid->get_led_state(bad_usb->hid_inst) & HID_KB_LED_NUM) == 0) {
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
}
}
bool ducky_numpad_press(const char num) {
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num) {
if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0'];
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release(key);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return true;
}
bool ducky_altchar(const char* charcode) {
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode) {
uint8_t i = 0;
bool state = false;
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
while(!ducky_is_line_end(charcode[i])) {
state = ducky_numpad_press(charcode[i]);
state = ducky_numpad_press(bad_usb, charcode[i]);
if(state == false) break;
i++;
}
furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
bad_usb->hid->kb_release(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
return state;
}
bool ducky_altstring(const char* param) {
bool ducky_altstring(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
bool state = false;
@ -116,7 +116,7 @@ bool ducky_altstring(const char* param) {
char temp_str[4];
snprintf(temp_str, 4, "%u", param[i]);
state = ducky_altchar(temp_str);
state = ducky_altchar(bad_usb, temp_str);
if(state == false) break;
i++;
}
@ -140,12 +140,12 @@ bool ducky_string(BadUsbScript* bad_usb, const char* param) {
if(param[i] != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
}
i++;
}
@ -163,12 +163,12 @@ static bool ducky_string_next(BadUsbScript* bad_usb) {
if(print_char != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
}
bad_usb->string_print_pos++;
@ -205,8 +205,8 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
key |= ducky_get_keycode(bad_usb, line_tmp + offset, true);
}
}
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release(key);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
@ -235,6 +235,17 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
return false;
}
static void bad_usb_hid_state_callback(bool state, void* context) {
furi_assert(context);
BadUsbScript* bad_usb = context;
if(state == true) {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
} else {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
}
}
static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
uint8_t ret = 0;
uint32_t line_len = 0;
@ -269,10 +280,11 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
}
if(id_set) {
furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg));
bad_usb->hid_inst = bad_usb->hid->init(&bad_usb->hid_cfg);
} else {
furi_check(furi_hal_usb_set_config(&usb_hid, NULL));
bad_usb->hid_inst = bad_usb->hid->init(NULL);
}
bad_usb->hid->set_state_callback(bad_usb->hid_inst, bad_usb_hid_state_callback, bad_usb);
storage_file_seek(script_file, 0, true);
furi_string_reset(bad_usb->line);
@ -349,17 +361,6 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
return 0;
}
static void bad_usb_hid_state_callback(bool state, void* context) {
furi_assert(context);
BadUsbScript* bad_usb = context;
if(state == true) {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
} else {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
}
}
static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0);
@ -386,8 +387,6 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->line_prev = furi_string_alloc();
bad_usb->string_print = furi_string_alloc();
furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb);
while(1) {
if(worker_state == BadUsbStateInit) { // State: initialization
if(storage_file_open(
@ -396,7 +395,7 @@ static int32_t bad_usb_worker(void* context) {
FSAM_READ,
FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
if(furi_hal_hid_is_connected()) {
if(bad_usb->hid->is_connected(bad_usb->hid_inst)) {
worker_state = BadUsbStateIdle; // Ready to run
} else {
worker_state = BadUsbStateNotConnected; // USB not connected
@ -412,7 +411,8 @@ static int32_t bad_usb_worker(void* context) {
} else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever);
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
if(flags & WorkerEvtEnd) {
break;
@ -494,10 +494,10 @@ static int32_t bad_usb_worker(void* context) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateRunning;
worker_state = BadUsbStatePaused; // Pause
@ -517,12 +517,12 @@ static int32_t bad_usb_worker(void* context) {
delay_val = 0;
worker_state = BadUsbStateScriptError;
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(delay_val == SCRIPT_STATE_END) { // End of script
delay_val = 0;
worker_state = BadUsbStateIdle;
bad_usb->st.state = BadUsbStateDone;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_usb->defdelay;
@ -550,7 +550,7 @@ static int32_t bad_usb_worker(void* context) {
worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
}
bad_usb->st.state = worker_state;
continue;
@ -565,11 +565,11 @@ static int32_t bad_usb_worker(void* context) {
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadUsbStateRunning) {
if(delay_val > 0) {
@ -599,10 +599,10 @@ static int32_t bad_usb_worker(void* context) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateStringDelay;
worker_state = BadUsbStatePaused; // Pause
@ -632,7 +632,8 @@ static int32_t bad_usb_worker(void* context) {
}
}
furi_hal_hid_set_state_callback(NULL, NULL);
bad_usb->hid->set_state_callback(bad_usb->hid_inst, NULL, NULL);
bad_usb->hid->deinit(bad_usb->hid_inst);
storage_file_close(script_file);
storage_file_free(script_file);
@ -651,7 +652,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
}
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) {
furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
@ -661,6 +662,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) {
bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0';
bad_usb->hid = bad_usb_hid_get_interface(interface);
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread);

View File

@ -6,6 +6,7 @@ extern "C" {
#include <furi.h>
#include <furi_hal.h>
#include "bad_usb_hid.h"
typedef enum {
BadUsbStateInit,
@ -33,7 +34,7 @@ typedef struct {
typedef struct BadUsbScript BadUsbScript;
BadUsbScript* bad_usb_script_open(FuriString* file_path);
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface);
void bad_usb_script_close(BadUsbScript* bad_usb);

View File

@ -1,5 +1,4 @@
#include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
@ -93,9 +92,9 @@ static int32_t ducky_fnc_sysrq(BadUsbScript* bad_usb, const char* line, int32_t
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all();
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->release_all(bad_usb->hid_inst);
return 0;
}
@ -103,8 +102,8 @@ static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on();
bool state = ducky_altchar(line);
ducky_numlock_on(bad_usb);
bool state = ducky_altchar(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altchar %s", line);
}
@ -115,8 +114,8 @@ static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int3
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on();
bool state = ducky_altstring(line);
ducky_numlock_on(bad_usb);
bool state = ducky_altstring(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altstring %s", line);
}
@ -135,7 +134,7 @@ static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t p
if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are hold");
}
furi_hal_hid_kb_press(key);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;
}
@ -151,7 +150,36 @@ static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_
return ducky_error(bad_usb, "No keys are hold");
}
bad_usb->key_hold_nb--;
furi_hal_hid_kb_release(key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_media(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_media_keycode_by_name(line);
if(key == HID_CONSUMER_UNASSIGNED) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->hid->consumer_press(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_globe(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_usb->hid->consumer_press(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
return 0;
}
@ -183,6 +211,8 @@ static const DuckyCmd ducky_commands[] = {
{"HOLD", ducky_fnc_hold, -1},
{"RELEASE", ducky_fnc_release, -1},
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
{"MEDIA", ducky_fnc_media, -1},
{"GLOBE", ducky_fnc_globe, -1},
};
#define TAG "BadUsb"

View File

@ -7,6 +7,7 @@ extern "C" {
#include <furi.h>
#include <furi_hal.h>
#include "ducky_script.h"
#include "bad_usb_hid.h"
#define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2)
@ -19,6 +20,8 @@ extern "C" {
struct BadUsbScript {
FuriHalUsbHidConfig hid_cfg;
const BadUsbHidApi* hid;
void* hid_inst;
FuriThread* thread;
BadUsbState st;
@ -50,15 +53,17 @@ bool ducky_is_line_end(const char chr);
uint16_t ducky_get_keycode_by_name(const char* param);
uint16_t ducky_get_media_keycode_by_name(const char* param);
bool ducky_get_number(const char* param, uint32_t* val);
void ducky_numlock_on(void);
void ducky_numlock_on(BadUsbScript* bad_usb);
bool ducky_numpad_press(const char num);
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num);
bool ducky_altchar(const char* charcode);
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode);
bool ducky_altstring(const char* param);
bool ducky_altstring(BadUsbScript* bad_usb, const char* param);
bool ducky_string(BadUsbScript* bad_usb, const char* param);

View File

@ -1,5 +1,4 @@
#include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script_i.h"
typedef struct {
@ -78,6 +77,37 @@ static const DuckyKey ducky_keys[] = {
{"F24", HID_KEYBOARD_F24},
};
static const DuckyKey ducky_media_keys[] = {
{"POWER", HID_CONSUMER_POWER},
{"REBOOT", HID_CONSUMER_RESET},
{"SLEEP", HID_CONSUMER_SLEEP},
{"LOGOFF", HID_CONSUMER_AL_LOGOFF},
{"EXIT", HID_CONSUMER_AC_EXIT},
{"HOME", HID_CONSUMER_AC_HOME},
{"BACK", HID_CONSUMER_AC_BACK},
{"FORWARD", HID_CONSUMER_AC_FORWARD},
{"REFRESH", HID_CONSUMER_AC_REFRESH},
{"SNAPSHOT", HID_CONSUMER_SNAPSHOT},
{"PLAY", HID_CONSUMER_PLAY},
{"PAUSE", HID_CONSUMER_PAUSE},
{"PLAY_PAUSE", HID_CONSUMER_PLAY_PAUSE},
{"NEXT_TRACK", HID_CONSUMER_SCAN_NEXT_TRACK},
{"PREV_TRACK", HID_CONSUMER_SCAN_PREVIOUS_TRACK},
{"STOP", HID_CONSUMER_STOP},
{"EJECT", HID_CONSUMER_EJECT},
{"MUTE", HID_CONSUMER_MUTE},
{"VOLUME_UP", HID_CONSUMER_VOLUME_INCREMENT},
{"VOLUME_DOWN", HID_CONSUMER_VOLUME_DECREMENT},
{"FN", HID_CONSUMER_FN_GLOBE},
{"BRIGHT_UP", HID_CONSUMER_BRIGHTNESS_INCREMENT},
{"BRIGHT_DOWN", HID_CONSUMER_BRIGHTNESS_DECREMENT},
};
uint16_t ducky_get_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name);
@ -89,3 +119,15 @@ uint16_t ducky_get_keycode_by_name(const char* param) {
return HID_KEYBOARD_NONE;
}
uint16_t ducky_get_media_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_media_keys); i++) {
size_t key_cmd_len = strlen(ducky_media_keys[i].name);
if((strncmp(param, ducky_media_keys[i].name, key_cmd_len) == 0) &&
(ducky_is_line_end(param[key_cmd_len]))) {
return ducky_media_keys[i].keycode;
}
}
return HID_CONSUMER_UNASSIGNED;
}

View File

@ -0,0 +1,80 @@
REM This is BadUSB demo script for ChromeOS by kowalski7cc
REM Open a new tab
CTRL t
REM wait for some slower chromebooks
DELAY 1000
REM Open an empty editable page
DEFAULT_DELAY 50
STRING data:text/html, <html contenteditable autofocus><style>body{font-family:monospace;}
ENTER
DELAY 500
STRING Hello World!
ENTER
REM Copy-Paste previous string
UP
HOME
SHIFT DOWN
CTRL c
RIGHT
CTRL v
CTRL v
STRING =
REPEAT 59
ENTER
ENTER
STRING _.-------.._ -,
ENTER
HOME
STRING .-"```"--..,,_/ /`-, -, \
ENTER
HOME
STRING .:" /:/ /'\ \ ,_..., `. | |
ENTER
HOME
STRING / ,----/:/ /`\ _\~`_-"` _;
ENTER
HOME
STRING ' / /`"""'\ \ \.~`_-' ,-"'/
ENTER
HOME
STRING | | | 0 | | .-' ,/` /
ENTER
HOME
STRING | ,..\ \ ,.-"` ,/` /
ENTER
HOME
STRING ; : `/`""\` ,/--==,/-----,
ENTER
HOME
STRING | `-...| -.___-Z:_______J...---;
ENTER
HOME
STRING : ` _-'
ENTER
HOME
STRING _L_ _ ___ ___ ___ ___ ____--"`
ENTER
HOME
STRING | __|| | |_ _|| _ \| _ \| __|| _ \
ENTER
HOME
STRING | _| | |__ | | | _/| _/| _| | /
ENTER
HOME
STRING |_| |____||___||_| |_| |___||_|_\
ENTER
HOME
ENTER
STRING Flipper Zero BadUSB feature is compatible with USB Rubber Ducky script format
ENTER
STRING More information about script syntax can be found here:
ENTER
STRING https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/file_formats/BadUsbScriptFormat.md
ENTER

View File

@ -1,29 +1,62 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
enum SubmenuIndex {
SubmenuIndexKeyboardLayout,
ConfigIndexKeyboardLayout,
ConfigIndexInterface,
ConfigIndexBleUnpair,
};
void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) {
const char* const interface_mode_text[2] = {
"USB",
"BLE",
};
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
if(index != ConfigIndexInterface) {
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
}
}
void bad_usb_scene_config_interface_callback(VariableItem* item) {
BadUsbApp* bad_usb = variable_item_get_context(item);
furi_assert(bad_usb);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, interface_mode_text[index]);
bad_usb->interface = index;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ConfigIndexInterface);
}
static void draw_menu(BadUsbApp* bad_usb) {
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_reset(var_item_list);
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
VariableItem* item = variable_item_list_add(
var_item_list, "Interface", 2, bad_usb_scene_config_interface_callback, bad_usb);
if(bad_usb->interface == BadUsbHidInterfaceUsb) {
variable_item_set_current_value_index(item, 0);
variable_item_set_current_value_text(item, interface_mode_text[0]);
} else {
variable_item_set_current_value_index(item, 1);
variable_item_set_current_value_text(item, interface_mode_text[1]);
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
}
}
void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;
VariableItemList* var_item_list = bad_usb->var_item_list;
submenu_add_item(
submenu,
"Keyboard Layout (global)",
SubmenuIndexKeyboardLayout,
bad_usb_scene_config_submenu_callback,
bad_usb);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig));
variable_item_list_set_enter_callback(
var_item_list, bad_usb_scene_config_select_callback, bad_usb);
draw_menu(bad_usb);
variable_item_list_set_selected_item(var_item_list, 0);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig);
}
@ -33,10 +66,13 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event);
consumed = true;
if(event.event == SubmenuIndexKeyboardLayout) {
if(event.event == ConfigIndexKeyboardLayout) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
} else if(event.event == ConfigIndexInterface) {
draw_menu(bad_usb);
} else if(event.event == ConfigIndexBleUnpair) {
bad_usb_hid_ble_remove_pairing();
} else {
furi_crash("Unknown key type");
}
@ -47,7 +83,7 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;
VariableItemList* var_item_list = bad_usb->var_item_list;
submenu_reset(submenu);
variable_item_list_reset(var_item_list);
}

View File

@ -1,6 +1,5 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
#include <storage/storage.h>
static bool bad_usb_layout_select(BadUsbApp* bad_usb) {

View File

@ -32,7 +32,7 @@ void bad_usb_scene_error_on_enter(void* context) {
} else if(app->error == BadUsbAppErrorCloseRpc) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element(
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nIs Active!");
widget_add_string_multiline_element(
app->widget,
3,

View File

@ -1,6 +1,5 @@
#include "../bad_usb_app_i.h"
#include <furi_hal_power.h>
#include <furi_hal_usb.h>
#include <storage/storage.h>
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
@ -28,9 +27,6 @@ void bad_usb_scene_file_select_on_enter(void* context) {
}
if(bad_usb_file_select(bad_usb)) {
bad_usb->bad_usb_script = bad_usb_script_open(bad_usb->file_path);
bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else {
view_dispatcher_stop(bad_usb->view_dispatcher);

View File

@ -16,7 +16,10 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_usb_is_idle_state(app->bad_usb_view)) {
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = NULL;
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
}
consumed = true;
@ -28,7 +31,7 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
}
return consumed;
}
@ -36,21 +39,24 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
void bad_usb_scene_work_on_enter(void* context) {
BadUsbApp* app = context;
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
FuriString* file_name;
file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true);
bad_usb_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name));
bad_usb_view_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name));
furi_string_free(file_name);
FuriString* layout;
layout = furi_string_alloc();
path_extract_filename(app->keyboard_layout, layout, true);
bad_usb_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
bad_usb_view_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
furi_string_free(layout);
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app);
bad_usb_view_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWork);
}

View File

@ -66,7 +66,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to USB");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to device");
} else if(state == BadUsbStateWillRun) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
@ -193,7 +193,7 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) {
return consumed;
}
BadUsb* bad_usb_alloc(void) {
BadUsb* bad_usb_view_alloc(void) {
BadUsb* bad_usb = malloc(sizeof(BadUsb));
bad_usb->view = view_alloc();
@ -205,18 +205,21 @@ BadUsb* bad_usb_alloc(void) {
return bad_usb;
}
void bad_usb_free(BadUsb* bad_usb) {
void bad_usb_view_free(BadUsb* bad_usb) {
furi_assert(bad_usb);
view_free(bad_usb->view);
free(bad_usb);
}
View* bad_usb_get_view(BadUsb* bad_usb) {
View* bad_usb_view_get_view(BadUsb* bad_usb) {
furi_assert(bad_usb);
return bad_usb->view;
}
void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context) {
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context) {
furi_assert(bad_usb);
furi_assert(callback);
with_view_model(
@ -230,7 +233,7 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback,
true);
}
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name) {
furi_assert(name);
with_view_model(
bad_usb->view,
@ -239,7 +242,7 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
true);
}
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout) {
furi_assert(layout);
with_view_model(
bad_usb->view,
@ -248,7 +251,7 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
true);
}
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
bad_usb->view,
@ -263,7 +266,7 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
true);
}
bool bad_usb_is_idle_state(BadUsb* bad_usb) {
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false;
with_view_model(
bad_usb->view,

View File

@ -6,18 +6,21 @@
typedef struct BadUsb BadUsb;
typedef void (*BadUsbButtonCallback)(InputKey key, void* context);
BadUsb* bad_usb_alloc(void);
BadUsb* bad_usb_view_alloc(void);
void bad_usb_free(BadUsb* bad_usb);
void bad_usb_view_free(BadUsb* bad_usb);
View* bad_usb_get_view(BadUsb* bad_usb);
View* bad_usb_view_get_view(BadUsb* bad_usb);
void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context);
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context);
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st);
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
bool bad_usb_is_idle_state(BadUsb* bad_usb);
bool bad_usb_view_is_idle_state(BadUsb* bad_usb);

View File

@ -6,7 +6,7 @@ void gpio_scene_usb_uart_close_rpc_on_enter(void* context) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element(
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nIs Active!");
widget_add_string_multiline_element(
app->widget,
3,

View File

@ -6,7 +6,7 @@ void infrared_scene_learn_done_on_enter(void* context) {
if(infrared->app_state.is_learning_new_remote) {
popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58);
popup_set_header(popup, "New remote\ncreated!", 0, 0, AlignLeft, AlignTop);
popup_set_header(popup, "Success!", 10, 12, AlignLeft, AlignTop);
} else {
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom);

View File

@ -34,7 +34,7 @@ static void infrared_move_view_draw_callback(Canvas* canvas, void* _model) {
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(
canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "Select a button to move");
canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "Select a Button to Move");
const size_t btn_number = InfraredMoveViewItemArray_size(model->labels);
const bool show_scrollbar = btn_number > LIST_ITEMS;

View File

@ -27,7 +27,7 @@ void u2f_scene_error_on_enter(void* context) {
} else if(app->error == U2fAppErrorCloseRpc) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element(
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nIs Active!");
widget_add_string_multiline_element(
app->widget,
3,

View File

@ -17,50 +17,50 @@
#include <stdbool.h>
typedef struct {
uint8_t x;
uint8_t y;
uint8_t leading_min;
uint8_t leading_default;
uint8_t height;
uint8_t descender;
uint8_t len;
int32_t x;
int32_t y;
int32_t leading_min;
int32_t leading_default;
size_t height;
size_t descender;
size_t len;
const char* text;
} ElementTextBoxLine;
void elements_progress_bar(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, float progress) {
void elements_progress_bar(Canvas* canvas, int32_t x, int32_t y, size_t width, float progress) {
furi_check(canvas);
furi_check((progress >= 0.0f) && (progress <= 1.0f));
uint8_t height = 9;
size_t height = 9;
uint8_t progress_length = roundf(progress * (width - 2));
float progress_width = roundf(progress * (width - 2));
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, x + 1, y + 1, width - 2, height - 2);
canvas_set_color(canvas, ColorBlack);
canvas_draw_rframe(canvas, x, y, width, height, 3);
canvas_draw_box(canvas, x + 1, y + 1, progress_length, height - 2);
canvas_draw_box(canvas, x + 1, y + 1, progress_width, height - 2);
}
void elements_progress_bar_with_text(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
int32_t x,
int32_t y,
size_t width,
float progress,
const char* text) {
furi_check(canvas);
furi_check((progress >= 0.0f) && (progress <= 1.0f));
uint8_t height = 11;
size_t height = 11;
uint8_t progress_length = roundf(progress * (width - 2));
float progress_width = roundf(progress * (width - 2));
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, x + 1, y + 1, width - 2, height - 2);
canvas_set_color(canvas, ColorBlack);
canvas_draw_rframe(canvas, x, y, width, height, 3);
canvas_draw_box(canvas, x + 1, y + 1, progress_length, height - 2);
canvas_draw_box(canvas, x + 1, y + 1, progress_width, height - 2);
canvas_set_color(canvas, ColorXOR);
canvas_set_font(canvas, FontSecondary);
@ -69,20 +69,23 @@ void elements_progress_bar_with_text(
void elements_scrollbar_pos(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t height,
uint16_t pos,
uint16_t total) {
int32_t x,
int32_t y,
size_t height,
size_t pos,
size_t total) {
furi_check(canvas);
// prevent overflows
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, x - 3, y, 3, height);
// dot line
canvas_set_color(canvas, ColorBlack);
for(uint8_t i = y; i < height + y; i += 2) {
for(int32_t i = y; i < (int32_t)height + y; i += 2) {
canvas_draw_dot(canvas, x - 2, i);
}
// Position block
if(total) {
float block_h = ((float)height) / total;
@ -90,19 +93,22 @@ void elements_scrollbar_pos(
}
}
void elements_scrollbar(Canvas* canvas, uint16_t pos, uint16_t total) {
void elements_scrollbar(Canvas* canvas, size_t pos, size_t total) {
furi_check(canvas);
uint8_t width = canvas_width(canvas);
uint8_t height = canvas_height(canvas);
size_t width = canvas_width(canvas);
size_t height = canvas_height(canvas);
// prevent overflows
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, width - 3, 0, 3, height);
// dot line
canvas_set_color(canvas, ColorBlack);
for(uint8_t i = 0; i < height; i += 2) {
for(size_t i = 0; i < height; i += 2) {
canvas_draw_dot(canvas, width - 2, i);
}
// Position block
if(total) {
float block_h = ((float)height) / total;
@ -110,7 +116,7 @@ void elements_scrollbar(Canvas* canvas, uint16_t pos, uint16_t total) {
}
}
void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
void elements_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height) {
furi_check(canvas);
canvas_draw_line(canvas, x + 2, y, x + width - 2, y);
@ -127,18 +133,18 @@ void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t
void elements_button_left(Canvas* canvas, const char* str) {
furi_check(canvas);
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 3;
const uint8_t string_width = canvas_string_width(canvas, str);
const size_t button_height = 12;
const size_t vertical_offset = 3;
const size_t horizontal_offset = 3;
const size_t string_width = canvas_string_width(canvas, str);
const Icon* icon = &I_ButtonLeft_4x7;
const uint8_t icon_h_offset = 3;
const uint8_t icon_width_with_offset = icon->width + icon_h_offset;
const uint8_t icon_v_offset = icon->height + vertical_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const int32_t icon_h_offset = 3;
const int32_t icon_width_with_offset = icon->width + icon_h_offset;
const int32_t icon_v_offset = icon->height + vertical_offset;
const size_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = 0;
const uint8_t y = canvas_height(canvas);
const int32_t x = 0;
const int32_t y = canvas_height(canvas);
canvas_draw_box(canvas, x, y - button_height, button_width, button_height);
canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0);
@ -155,18 +161,18 @@ void elements_button_left(Canvas* canvas, const char* str) {
void elements_button_right(Canvas* canvas, const char* str) {
furi_check(canvas);
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 3;
const uint8_t string_width = canvas_string_width(canvas, str);
const size_t button_height = 12;
const size_t vertical_offset = 3;
const size_t horizontal_offset = 3;
const size_t string_width = canvas_string_width(canvas, str);
const Icon* icon = &I_ButtonRight_4x7;
const uint8_t icon_h_offset = 3;
const uint8_t icon_width_with_offset = icon->width + icon_h_offset;
const uint8_t icon_v_offset = icon->height + vertical_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const int32_t icon_h_offset = 3;
const int32_t icon_width_with_offset = icon->width + icon_h_offset;
const int32_t icon_v_offset = icon->height + vertical_offset;
const size_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = canvas_width(canvas);
const uint8_t y = canvas_height(canvas);
const int32_t x = canvas_width(canvas);
const int32_t y = canvas_height(canvas);
canvas_draw_box(canvas, x - button_width, y - button_height, button_width, button_height);
canvas_draw_line(canvas, x - button_width - 1, y, x - button_width - 1, y - button_height + 0);
@ -183,18 +189,18 @@ void elements_button_right(Canvas* canvas, const char* str) {
void elements_button_center(Canvas* canvas, const char* str) {
furi_check(canvas);
const uint8_t button_height = 12;
const uint8_t vertical_offset = 3;
const uint8_t horizontal_offset = 1;
const uint8_t string_width = canvas_string_width(canvas, str);
const size_t button_height = 12;
const size_t vertical_offset = 3;
const size_t horizontal_offset = 1;
const size_t string_width = canvas_string_width(canvas, str);
const Icon* icon = &I_ButtonCenter_7x7;
const uint8_t icon_h_offset = 3;
const uint8_t icon_width_with_offset = icon->width + icon_h_offset;
const uint8_t icon_v_offset = icon->height + vertical_offset;
const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const int32_t icon_h_offset = 3;
const int32_t icon_width_with_offset = icon->width + icon_h_offset;
const int32_t icon_v_offset = icon->height + vertical_offset;
const size_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
const uint8_t x = (canvas_width(canvas) - button_width) / 2;
const uint8_t y = canvas_height(canvas);
const int32_t x = (canvas_width(canvas) - button_width) / 2;
const int32_t y = canvas_height(canvas);
canvas_draw_box(canvas, x, y - button_height, button_width, button_height);
@ -214,7 +220,7 @@ void elements_button_center(Canvas* canvas, const char* str) {
}
static size_t
elements_get_max_chars_to_fit(Canvas* canvas, Align horizontal, const char* text, uint8_t x) {
elements_get_max_chars_to_fit(Canvas* canvas, Align horizontal, const char* text, int32_t x) {
const char* end = strchr(text, '\n');
if(end == NULL) {
end = text + strlen(text);
@ -225,10 +231,10 @@ static size_t
furi_string_left(str, text_size);
size_t result = 0;
uint16_t len_px = canvas_string_width(canvas, furi_string_get_cstr(str));
uint8_t px_left = 0;
size_t len_px = canvas_string_width(canvas, furi_string_get_cstr(str));
size_t px_left = 0;
if(horizontal == AlignCenter) {
if(x > (canvas_width(canvas) / 2)) {
if(x > (int32_t)(canvas_width(canvas) / 2)) {
px_left = (canvas_width(canvas) - x) * 2;
} else {
px_left = x * 2;
@ -261,16 +267,16 @@ static size_t
void elements_multiline_text_aligned(
Canvas* canvas,
uint8_t x,
uint8_t y,
int32_t x,
int32_t y,
Align horizontal,
Align vertical,
const char* text) {
furi_check(canvas);
furi_check(text);
uint8_t lines_count = 0;
uint8_t font_height = canvas_current_font_height(canvas);
size_t lines_count = 0;
size_t font_height = canvas_current_font_height(canvas);
FuriString* line;
/* go through text line by line and count lines */
@ -302,7 +308,7 @@ void elements_multiline_text_aligned(
canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, furi_string_get_cstr(line));
furi_string_free(line);
y += font_height;
if(y > canvas_height(canvas)) {
if(y > (int32_t)canvas_height(canvas)) {
break;
}
@ -311,11 +317,11 @@ void elements_multiline_text_aligned(
}
}
void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text) {
void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* text) {
furi_check(canvas);
furi_check(text);
uint8_t font_height = canvas_current_font_height(canvas);
size_t font_height = canvas_current_font_height(canvas);
FuriString* str;
str = furi_string_alloc();
const char* start = text;
@ -334,57 +340,53 @@ void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* t
furi_string_free(str);
}
void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const char* text) {
void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const char* text) {
furi_check(canvas);
furi_check(text);
uint8_t font_y = canvas_current_font_height(canvas);
uint16_t str_width = canvas_string_width(canvas, text);
size_t font_height = canvas_current_font_height(canvas);
size_t str_width = canvas_string_width(canvas, text);
// count \n's
uint8_t lines = 1;
size_t lines = 1;
const char* t = text;
while(*t != '\0') {
if(*t == '\n') {
lines++;
uint16_t temp_width = canvas_string_width(canvas, t + 1);
size_t temp_width = canvas_string_width(canvas, t + 1);
str_width = temp_width > str_width ? temp_width : str_width;
}
t++;
}
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, x, y - font_y, str_width + 8, font_y * lines + 4);
canvas_draw_box(canvas, x, y - font_height, str_width + 8, font_height * lines + 4);
canvas_set_color(canvas, ColorBlack);
elements_multiline_text(canvas, x + 4, y - 1, text);
elements_frame(canvas, x, y - font_y, str_width + 8, font_y * lines + 4);
elements_frame(canvas, x, y - font_height, str_width + 8, font_height * lines + 4);
}
void elements_slightly_rounded_frame(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height) {
int32_t x,
int32_t y,
size_t width,
size_t height) {
furi_check(canvas);
canvas_draw_rframe(canvas, x, y, width, height, 1);
}
void elements_slightly_rounded_box(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height) {
int32_t x,
int32_t y,
size_t width,
size_t height) {
furi_check(canvas);
canvas_draw_rbox(canvas, x, y, width, height, 1);
}
void elements_bold_rounded_frame(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height) {
void elements_bold_rounded_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height) {
furi_check(canvas);
canvas_set_color(canvas, ColorWhite);
@ -420,10 +422,10 @@ void elements_bold_rounded_frame(
canvas_draw_dot(canvas, x + width - 2, y + height - 3);
}
void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
void elements_bubble(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height) {
furi_check(canvas);
canvas_draw_rframe(canvas, x + 4, y, width, height, 3);
uint8_t y_corner = y + height * 2 / 3;
int32_t y_corner = y + height * 2 / 3;
canvas_draw_line(canvas, x, y_corner, x + 4, y_corner - 4);
canvas_draw_line(canvas, x, y_corner, x + 4, y_corner + 4);
canvas_set_color(canvas, ColorWhite);
@ -433,45 +435,46 @@ void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_
void elements_bubble_str(
Canvas* canvas,
uint8_t x,
uint8_t y,
int32_t x,
int32_t y,
const char* text,
Align horizontal,
Align vertical) {
furi_check(canvas);
furi_check(text);
uint8_t font_y = canvas_current_font_height(canvas);
uint16_t str_width = canvas_string_width(canvas, text);
size_t font_height = canvas_current_font_height(canvas);
size_t str_width = canvas_string_width(canvas, text);
// count \n's
uint8_t lines = 1;
size_t lines = 1;
const char* t = text;
while(*t != '\0') {
if(*t == '\n') {
lines++;
uint16_t temp_width = canvas_string_width(canvas, t + 1);
size_t temp_width = canvas_string_width(canvas, t + 1);
str_width = temp_width > str_width ? temp_width : str_width;
}
t++;
}
uint8_t frame_x = x;
uint8_t frame_y = y;
uint8_t frame_width = str_width + 8;
uint8_t frame_height = font_y * lines + 4;
int32_t frame_x = x;
int32_t frame_y = y;
size_t frame_width = str_width + 8;
size_t frame_height = font_height * lines + 4;
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, frame_x + 1, frame_y + 1, frame_width - 2, frame_height - 2);
canvas_set_color(canvas, ColorBlack);
canvas_draw_rframe(canvas, frame_x, frame_y, frame_width, frame_height, 1);
elements_multiline_text(canvas, x + 4, y - 1 + font_y, text);
elements_multiline_text(canvas, x + 4, y - 1 + font_height, text);
uint8_t x1 = 0;
uint8_t x2 = 0;
uint8_t x3 = 0;
uint8_t y1 = 0;
uint8_t y2 = 0;
uint8_t y3 = 0;
int32_t x1 = 0;
int32_t x2 = 0;
int32_t x3 = 0;
int32_t y1 = 0;
int32_t y2 = 0;
int32_t y3 = 0;
if((horizontal == AlignLeft) && (vertical == AlignTop)) {
x1 = frame_x;
y1 = frame_y;
@ -565,11 +568,11 @@ void elements_bubble_str(
canvas_draw_line(canvas, x2, y2, x3, y3);
}
void elements_string_fit_width(Canvas* canvas, FuriString* string, uint8_t width) {
void elements_string_fit_width(Canvas* canvas, FuriString* string, size_t width) {
furi_check(canvas);
furi_check(string);
uint16_t len_px = canvas_string_width(canvas, furi_string_get_cstr(string));
size_t len_px = canvas_string_width(canvas, furi_string_get_cstr(string));
if(len_px > width) {
width -= canvas_string_width(canvas, "...");
do {
@ -640,9 +643,9 @@ void elements_scrollable_text_line_str(
void elements_scrollable_text_line(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
int32_t x,
int32_t y,
size_t width,
FuriString* string,
size_t scroll,
bool ellipsis) {
@ -690,10 +693,10 @@ void elements_scrollable_text_line(
void elements_text_box(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
int32_t x,
int32_t y,
size_t width,
size_t height,
Align horizontal,
Align vertical,
const char* text,
@ -710,18 +713,18 @@ void elements_text_box(
const CanvasFontParameters* font_params = canvas_get_font_params(canvas, current_font);
// Fill line parameters
uint8_t line_leading_min = font_params->leading_min;
uint8_t line_leading_default = font_params->leading_default;
uint8_t line_height = font_params->height;
uint8_t line_descender = font_params->descender;
uint8_t line_num = 0;
uint8_t line_width = 0;
uint8_t line_len = 0;
uint8_t total_height_min = 0;
uint8_t total_height_default = 0;
uint16_t i = 0;
size_t line_leading_min = font_params->leading_min;
size_t line_leading_default = font_params->leading_default;
size_t line_height = font_params->height;
size_t line_descender = font_params->descender;
size_t line_num = 0;
size_t line_width = 0;
size_t line_len = 0;
size_t total_height_min = 0;
size_t total_height_default = 0;
size_t i = 0;
bool full_text_processed = false;
uint16_t dots_width = canvas_string_width(canvas, "...");
size_t dots_width = canvas_string_width(canvas, "...");
canvas_set_font(canvas, FontSecondary);
@ -823,14 +826,14 @@ void elements_text_box(
line[0].y = y + line[0].height + (height - total_height_default);
}
if(line_num > 1) {
for(uint8_t i = 1; i < line_num; i++) {
for(size_t i = 1; i < line_num; i++) {
line[i].y = line[i - 1].y + line[i - 1].leading_default;
}
}
} else if(line_num > 1) {
uint8_t free_pixel_num = height - total_height_min;
uint8_t fill_pixel = 0;
uint8_t j = 1;
size_t free_pixel_num = height - total_height_min;
size_t fill_pixel = 0;
size_t j = 1;
line[0].y = y + line[0].height;
while(fill_pixel < free_pixel_num) {
line[j].y = line[j - 1].y + line[j - 1].leading_min + 1;
@ -844,8 +847,8 @@ void elements_text_box(
bold = false;
mono = false;
inverse = false;
for(uint8_t i = 0; i < line_num; i++) {
for(uint8_t j = 0; j < line[i].len; j++) {
for(size_t i = 0; i < line_num; i++) {
for(size_t j = 0; j < line[i].len; j++) {
// Process format symbols
if(line[i].text[j] == ELEMENTS_BOLD_MARKER) {
if(bold) {
@ -883,8 +886,9 @@ void elements_text_box(
canvas_invert_color(canvas);
} else {
if((i == line_num - 1) && strip_to_dots) {
uint8_t next_symbol_width = canvas_glyph_width(canvas, line[i].text[j]);
if(line[i].x + next_symbol_width + dots_width > x + width) {
size_t next_symbol_width = canvas_glyph_width(canvas, line[i].text[j]);
if((line[i].x + (int32_t)next_symbol_width + (int32_t)dots_width) >
(x + (int32_t)width)) {
canvas_draw_str(canvas, line[i].x, line[i].y, "...");
break;
}

View File

@ -29,7 +29,7 @@ extern "C" {
* @param width progress bar width
* @param progress progress (0.0 - 1.0)
*/
void elements_progress_bar(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, float progress);
void elements_progress_bar(Canvas* canvas, int32_t x, int32_t y, size_t width, float progress);
/** Draw progress bar with text.
*
@ -42,9 +42,9 @@ void elements_progress_bar(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width,
*/
void elements_progress_bar_with_text(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
int32_t x,
int32_t y,
size_t width,
float progress,
const char* text);
@ -59,11 +59,11 @@ void elements_progress_bar_with_text(
*/
void elements_scrollbar_pos(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t height,
uint16_t pos,
uint16_t total);
int32_t x,
int32_t y,
size_t height,
size_t pos,
size_t total);
/** Draw scrollbar on canvas.
* @note width 3px, height equal to canvas height
@ -72,7 +72,7 @@ void elements_scrollbar_pos(
* @param pos current element of total elements
* @param total total elements
*/
void elements_scrollbar(Canvas* canvas, uint16_t pos, uint16_t total);
void elements_scrollbar(Canvas* canvas, size_t pos, size_t total);
/** Draw rounded frame
*
@ -80,7 +80,7 @@ void elements_scrollbar(Canvas* canvas, uint16_t pos, uint16_t total);
* @param x, y top left corner coordinates
* @param width, height frame width and height
*/
void elements_frame(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
void elements_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height);
/** Draw button in left corner
*
@ -112,8 +112,8 @@ void elements_button_center(Canvas* canvas, const char* str);
*/
void elements_multiline_text_aligned(
Canvas* canvas,
uint8_t x,
uint8_t y,
int32_t x,
int32_t y,
Align horizontal,
Align vertical,
const char* text);
@ -124,7 +124,7 @@ void elements_multiline_text_aligned(
* @param x, y top left corner coordinates
* @param text string (possible multiline)
*/
void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* text);
void elements_multiline_text(Canvas* canvas, int32_t x, int32_t y, const char* text);
/** Draw framed multiline text
*
@ -132,7 +132,7 @@ void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* t
* @param x, y top left corner coordinates
* @param text string (possible multiline)
*/
void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const char* text);
void elements_multiline_text_framed(Canvas* canvas, int32_t x, int32_t y, const char* text);
/** Draw slightly rounded frame
*
@ -142,10 +142,10 @@ void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const
*/
void elements_slightly_rounded_frame(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height);
int32_t x,
int32_t y,
size_t width,
size_t height);
/** Draw slightly rounded box
*
@ -155,10 +155,10 @@ void elements_slightly_rounded_frame(
*/
void elements_slightly_rounded_box(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height);
int32_t x,
int32_t y,
size_t width,
size_t height);
/** Draw bold rounded frame
*
@ -166,12 +166,7 @@ void elements_slightly_rounded_box(
* @param x, y top left corner coordinates
* @param width, height size of frame
*/
void elements_bold_rounded_frame(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height);
void elements_bold_rounded_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height);
/** Draw bubble frame for text
*
@ -181,7 +176,7 @@ void elements_bold_rounded_frame(
* @param width bubble width
* @param height bubble height
*/
void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height);
void elements_bubble(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height);
/** Draw bubble frame for text with corner
*
@ -194,8 +189,8 @@ void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_
*/
void elements_bubble_str(
Canvas* canvas,
uint8_t x,
uint8_t y,
int32_t x,
int32_t y,
const char* text,
Align horizontal,
Align vertical);
@ -206,7 +201,7 @@ void elements_bubble_str(
* @param string string to trim
* @param width max width
*/
void elements_string_fit_width(Canvas* canvas, FuriString* string, uint8_t width);
void elements_string_fit_width(Canvas* canvas, FuriString* string, size_t width);
/** Draw scrollable text line
*
@ -220,9 +215,9 @@ void elements_string_fit_width(Canvas* canvas, FuriString* string, uint8_t width
*/
void elements_scrollable_text_line(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
int32_t x,
int32_t y,
size_t width,
FuriString* string,
size_t scroll,
bool ellipsis);
@ -254,10 +249,10 @@ void elements_scrollable_text_line_str(
*/
void elements_text_box(
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height,
int32_t x,
int32_t y,
size_t width,
size_t height,
Align horizontal,
Align vertical,
const char* text,

View File

@ -432,7 +432,7 @@ static void browser_list_item_cb(
uint32_t idx,
bool is_folder,
bool is_last) {
furi_assert(context);
furi_check(context);
FileBrowser* browser = (FileBrowser*)context;
BrowserItem_t item;

View File

@ -100,7 +100,7 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
line_num++;
model->text = furi_string_get_cstr(model->text_formatted);
model->text_pos = (char*)model->text;
uint8_t lines_on_screen = 56 / canvas_current_font_height(canvas);
size_t lines_on_screen = 56 / canvas_current_font_height(canvas);
if(model->focus == TextBoxFocusEnd && line_num > lines_on_screen) {
// Set text position to 5th line from the end
const char* end = model->text + furi_string_size(model->text_formatted);

View File

@ -94,8 +94,9 @@ void view_holder_start(ViewHolder* view_holder);
void view_holder_stop(ViewHolder* view_holder);
/** View Update Handler
* @param view, View Instance
* @param context, ViewHolder instance
*
* @param view View Instance
* @param context ViewHolder instance
*/
void view_holder_update(View* view, void* context);

View File

@ -142,7 +142,7 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
}
}
submenu_set_header(submenu, is_dummy_app ? ("Dummy Mode app:") : ("Favorite app:"));
submenu_set_header(submenu, is_dummy_app ? ("Dummy Mode App") : ("Favorite App"));
submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch.
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);

View File

@ -25,7 +25,7 @@ void desktop_settings_scene_pin_disable_on_enter(void* context) {
popup_set_context(app->popup, app);
popup_set_callback(app->popup, pin_disable_back_callback);
popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_119x62);
popup_set_header(app->popup, "Deleted", 80, 19, AlignLeft, AlignBottom);
popup_set_header(app->popup, "PIN\nDeleted!", 100, 0, AlignCenter, AlignTop);
popup_set_timeout(app->popup, 1500);
popup_enable_timeout(app->popup);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);

View File

@ -22,7 +22,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
if(!app->settings.pin_code.length) {
submenu_add_item(
submenu,
"Set Pin",
"Set PIN",
SCENE_EVENT_SET_PIN,
desktop_settings_scene_pin_menu_submenu_callback,
app);
@ -30,7 +30,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
} else {
submenu_add_item(
submenu,
"Change Pin",
"Change PIN",
SCENE_EVENT_CHANGE_PIN,
desktop_settings_scene_pin_menu_submenu_callback,
app);
@ -43,7 +43,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
app);
}
submenu_set_header(app->submenu, "Pin code settings:");
submenu_set_header(app->submenu, "PIN Code Settings");
submenu_set_selected_item(app->submenu, app->menu_idx);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
}

View File

@ -34,7 +34,7 @@ void desktop_settings_scene_pin_setup_done_on_enter(void* context) {
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback);
desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code);
desktop_view_pin_input_set_label_button(app->pin_input_view, "Done");
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN activated!");
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN Activated!");
desktop_view_pin_input_set_label_secondary(
app->pin_input_view, 7, 45, "Remember or write it down");
desktop_view_pin_input_lock_input(app->pin_input_view);

View File

@ -23,7 +23,7 @@ static void desktop_settings_view_pin_setup_howto_draw(Canvas* canvas, void* mod
elements_button_right(canvas, "Next");
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Setting up PIN");
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Setting Up PIN");
canvas_set_font(canvas, FontSecondary);
elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols");

View File

@ -10,7 +10,7 @@ void power_settings_scene_power_off_on_enter(void* context) {
PowerSettingsApp* app = context;
DialogEx* dialog = app->dialog;
dialog_ex_set_header(dialog, "Turn Off Device?", 64, 2, AlignCenter, AlignTop);
dialog_ex_set_header(dialog, "Turn OFF Device?", 64, 2, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52);

View File

@ -15,10 +15,10 @@ void power_settings_scene_reboot_on_enter(void* context) {
PowerSettingsApp* app = context;
Submenu* submenu = app->submenu;
submenu_set_header(submenu, "Reboot type");
submenu_set_header(submenu, "Reboot Type");
submenu_add_item(
submenu,
"Firmware upgrade",
"Firmware Upgrade",
PowerSettingsRebootSubmenuIndexDfu,
power_settings_scene_reboot_submenu_callback,
app);

View File

@ -1,4 +1,4 @@
# Doxyfile 1.9.2
# Doxyfile 1.10.0
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -12,6 +12,16 @@
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
#
# Note:
#
# Use doxygen to compare the used configuration file with the template
# configuration file:
# doxygen -x [configFile]
# Use doxygen to compare the used configuration file with the template
# configuration file without replacing the environment variables or CMake type
# replacement variables:
# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
# Project related configuration options
@ -51,25 +61,43 @@ PROJECT_BRIEF =
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
PROJECT_LOGO = $(DOXY_CONFIG_DIR)/logo.png
# With the PROJECT_ICON tag one can specify an icon that is included in the tabs
# when the HTML document is shown. Doxygen will copy the logo to the output
# directory.
PROJECT_ICON = $(DOXY_CONFIG_DIR)/favicon.ico
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = documentation
OUTPUT_DIRECTORY = $(DOXY_CONFIG_DIR)/build
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# sub-directories (in 2 levels) under the output directory of each output format
# and will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
# control the number of sub-directories.
# The default value is: NO.
CREATE_SUBDIRS = NO
# Controls the number of sub-directories that will be created when
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
# level increment doubles the number of directories, resulting in 4096
# directories at level 8 which is the default and also the maximum value. The
# sub-directories are organized in 2 levels, the first level always has a fixed
# number of 16 directories.
# Minimum value: 0, maximum value: 8, default value: 8.
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
CREATE_SUBDIRS_LEVEL = 8
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
# Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
@ -341,13 +369,24 @@ MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
# generate identifiers for the Markdown headings. Note: Every identifier is
# unique.
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
# sequence number starting at 0 and GITHUB use the lower case version of title
# with any whitespace replaced by '-' and punctuation characters removed.
# The default value is: DOXYGEN.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
MARKDOWN_ID_STYLE = DOXYGEN
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
AUTOLINK_SUPPORT = NO
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this
@ -452,7 +491,7 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
@ -465,6 +504,14 @@ LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
# If the TIMESTAMP tag is set different from NO then each generated page will
# contain the date or date and time when the page was generated. Setting this to
# NO can help when comparing the output of multiple runs.
# Possible values are: YES, NO, DATETIME and DATE.
# The default value is: NO.
TIMESTAMP = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -546,7 +593,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# will also hide undocumented C++ concepts if enabled. This option has no effect
# if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
@ -577,14 +625,15 @@ INTERNAL_DOCS = NO
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# are not case sensitive the option should be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
# Possible values are: SYSTEM, NO and YES.
# The default value is: SYSTEM.
CASE_SENSE_NAMES = NO
@ -793,7 +842,7 @@ CITE_BIB_FILES =
# messages are off.
# The default value is: NO.
QUIET = NO
QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
@ -809,7 +858,7 @@ WARNINGS = YES
# will automatically be disabled.
# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
WARN_IF_UNDOCUMENTED = NO
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as documenting some parameters in
@ -834,16 +883,31 @@ WARN_IF_INCOMPLETE_DOC = YES
# WARN_IF_INCOMPLETE_DOC
# The default value is: NO.
WARN_NO_PARAMDOC = NO
WARN_NO_PARAMDOC = YES
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
# undocumented enumeration values. If set to NO, doxygen will accept
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: NO.
WARN_IF_UNDOC_ENUM_VAL = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
# write the warning messages in between other messages but write them at the end
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
# besides being in the defined file also be shown at the end of a run, unless
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
# The default value is: NO.
WARN_AS_ERROR = NO
WARN_AS_ERROR = FAIL_ON_WARNINGS
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
@ -851,13 +915,27 @@ WARN_AS_ERROR = NO
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
# In the $text part of the WARN_FORMAT command it is possible that a reference
# to a more specific place is given. To make it easier to jump to this place
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
# Example:
# WARN_LINE_FORMAT = "'vi $file +$line'"
# See also: WARN_FORMAT
# The default value is: at line $line of file $file.
WARN_LINE_FORMAT = "at line $line of file $file"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr).
# error (stderr). In case the file specified cannot be opened for writing the
# warning and error messages are written to standard error. When as file - is
# specified the warning and error messages are written to standard output
# (stdout).
WARN_LOGFILE =
@ -871,20 +949,34 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = applications \
lib \
firmware \
furi
INPUT = $(DOXY_SRC_ROOT)/applications \
$(DOXY_SRC_ROOT)/documentation \
$(DOXY_SRC_ROOT)/targets \
$(DOXY_SRC_ROOT)/assets \
$(DOXY_SRC_ROOT)/lib \
$(DOXY_SRC_ROOT)/furi \
$(DOXY_SRC_ROOT)/.vscode
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# This tag can be used to specify the character encoding of the source files
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
# character encoding on a per file pattern basis. Doxygen will compare the file
# name with each pattern and apply the encoding instead of the default
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
# "INPUT_ENCODING" for further information on supported encodings.
INPUT_FILE_ENCODING =
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@ -896,12 +988,12 @@ INPUT_ENCODING = UTF-8
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice.
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
@ -927,19 +1019,45 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE = \
lib/mlib \
lib/stm32wb_cmsis \
lib/stm32wb_copro \
lib/stm32wb_hal_driver \
lib/littlefs \
lib/nanopb \
assets/protobuf \
lib/libusb_stm32 \
lib/FreeRTOS-Kernel \
lib/microtar \
lib/mbedtls \
lib/cxxheaderparser
EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \
$(DOXY_SRC_ROOT)/lib/STM32CubeWB \
$(DOXY_SRC_ROOT)/lib/littlefs \
$(DOXY_SRC_ROOT)/lib/nanopb \
$(DOXY_SRC_ROOT)/assets/protobuf \
$(DOXY_SRC_ROOT)/lib/libusb_stm32 \
$(DOXY_SRC_ROOT)/lib/FreeRTOS-Kernel \
$(DOXY_SRC_ROOT)/lib/microtar \
$(DOXY_SRC_ROOT)/lib/mbedtls \
$(DOXY_SRC_ROOT)/lib/cxxheaderparser \
$(DOXY_SRC_ROOT)/lib/ST25RFAL002 \
$(DOXY_SRC_ROOT)/lib/fatfs \
$(DOXY_SRC_ROOT)/lib/mlib \
$(DOXY_SRC_ROOT)/lib/stm32wb_cmsis \
$(DOXY_SRC_ROOT)/lib/stm32wb_copro \
$(DOXY_SRC_ROOT)/lib/stm32wb_hal_driver \
$(DOXY_SRC_ROOT)/lib/stm32wb_hal \
$(DOXY_SRC_ROOT)/lib/cmsis_core \
$(DOXY_SRC_ROOT)/targets/f7/fatfs/ \
$(DOXY_SRC_ROOT)/applications/plugins/dap_link/lib/free-dap \
$(DOXY_SRC_ROOT)/applications/debug \
$(DOXY_SRC_ROOT)/applications/main \
$(DOXY_SRC_ROOT)/applications/settings \
$(DOXY_SRC_ROOT)/lib/micro-ecc \
$(DOXY_SRC_ROOT)/lib/ReadMe.md \
$(DOXY_SRC_ROOT)/lib/callback-connector \
$(DOXY_SRC_ROOT)/lib/app-scened-template \
$(DOXY_SRC_ROOT)/applications/ReadMe.md \
$(DOXY_SRC_ROOT)/targets/ReadMe.md \
$(DOXY_SRC_ROOT)/web \
$(DOXY_SRC_ROOT)/assets/protobuf \
$(DOXY_SRC_ROOT)/lib/libusb_stm32 \
$(DOXY_SRC_ROOT)/lib/FreeRTOS-Kernel \
$(DOXY_SRC_ROOT)/lib/microtar \
$(DOXY_SRC_ROOT)/lib/mbedtls \
$(DOXY_SRC_ROOT)/lib/cxxheaderparser \
$(DOXY_SRC_ROOT)/applications/external/dap_link/lib/free-dap \
$(DOXY_SRC_ROOT)/lib/heatshrink \
$(DOXY_CONFIG_DIR)/doxygen-awesome-css
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@ -961,10 +1079,7 @@ EXCLUDE_PATTERNS =
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
# ANamespace::AClass, ANamespace::*Test
EXCLUDE_SYMBOLS =
@ -1009,6 +1124,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
# Note that doxygen will use the data processed and written to standard output
# for further processing, therefore nothing else, like debug statements or used
# commands (so in case of a Windows batch file always use @echo OFF), should be
# written to standard output.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@ -1050,6 +1170,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
# The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common
# extension is to allow longer lines before the automatic comment starts. The
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
# be processed before the automatic comment starts.
# Minimum value: 7, maximum value: 10000, default value: 72.
FORTRAN_COMMENT_AFTER = 72
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
@ -1064,7 +1193,8 @@ USE_MDFILE_AS_MAINPAGE =
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# multi-line macros, enums or list initialized variables directly into the
# documentation.
# The default value is: NO.
INLINE_SOURCES = NO
@ -1147,10 +1277,11 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
# that should be ignored while generating the index headers. The IGNORE_PREFIX
# tag works for classes, function and member names. The entity will be placed in
# the alphabetical list under the first letter of the entity name that remains
# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@ -1229,7 +1360,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# list).
# Note: Since the styling of scrollbars can currently not be overruled in
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
# one or more extra stylesheets have been specified. So if scrollbar
# customization is desired it has to be added explicitly. For an example see the
# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@ -1244,6 +1380,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
# should be rendered with a dark or light theme.
# Possible values are: LIGHT always generate light mode output, DARK always
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
# the user preference, use light mode if no preference is set (the default),
# AUTO_DARK automatically set the mode according to the user preference, use
# dark mode if no preference is set and TOGGLE allow to user to switch between
# light and dark mode via a button.
# The default value is: AUTO_LIGHT.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE = AUTO_LIGHT
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
@ -1274,15 +1423,6 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
@ -1302,6 +1442,33 @@ HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
# dynamically folded and expanded in the generated HTML source code.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_CODE_FOLDING = YES
# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in
# the top right corner of code and text fragments that allows the user to copy
# its content to the clipboard. Note this only works if supported by the browser
# and the web page is served via a secure context (see:
# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file:
# protocol.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COPY_CLIPBOARD = YES
# Doxygen stores a couple of settings persistently in the browser (via e.g.
# cookies). By default these settings apply to all HTML pages generated by
# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store
# the settings under a project specific key, such that the user preferences will
# be stored separately.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_PROJECT_COOKIE =
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
@ -1338,6 +1505,13 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
# This tag determines the URL of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDURL =
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@ -1425,6 +1599,16 @@ BINARY_TOC = NO
TOC_EXPAND = NO
# The SITEMAP_URL tag is used to specify the full URL of the place where the
# generated documentation will be placed on the server by the user during the
# deployment of the documentation. The generated sitemap is called sitemap.xml
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
# is specified no sitemap is generated. For information about the sitemap
# protocol see https://www.sitemaps.org
# This tag requires that the tag GENERATE_HTML is set to YES.
SITEMAP_URL =
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@ -1542,7 +1726,7 @@ GENERATE_TREEVIEW = NO
# area (value NO) or if it should extend to the full height of the window (value
# YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the
# project logo, title, and description. If either GENERATOR_TREEVIEW or
# project logo, title, and description. If either GENERATE_TREEVIEW or
# DISABLE_INDEX is set to NO, this option has no effect.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1573,6 +1757,13 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
# addresses.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
OBFUSCATE_EMAILS = YES
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
@ -1593,17 +1784,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
@ -1665,8 +1845,8 @@ MATHJAX_RELPATH =
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
# #tex-and-latex-extensions):
# for MathJax version 2 (see
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# For example for MathJax version 3 (see
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
@ -1917,9 +2097,16 @@ PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help.
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
# hit at every error; missing files that TeX tries to input or request from
# keyboard input (\read on a not open input stream) cause the job to abort,
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
# but there is no possibility of user interaction just like in batch mode,
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
# each error, asking for user intervention.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1940,14 +2127,6 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
@ -2113,13 +2292,39 @@ DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
# database with symbols found by doxygen stored in tables.
# The default value is: NO.
GENERATE_SQLITE3 = NO
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
# in front of it.
# The default directory is: sqlite3.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_OUTPUT = sqlite3
# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db
# database file will be recreated with each doxygen run. If set to NO, doxygen
# will warn if a database file is already found and not modify it.
# The default value is: YES.
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
SQLITE3_RECREATE_DB = YES
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
@ -2194,7 +2399,8 @@ SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
# preprocessor.
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
# RECURSIVE has no effect here.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
@ -2261,15 +2467,15 @@ TAGFILES =
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
# will be listed in the class and namespace index. If set to NO, only the
# inherited external classes will be listed.
# The default value is: NO.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# in the topic index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
@ -2283,25 +2489,9 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@ -2310,7 +2500,7 @@ HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
@ -2327,49 +2517,77 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# subgraphs. When you want a differently looking font in the dot files that
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
# Edge and Graph Attributes specification</a> You need to make sure dot is able
# to find the font, which can be done by putting it in a standard location or by
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font. Default graphviz fontsize is 14.
# The default value is: fontname=Helvetica,fontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
# arrows shapes.</a>
# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag.
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# around nodes set 'shape=plain' or 'shape=plaintext' <a
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
# You can set the path where dot can find font specified with fontname in
# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
# generate a graph for each documented class showing the direct and indirect
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
# relations will be shown as texts / links. Explicit enabling an inheritance
# graph or choosing a different representation for an inheritance graph of a
# specific class, can be accomplished by means of the command \inheritancegraph.
# Disabling an inheritance graph can be accomplished by means of the command
# \hideinheritancegraph.
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
# graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the
# class with other documented classes.
# class with other documented classes. Explicit enabling a collaboration graph,
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
# command \collaborationgraph. Disabling a collaboration graph can be
# accomplished by means of the command \hidecollaborationgraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
# groups, showing the direct groups dependencies.
# groups, showing the direct groups dependencies. Explicit enabling a group
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
# of the command \groupgraph. Disabling a directory graph can be accomplished by
# means of the command \hidegroupgraph. See also the chapter Grouping in the
# manual.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2411,8 +2629,8 @@ DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# significantly it will be wrapped across multiple lines. Some heuristics are
# applied to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2429,7 +2647,9 @@ TEMPLATE_RELATIONS = NO
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
# can be accomplished by means of the command \includegraph. Disabling an
# include graph can be accomplished by means of the command \hideincludegraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2438,7 +2658,10 @@ INCLUDE_GRAPH = YES
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
# set to YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other documented
# files.
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
# an included by graph can be accomplished by means of the command
# \hideincludedbygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2478,16 +2701,26 @@ GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between the
# files in the directories.
# files in the directories. Explicit enabling a directory graph, when
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
# \directorygraph. Disabling a directory graph can be accomplished by means of
# the command \hidedirectorygraph.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
# of child directories generated in directory dependency graphs by dot.
# Minimum value: 1, maximum value: 25, default value: 1.
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
DIR_GRAPH_MAX_DEPTH = 1
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# https://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
@ -2524,11 +2757,12 @@ DOT_PATH =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
MSCFILE_DIRS =
DIA_PATH =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
@ -2537,10 +2771,10 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
# path where java can find the plantuml.jar file or to the filename of jar file
# to be used. If left blank, it is assumed PlantUML is not used or called during
# a preprocessing step. Doxygen will generate a warning when it encounters a
# \startuml command in this case and will not generate output for the diagram.
PLANTUML_JAR_PATH =
@ -2578,18 +2812,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
@ -2602,6 +2824,8 @@ DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
# graphical representation for inheritance and collaboration diagrams is used.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
@ -2615,3 +2839,19 @@ GENERATE_LEGEND = YES
# The default value is: YES.
DOT_CLEANUP = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
# use a built-in version of mscgen tool to produce the charts. Alternatively,
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
# specifying prog as the value, doxygen will call the tool as prog -T
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
# output file formats "png", "eps", "svg", and "ismap".
MSCGEN_TOOL =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =

View File

@ -1,77 +1,30 @@
# Firmware update on Developer Board {#dev_board_fw_update}
It's important to regularly update your Developer Board to keep it up to date. This tutorial will guide you through the necessary steps to successfully update the firmware of your Developer Board.
It's important to regularly update your Developer Board to ensure that you have access to the latest features and bug fixes. This tutorial will guide you through the necessary steps to update the firmware of your Developer Board.
This tutorial assumes that you're familiar with the basics of the command line. If youre unfamiliar with the command line, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials.
This tutorial assumes that you're familiar with the basics of the command line. If youre not, please refer to the [Windows](https://www.digitalcitizen.life/command-prompt-how-use-basic-commands/) or [MacOS/Linux](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) command line tutorials.
***
## Downloading the latest firmware
## Installing the micro Flipper Build Tool
The first thing you need to do is to download the latest Developer Board firmware.
Micro Flipper Build Tool (uFBT) is a cross-platform tool that enables basic development tasks for Flipper Zero, such as building and debugging applications, flashing firmware, and creating VS Code development configurations.
To get the latest pre-built firmware, do the following:
Install uFBT on your computer by running the following command in the Terminal:
1. Go to the [Update Server page](https://update.flipperzero.one/builds/blackmagic-firmware).
![The Update Server page hosts different versions of the Developer Board firmware](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/gIXVO9VrE4LK05CmcMSSD_monosnap-miro-2023-07-19-17-36-23.jpg)
There, you can find the following version of the Developer Board firmware:
* **Release:** The most stable version of the firmware, which went through rigorous testing. The Release firmware version has the following format: **X.Y.Z/**, where X, Y, and Z are the build numbers. We recommend installing this version of the firmware.
* **Release-candidate:** The firmware version that hasn't been tested yet and may contain bugs. The Release-candidate firmware version has the following format: **X.Y.Z-rc/**, where X, Y, and Z are the build numbers.
* **Development:** The firmware version which builds every day and contains the latest features but might be unstable.
2. Open the folder with the latest Release firmware and download the `blackmagic-firmware-s2-full-X.Y.Z.tgz` file.
***
## Extracting the firmware
After downloading the firmware archive, extract it into a folder:
* On Windows, you can use any archive manager for this, for example, [7-Zip](https://www.7-zip.org/).
* On MacOS and Linux, you can use the `tar` command:
```text
tar -xzf blackmagic-firmware-s2-full-X.Y.Z.tgz -C <destination_directory>
```
Don't forget to replace `X.Y.Z` with the actual version number and set the destination directory!
***
## Installing the prerequisites for flashing
Install the tools below if you haven't already.
### Python
Download and install [Python3](https://www.python.org/downloads/). Make sure to check the “Add Python to PATH” option during installation.
### pip
To install the pip package manager, run the following command in the Terminal:
**For Linux & macOS:**
```text
python3 -m ensurepip --upgrade
python3 -m pip install --upgrade ufbt
```
If this command fails, please refer to the [official pip documentation](https://pip.pypa.io/en/stable/installation/) for alternative installation methods.
### esptool
esptool is a command-line utility for flashing ESP8266 and ESP32 microcontrollers, including the ESP32-S2 in your Developer Board.
To install esptool, run the following command in the Terminal:
**For Windows:**
```text
pip3 install esptool
py -m pip install --upgrade ufbt
```
If this command fails, try using **pip** instead of **pip3**. If this didnt help, please refer to the [official esptool installation manual](https://docs.espressif.com/projects/esptool/en/latest/esp32/installation.html).
If you want to learn more about uFBT, visit [the project's page](https://pypi.org/project/ufbt/).
***
@ -79,38 +32,38 @@ If this command fails, try using **pip** instead of **pip3**. If this didnt h
1. List all of the serial devices on your computer.
* ***Windows***
**Windows**
On Windows, go to Device Manager and expand the Ports (COM & LPT) section.
On Windows, go to Device Manager and expand the Ports (COM & LPT) section.
* ***macOS***
**macOS**
On macOS, you can run the following command in the Terminal:
On macOS, you can run the following command in the Terminal:
```text
ls /dev/cu.*
```
```text
ls /dev/cu.*
```
* ***Linux***
**Linux**
On Linux, you can run the following command in the Terminal:
On Linux, you can run the following command in the Terminal:
```text
ls /dev/tty*
```
```text
ls /dev/tty*
```
View the devices in the list.
2. Connect the Developer Board to your computer using a USB-C cable.\
2. Connect the Developer Board to your computer using a USB-C cable.
![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/Aq7gfMI-m_5H6sGGjwb4I_monosnap-miro-2023-07-19-19-47-39.jpg)
3. Switch your Developer Board to Bootloader mode:
3.1. Press and hold the **BOOT** button.
3.2. Press the **RESET** button while holding the **BOOT** button.
3.3. Release the **BOOT** button.
3.1. Press and hold the **BOOT** button.
3.2. Press the **RESET** button while holding the **BOOT** button.
3.3. Release the **BOOT** button.\
![You can easily switch the Dev Board to Bootloader mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KynP9iT6sJ3mXLaLyI82__image.png)
4. Repeat Step 1 and view the name of your Developer Board that appeared in the list.
@ -125,103 +78,23 @@ If this command fails, try using **pip** instead of **pip3**. If this didnt h
## Flashing the firmware
### Getting the flash command
To flash the firmware onto your Developer Board, run the following command in the terminal:
1. Run the Terminal and navigate to the folder with the extracted firmware.
```text
python3 -m ufbt devboard_flash
```
2. Run the following command to read the file with the flash command:
You should see the following message: `WiFi board flashed successfully`.
```text
cat flash.command
```
## If flashing failed
If you see a similar output, you can proceed to the Flashing step:
```text
esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip esp32s2 write_flash --flash_mode dio --flash_freq 80m --flash_size 4MB 0x1000 bootloader.bin 0x10000 blackmagic.bin 0x8000 partition-table.bin
```
Don't use the exact command above for your Developer Board in the next step since it's just an example and may not match your firmware version!
If you get an error, ensure youre in the correct directory and extracted the firmware archive correctly.
***
### Flashing
1. Copy the command you got from the previous step and replace the `(PORT)` part with the name of the serial device you learned earlier.
For Windows, replace `(PORT)` with the COM port number—for example, `COM3`.
2. Run the command in the Terminal.
Your command should look similar to this:
```text
esptool.py -p /dev/cu.usbmodem01 -b 460800 --before default_reset --after hard_reset --chip esp32s2 write_flash --flash_mode dio --flash_freq 80m --flash_size 4MB 0x1000 bootloader.bin 0x10000 blackmagic.bin 0x8000 partition-table.bin
```
If you get an error, ensure that youve entered the correct serial device name and that the Developer Board is in Bootloader mode.
3. Wait till the firmware flashing is over. The flashing process takes about 30 seconds.
The Terminal output should look similar to this:
```text
esptool.py v4.6.1
Serial port /dev/cu.usbmodem01
Connecting...
Chip is ESP32-S2 (revision v0.0)
Features: WiFi, No Embedded Flash, No Embedded PSRAM, ADC and temperature sensor
calibration in BLK2 of efuse V2
Crystal is 40MHz
MAC: 00:11:22:33:44:55
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00004fff...
Flash will be erased from 0x00010000 to 0x000ecfff...
Flash will be erased from 0x00008000 to 0x00008fff...
Compressed 13248 bytes to 9298...
Wrote 13248 bytes (9298 compressed) at 0x00001000 in 0.3 seconds (effective 402.7 kbit/s)...
Hash of data verified.
Compressed 904288 bytes to 562550...
Wrote 904288 bytes (562550 compressed) at 0x00010000 in 6.7 seconds (effective 1076.5 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 124...
Wrote 3072 bytes (124 compressed) at 0x00008000 in 0.1 seconds (effective 360.8 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
```
If the Terminal output has these two lines at the end, your Developer Board has been successfully updated:
```text
Leaving...
Hard resetting via RTS pin...
```
If you get this warning, you can safely ignore it:
```text
WARNING: ESP32-S2 (revision v0.0) chip was placed into download mode using GPIO0.
esptool.py can not exit the download mode over USB. To run the app, reset the chip manually.
To suppress this note, set --after option to 'no_reset
```
#### If flashing failed
If you get an error message during the flashing process, such as:
If you get an error message during the flashing process, such as this:
```text
A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.
```
or
Or this:
```text
FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01'
@ -239,8 +112,11 @@ Try doing the following:
## Finishing the installation
After flashing the firmware, you can reboot the Developer Board by pressing the **RESET** button.
After flashing the firmware:
1. Reboot the Developer Board by pressing the **RESET** button.
![Reset the Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/rcQeKARgrVwa51tLoo-qY_monosnap-miro-2023-07-20-18-29-33.jpg)
2. Disconnect and reconnect the USB-C cable.
The Developer Board should appear as a serial device on your computer. Now, you can use it with the Black Magic Debug client of your choice.

View File

@ -2,7 +2,7 @@
The Wi-Fi Developer Board serves as a tool to debug the Flipper Zero firmware. To debug the firmware, the initial step involves compiling the firmware from its source code. This process enables the debugging functionality within the firmware and generates all the necessary files required for debugging purposes.
> **NOTE:** Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux. Support for Windows is in beta test.
> **NOTE:** Building and debugging the Flipper Zero firmware is fully supported on MacOS and Linux. Support for Windows is in beta test.
***
@ -14,11 +14,11 @@ Update the firmware of your Developer Board before using it. For more informatio
## Installing Git
Youll need Git installed on your computer to clone the firmware repository. If you dont have Git, install it by doing the following:
You'll need Git installed on your computer to clone the firmware repository. If you don't have Git, install it by doing the following:
* **MacOS**
On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command:
On MacOS, install the **Xcode Command Line Tools** package, which includes Git as one of the pre-installed command-line utilities, by running in the Terminal the following command:
```text
xcode-select --install
@ -26,11 +26,11 @@ Youll need Git installed on your computer to clone the firmware repository. I
* **Linux**
On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command:
On Linux, you can install Git using your package manager. For example, on Ubuntu, run in the Terminal the following command:
```text
sudo apt install git
```
```text
sudo apt install git
```
For other distributions, refer to your package manager documentation.
@ -57,7 +57,9 @@ Then, run the **Flipper Build Tool** (FBT) to build the firmware:
The Developer Board can work in the **Wired** mode and two **Wireless** modes: **Wi-Fi access point (AP)** mode and **Wi-Fi client (STA)** mode. The Wired mode is the simplest to set up, but requires a USB Type-C cable. The Wireless modes are more complex to set up, but they allow you to debug your Flipper Zero wirelessly.
> **NOTE:** Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode: Name: **blackmagic**, Password: **iamwitcher**
> **NOTE:** Use the following credentials when connecting to the Developer Board in **Wi-Fi access point** mode:\n
Name: **blackmagic**\n
Password: **iamwitcher**
## Wired
@ -69,13 +71,13 @@ To connect the Developer Board in **Wired** mode, do the following:
2. On your computer, open the **Terminal** and run the following:
* **MacOS**
* **MacOS**
```text
ls /dev/cu.*
```
* **Linux**
* **Linux**
```text
ls /dev/tty*
@ -87,9 +89,9 @@ To connect the Developer Board in **Wired** mode, do the following:
4. Rerun the command. Two new devices have to appear: this is the Developer Board.
> **NOTE:** If the Developer Board doesnt appear in the list of devices, try using a different cable, USB port, or computer.
>
> **NOTE:** Flipper Zero logs can only be viewed when the Developer Board is connected via USB. The option to view logs over Wi-Fi will be added in future updates. For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs).
> **NOTE:** If the Developer Board doesn't appear in the list of devices, try using a different cable, USB port, or computer.
>
> **NOTE:** Flipper Zero logs can only be viewed when the Developer Board is connected via USB. The option to view logs over Wi-Fi will be added in future updates. For more information, visit [Reading logs via the Dev Board](https://docs.flipperzero.one/development/hardware/wifi-debugger-module/reading-logs).
## Wireless
@ -97,7 +99,7 @@ To connect the Developer Board in **Wired** mode, do the following:
![The Developer Board in Wi-Fi access point mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/tKRTMHAuruiLSEce2a8Ve_monosnap-miro-2023-06-22-16-39-17.jpg)
Out of the box, the Developer Board is configured to work as a **Wi-Fi access point**. This means it will create its own Wi-Fi network to which you can connect. If your Developer Board doesnt create a Wi-Fi network, it is probably configured to work in **Wi-Fi client** mode. To reset your Developer Board back to **Wi-Fi access point** mode, press and hold the **BOOT** button for 10 seconds, then wait for the module to reboot.
Out of the box, the Developer Board is configured to work as a **Wi-Fi access point**. This means it'll create its own Wi-Fi network to which you can connect. If your Developer Board doesn't create a Wi-Fi network, it is probably configured to work in **Wi-Fi client** mode. To reset your Developer Board back to **Wi-Fi access point** mode, press and hold the **BOOT** button for 10 seconds, then wait for the module to reboot.
![You can reconfigure the Developer Board mode by pressing and holding the BOOT button](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/57eELJsAwMxeZCEA1NMJw_monosnap-miro-2023-06-22-20-33-27.jpg)
@ -110,11 +112,12 @@ To connect the Developer Board in **Wi-Fi access point** mode, do the following:
3. Connect to the network:
* Name: **blackmagic**
* Password: **iamwitcher**
4. To configure the Developer Board, open a browser and go to `http://192.168.4.1`.
#### Wi-Fi client (STA) mode
### Wi-Fi client (STA) mode
![The Developer Board in Wi-Fi client mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/xLQpFyYPfUS5Cx0uQhrNd_monosnap-miro-2023-06-23-12-34-36.jpg)
@ -126,15 +129,15 @@ To connect the Developer Board in **Wi-Fi client** mode, you need to configure i
3. In a browser, go to the configuration page on `http://192.168.4.1`.
4. Select the **STA** mode and enter your networks **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby networks.
4. Select the **STA** mode and enter your network's **SSID** (name) and **password**. For convenience, you can click the **+** button to see the list of nearby networks.
5. Save the configuration and reboot the Developer Board.
![In the Wi-Fi tab, you can set the Developer Board mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/klbLVj8lz2bEvm7j4wRaj_monosnap-miro-2023-06-23-13-06-32.jpg)
After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name [blackmagic.local](http://blackmagic.local) or the IP address it got from your router (youll have to figure this out yourself, every router is different).
After rebooting, the Developer Board connects to your Wi-Fi network. You can connect to the device using the mDNS name **blackmagic.local** or the IP address it got from your router (you'll have to figure this out yourself, every router is different).
After connecting to your debugger via [blackmagic.local](http://blackmagic.local), you can find its IP address in the **SYS** tab. You can also change the debuggers mode to **AP** or **STA** there.
After connecting to your debugger via <http://blackmagic.local>, you can find its IP address in the **SYS** tab. You can also change the debugger's mode to **AP** or **STA** there.
![In the SYS tab, you can view the IP address of your Developer Board](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/5XbUptlfqzlV0p6hRUqiG_monosnap-miro-2023-06-22-18-11-30.jpg)
@ -145,10 +148,10 @@ After connecting to your debugger via [blackmagic.local](http://blackmagic.local
Open the **Terminal** in the **flipperzero-firmware** directory that you cloned earlier and run the following command:
```text
./fbt flash_blackmagic
./fbt flash
```
This will upload the firmware youve just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware using the [GDB](https://www.gnu.org/software/gdb/) debugger. We recommend using **VSCode** with the recommended extensions, and we have pre-made configurations for it.
This will upload the firmware you've just built to your Flipper Zero via the Developer Board. After that, you can start debugging the firmware using the [GDB](https://www.gnu.org/software/gdb/) debugger. We recommend using **VSCode** with the recommended extensions, and we have pre-made configurations for it.
To debug in **VSCode**, do the following:
@ -162,9 +165,9 @@ To debug in **VSCode**, do the following:
4. In VSCode, open the **Run and Debug** tab and select **Attach FW (blackmagic)** from the dropdown menu.
5. If needed, flash your Flipper Zero with the `./fbt flash_blackmagic` command, then click the **Play** button in the debug sidebar to start the debugging session.
5. If needed, flash your Flipper Zero with the `./fbt flash` command, then click the **Play** button in the debug sidebar to start the debugging session.
6. Note that starting a debug session halts the execution of the firmware, so youll need to click the **Continue** button on the toolbar at the top of your VSCode window to continue execution.
6. Note that starting a debug session halts the execution of the firmware, so you'll need to click the **Continue** button on the toolbar at the top of your VSCode window to continue execution.
![Click Continue in the toolbar to continue execution of the firmware](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/lp8ygGaZ3DvWD3OSI9yGO_monosnap-miro-2023-06-23-17-58-09.jpg)

View File

@ -4,9 +4,11 @@ The Developer Board allows you to read Flipper Zero logs via UART. Unlike readin
> **NOTE:** Flipper Zero logs can only be viewed when the developer board is connected via USB. The option to view logs over Wi-Fi will be added in future updates.
***
## Setting the log level
Depending on your needs, you can set the log level by going to Main Menu -> Settings -> Log Level. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt).
Depending on your needs, you can set the log level by going to **Main Menu -> Settings -> Log Level**. To learn more about logging levels, visit [Settings](https://docs.flipperzero.one/basics/settings#d5TAt).
![You can manually set the preferred log level](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/INzQMw8QUsG9PXi30WFS0_monosnap-miro-2023-07-11-13-29-47.jpg)
@ -20,17 +22,17 @@ Depending on your operating system, you need to install an additional applicatio
On MacOS, you need to install the **minicom** communication program by doing the following:
1. [Install Homebrew](https://brew.sh/) by running in the Terminal the following command:
1. [Install Homebrew](https://brew.sh/) by running the following command in the Terminal:
```text
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
```text
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
2. After installation of Homebrew, run the following command to install minicom:
```text
brew install minicom
```
```text
brew install minicom
```
After installation of minicom on your macOS computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following:
@ -38,21 +40,77 @@ After installation of minicom on your macOS computer, you can connect to the Dev
2. On your computer, open the Terminal and run the following command:
```text
ls /dev/cu.*
```
```text
ls /dev/cu.*
```
Note the list of devices.
Note the list of devices.
3. Connect the developer board to your computer using a USB Type-C cable.\
![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
3. Connect the developer board to your computer using a USB Type-C cable.
![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```text
/dev/cu.usbmodemblackmagic1
/dev/cu.usbmodemblackmagic3
```
```text
/dev/cu.usbmodemblackmagic1
```
```text
/dev/cu.usbmodemblackmagic3
```
Your Developer Board might have different names.
5. Run the following command:
```text
minicom -D /dev/<port> -b 230400
```
Where `<port>` is the name of your device with a bigger number.
Example:
```text
minicom -D /dev/cu.usbmodemblackmagic3 -b 230400
```
6. View logs of your Flipper Zero in the Terminal.
7. To quit, close the minicom window or quit via the minicom menu.
### Linux
On Linux, you need to install the **minicom** communication program. For example, on Ubuntu, run in the Terminal the following command:
```text
sudo apt install minicom
```
After installation of minicom on your Linux computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following:
1. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on.
2. On your computer, open the Terminal and run the following command:
```text
ls /dev/tty*
```
Note the list of devices.
3. Connect the developer board to your computer using a USB Type-C cable.
![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```text
/dev/ttyACM0
```
```text
/dev/ttyACM1
```
Your Developer Board might have different names.
@ -72,57 +130,7 @@ After installation of minicom on your macOS computer, you can connect to the Dev
6. View logs of your Flipper Zero in the Terminal.
7. To quit, close the minicom window or quit via the minicom menu.
### Linux
On Linux, you need to install the **minicom** communication program. For example, on Ubuntu, run in the Terminal the following command:
```text
sudo apt install minicom
```
After installation of minicom on your Linux computer, you can connect to the Developer Board to read Flipper Zero logs by doing the following:
1. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on.
2. On your computer, open the Terminal and run the following command:
```text
ls /dev/tty*
```
Note the list of devices.
3. Connect the developer board to your computer using a USB Type-C cable.
![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```text
/dev/ttyACM0
/dev/ttyACM1
```
Your Developer Board might have different names.
5. Run the following command:
```text
minicom -D /dev/<port> \-b 230400
```
Where `<port>` is the name of your device with a bigger number.
Example:
```text
minicom -D /dev/ttyACM1 \-b 230400
```
6. View logs of your Flipper Zero in the Terminal.
> **NOTE:** If no logs are shown in the Terminal, try running the command from Step 5 with another device name.
**NOTE:** If no logs are shown in the Terminal, try running the command from Step 5 with another device name.
7. To quit, close the minicom window or quit via the minicom menu.
@ -135,17 +143,17 @@ On Windows, do the following:
2. Cold-plug the Developer Board into your Flipper Zero by turning off the Flipper Zero, connecting the developer board, and then turning it back on.
3. Connect the developer board to your computer using a USB Type-C cable.
![The Developer Board in Wired mode](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
![Connect the developer board with a USB-C cable](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/iPpsMt2-is4aIjiVeFu5t_hjxs2i1oovrnps74v5jgsimage.png)
4. Find the serial port that the developer board is connected to by going to **Device Manager -> Ports (COM & LPT)** and looking for a new port that appears when you connect the Wi-Fi developer board.
![Go to Device Manager -> Ports (COM & LPT)](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KKLQJK1lvqmI5iab3d__C_image.png)
![Find the serial port in your Device Manager](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/KKLQJK1lvqmI5iab3d__C_image.png)
5. Run the PuTTY application and select **Serial** as the connection type.
6. Enter the port number you found in the previous step into the **Serial line** field.
7. Set the **Speed** parameter to **230400** and click **Open**.
![Set the required parameters](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/ROBSJyfQ_CXiy4GUZcPbs_monosnap-miro-2023-07-12-13-56-47.jpg)
![Set speed to 230400](https://archbee-image-uploads.s3.amazonaws.com/3StCFqarJkJQZV-7N79yY/ROBSJyfQ_CXiy4GUZcPbs_monosnap-miro-2023-07-12-13-56-47.jpg)
8. View logs of your Flipper Zero in the PuTTY terminal window.

View File

@ -79,6 +79,7 @@ To use language servers other than the default VS Code C/C++ language server, us
- `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs. Supports `ARGS="..."` to pass extra arguments to clang-format.
- `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests. Supports `ARGS="..."` to pass extra arguments to black.
- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be available on your system's `PATH`.
- `doxygen` - generate Doxygen documentation for the firmware. `doxy` target also opens web browser to view the generated documentation.
- `cli` - start a Flipper CLI session over USB.
### Firmware targets

View File

@ -79,15 +79,7 @@ Up to 5 keys can be hold simultaneously.
| HOLD | Special key or single character | Press and hold key until RELEASE command |
| RELEASE | Special key or single character | Release key |
## Wait for button press
Will wait indefinitely for a button to be pressed
| Command | Parameters | Notes |
| --------------------- | ------------ | --------------------------------------------------------------------- |
| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution |
### String
## String
| Command | Parameters | Notes |
| ------- | ----------- | ----------------- |
@ -126,7 +118,54 @@ Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key)
| ------- | ---------------- | ----- |
| SYSRQ | Single character | |
### USB device ID
## Media keys
Some Media/Consumer Control keys can be pressed with "MEDIA" command
| Command | Parameters | Notes |
| ------- | ------------------------- | ----- |
| MEDIA | Media key, see list below | |
| Key name | Notes |
| ----------------- | ----------------------------- |
| POWER | |
| REBOOT | |
| SLEEP | |
| LOGOFF | |
| EXIT | |
| HOME | |
| BACK | |
| FORWARD | |
| REFRESH | |
| SNAPSHOT | Take photo in a camera app |
| PLAY | |
| PAUSE | |
| PLAY_PAUSE | |
| NEXT_TRACK | |
| PREV_TRACK | |
| STOP | |
| EJECT | |
| MUTE | |
| VOLUME_UP | |
| VOLUME_DOWN | |
| FN | Fn/Globe key on Mac keyboard |
| BRIGHT_UP | Increase display brightness |
| BRIGHT_DOWN | Decrease display brightness |
## Fn/Globe key commands (Mac/iPad)
| Command | Parameters | Notes |
| ------- | ------------------------------- | ----- |
| GLOBE | Special key or single character | |
## Wait for button press
Will wait indefinitely for a button to be pressed
| Command | Parameters | Notes |
| --------------------- | ------------ | --------------------------------------------------------------------- |
| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution |
## USB device ID
You can set the custom ID of the Flipper USB HID device. ID command should be in the **first line** of script, it is executed before script run.

View File

@ -33,15 +33,13 @@ typedef enum {
FlipperApplicationLoadStatusMissingImports,
} FlipperApplicationLoadStatus;
/**
* @brief Get text description of preload status
/** Get text description of preload status
* @param status Status code
* @return String pointer to description
*/
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status);
/**
* @brief Get text description of load status
/** Get text description of load status
* @param status Status code
* @return String pointer to description
*/
@ -61,8 +59,7 @@ typedef struct {
uint8_t* debug_link;
} FlipperApplicationState;
/**
* @brief Initialize FlipperApplication object
/** Initialize FlipperApplication object
* @param storage Storage instance
* @param api_interface ELF API interface to use for pre-loading and symbol resolving
* @return Application instance
@ -70,44 +67,44 @@ typedef struct {
FlipperApplication*
flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface);
/**
* @brief Destroy FlipperApplication object
/** Destroy FlipperApplication object
* @param app Application pointer
*/
void flipper_application_free(FlipperApplication* app);
/**
* @brief Validate elf file and load application metadata
* @param app Application pointer
* @return Preload result code
/** Validate elf file and load application metadata
*
* @param app Application pointer
* @param[in] path The path to fap file
*
* @return Preload result code
*/
FlipperApplicationPreloadStatus
flipper_application_preload(FlipperApplication* app, const char* path);
/**
* @brief Validate elf file and load application manifest
* @param app Application pointer
* @return Preload result code
/** Validate elf file and load application manifest
*
* @param app Application pointer
* @param[in] path The path to fap file
*
* @return Preload result code
*/
FlipperApplicationPreloadStatus
flipper_application_preload_manifest(FlipperApplication* app, const char* path);
/**
* @brief Get pointer to application manifest for preloaded application
/** Get pointer to application manifest for preloaded application
* @param app Application pointer
* @return Pointer to application manifest
*/
const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app);
/**
* @brief Load sections and process relocations for already pre-loaded application
/** Load sections and process relocations for already pre-loaded application
* @param app Application pointer
* @return Load result code
*/
FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app);
/**
* @brief Allocate application thread at entry point address, using app name and
/** Allocate application thread at entry point address, using app name and
* stack size from metadata. Returned thread isn't started yet.
* Can be only called once for application instance.
* @param app Applicaiton pointer
@ -116,20 +113,17 @@ FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplicatio
*/
FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args);
/**
* @brief Check if application is a plugin (not a runnable standalone app)
/** Check if application is a plugin (not a runnable standalone app)
* @param app Application pointer
* @return true if application is a plugin, false otherwise
*/
bool flipper_application_is_plugin(FlipperApplication* app);
/**
* @brief Entry point prototype for standalone applications
/** Entry point prototype for standalone applications
*/
typedef int32_t (*FlipperApplicationEntryPoint)(void*);
/**
* @brief An object that describes a plugin - must be returned by plugin's entry point
/** An object that describes a plugin - must be returned by plugin's entry point
*/
typedef struct {
const char* appid;
@ -137,21 +131,18 @@ typedef struct {
const void* entry_point;
} FlipperAppPluginDescriptor;
/**
* @brief Entry point prototype for plugins
/** Entry point prototype for plugins
*/
typedef const FlipperAppPluginDescriptor* (*FlipperApplicationPluginEntryPoint)(void);
/**
* @brief Get plugin descriptor for preloaded plugin
/** Get plugin descriptor for preloaded plugin
* @param app Application pointer
* @return Pointer to plugin descriptor
*/
const FlipperAppPluginDescriptor*
flipper_application_plugin_get_descriptor(FlipperApplication* app);
/**
* @brief Load name and icon from FAP file.
/** Load name and icon from FAP file.
*
* @param path Path to FAP file.
* @param storage Storage instance.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/**
* @file lfrfid_worker.h
/** @file lfrfid_worker.h
*
* LFRFID worker
*/
@ -54,37 +53,35 @@ typedef void (*LFRFIDWorkerEmulateRawCallback)(LFRFIDWorkerEmulateRawResult resu
typedef struct LFRFIDWorker LFRFIDWorker;
/**
* Allocate LF-RFID worker
/** Allocate LF-RFID worker
* @return LFRFIDWorker*
*/
LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict);
/**
* Free LF-RFID worker
* @param worker
/** Free LF-RFID worker
*
* @param worker The worker
*/
void lfrfid_worker_free(LFRFIDWorker* worker);
/**
* Start LF-RFID worker thread
* @param worker
/** Start LF-RFID worker thread
*
* @param worker The worker
*/
void lfrfid_worker_start_thread(LFRFIDWorker* worker);
/**
* Stop LF-RFID worker thread
* @param worker
/** Stop LF-RFID worker thread
*
* @param worker The worker
*/
void lfrfid_worker_stop_thread(LFRFIDWorker* worker);
/**
* @brief Start read mode
*
* @param worker
* @param type
* @param callback
* @param context
/** Start read mode
*
* @param worker The worker
* @param type The type
* @param callback The callback
* @param context The context
*/
void lfrfid_worker_read_start(
LFRFIDWorker* worker,
@ -92,13 +89,12 @@ void lfrfid_worker_read_start(
LFRFIDWorkerReadCallback callback,
void* context);
/**
* @brief Start write mode
*
* @param worker
* @param protocol
* @param callback
* @param context
/** Start write mode
*
* @param worker The worker
* @param protocol The protocol
* @param callback The callback
* @param context The context
*/
void lfrfid_worker_write_start(
LFRFIDWorker* worker,
@ -126,14 +122,13 @@ void lfrfid_worker_write_and_set_pass_start(
*/
void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol);
/**
* @brief Start raw read mode
*
* @param worker
* @param filename
* @param type
* @param callback
* @param context
/** Start raw read mode
*
* @param worker The worker
* @param filename The filename
* @param type The type
* @param callback The callback
* @param context The context
*/
void lfrfid_worker_read_raw_start(
LFRFIDWorker* worker,
@ -142,12 +137,12 @@ void lfrfid_worker_read_raw_start(
LFRFIDWorkerReadRawCallback callback,
void* context);
/**
* Emulate raw read mode
* @param worker
* @param filename
* @param callback
* @param context
/** Emulate raw read mode
*
* @param worker The worker
* @param filename The filename
* @param callback The callback
* @param context The context
*/
void lfrfid_worker_emulate_raw_start(
LFRFIDWorker* worker,
@ -155,9 +150,9 @@ void lfrfid_worker_emulate_raw_start(
LFRFIDWorkerEmulateRawCallback callback,
void* context);
/**
* Stop all modes
* @param worker
/** Stop all modes
*
* @param worker The worker
*/
void lfrfid_worker_stop(LFRFIDWorker* worker);

View File

@ -225,7 +225,7 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) {
bool protocol_detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) {
MfDesfireKeyVersion key_version = 0;
MfDesfireKeyVersion key_version = {0};
MfDesfireError error = mf_desfire_poller_read_key_version(instance, 0, &key_version);
protocol_detected = (error == MfDesfireErrorNone);
}

View File

@ -143,8 +143,8 @@ MfDesfireError mf_desfire_poller_read_key_version(
MfDesfirePoller* instance,
uint8_t key_num,
MfDesfireKeyVersion* data) {
furi_assert(instance);
furi_assert(data);
furi_check(instance);
furi_check(data);
bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2);
bit_buffer_set_byte(instance->input_buffer, 0, MF_DESFIRE_CMD_GET_KEY_VERSION);

View File

@ -43,27 +43,29 @@ typedef struct Compress Compress;
/** Allocate encoder and decoder
*
* @param compress_buff_size size of decoder and encoder buffer to allocate
* @param compress_buff_size size of decoder and encoder buffer to
* allocate
*
* @return Compress instance
* @return Compress instance
*/
Compress* compress_alloc(uint16_t compress_buff_size);
/** Free encoder and decoder
*
* @param compress Compress instance
* @param compress Compress instance
*/
void compress_free(Compress* compress);
/** Encode data
*
* @param compress Compress instance
* @param data_in pointer to input data
* @param data_in_size size of input data
* @param data_out maximum size of output data
* @param data_res_size pointer to result output data size
* @param compress Compress instance
* @param data_in pointer to input data
* @param data_in_size size of input data
* @param data_out maximum size of output data
* @param[in] data_out_size The data out size
* @param data_res_size pointer to result output data size
*
* @return true on success
* @return true on success
*/
bool compress_encode(
Compress* compress,
@ -75,13 +77,14 @@ bool compress_encode(
/** Decode data
*
* @param compress Compress instance
* @param data_in pointer to input data
* @param data_in_size size of input data
* @param data_out maximum size of output data
* @param data_res_size pointer to result output data size
* @param compress Compress instance
* @param data_in pointer to input data
* @param data_in_size size of input data
* @param data_out maximum size of output data
* @param[in] data_out_size The data out size
* @param data_res_size pointer to result output data size
*
* @return true on success
* @return true on success
*/
bool compress_decode(
Compress* compress,

View File

@ -0,0 +1,40 @@
from SCons.Script import Action, Builder
def exists(env):
return True
def DoxyBuild(env, target, source, doxy_env_variables=None):
if doxy_env_variables:
doxy_env = env.Clone()
doxy_env.Append(ENV=doxy_env_variables)
else:
doxy_env = env
return doxy_env._DoxyBuilder(target, source)
def generate(env):
if not env["VERBOSE"]:
env.SetDefault(
DOXYGENCOMSTR="\tDOXY\t${TARGET}",
)
env.SetDefault(
DOXYGEN="doxygen",
)
env.AddMethod(DoxyBuild)
env.Append(
BUILDERS={
"_DoxyBuilder": Builder(
action=[
Action(
[["$DOXYGEN", "$SOURCE"]],
"$DOXYGENCOMSTR",
),
],
)
}
)

View File

@ -32,7 +32,7 @@ def atexist_handler():
for bf in GetBuildFailures():
for node in Flatten(bf.node):
if node.exists and node.name.endswith(".html"):
if node.exists and "pvs" in node.name and node.name.endswith(".html"):
# macOS
if sys.platform == "darwin":
subprocess.run(["open", node.abspath])

View File

@ -1,5 +1,5 @@
from fbt.util import link_dir
from ansi.color import fg
from fbt.util import link_dir
def link_elf_dir_as_latest(env, elf_node):

View File

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,59.0,,
Version,+,60.3,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@ -852,25 +852,25 @@ Function,-,dprintf,int,"int, const char*, ..."
Function,-,drand48,double,
Function,-,drem,double,"double, double"
Function,-,dremf,float,"float, float"
Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align"
Function,+,elements_bold_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble_str,void,"Canvas*, int32_t, int32_t, const char*, Align, Align"
Function,+,elements_button_center,void,"Canvas*, const char*"
Function,+,elements_button_left,void,"Canvas*, const char*"
Function,+,elements_button_right,void,"Canvas*, const char*"
Function,+,elements_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*"
Function,+,elements_scrollable_text_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool"
Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t"
Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool"
Function,+,elements_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_multiline_text,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, int32_t, int32_t, size_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, int32_t, int32_t, size_t, float, const char*"
Function,+,elements_scrollable_text_line,void,"Canvas*, int32_t, int32_t, size_t, FuriString*, size_t, _Bool"
Function,+,elements_scrollbar,void,"Canvas*, size_t, size_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t"
Function,+,elements_text_box,void,"Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool"
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
Function,+,elf_symbolname_hash,uint32_t,const char*
Function,+,empty_screen_alloc,EmptyScreen*,
@ -1205,6 +1205,7 @@ Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release_all,_Bool,
Function,+,furi_hal_hid_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t

1 entry status name type params
2 Version + 59.0 60.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
852 Function - drand48 double
853 Function - drem double double, double
854 Function - dremf float float, float
855 Function + elements_bold_rounded_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
856 Function + elements_bubble void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
857 Function + elements_bubble_str void Canvas*, uint8_t, uint8_t, const char*, Align, Align Canvas*, int32_t, int32_t, const char*, Align, Align
858 Function + elements_button_center void Canvas*, const char*
859 Function + elements_button_left void Canvas*, const char*
860 Function + elements_button_right void Canvas*, const char*
861 Function + elements_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
862 Function + elements_multiline_text void Canvas*, uint8_t, uint8_t, const char* Canvas*, int32_t, int32_t, const char*
863 Function + elements_multiline_text_aligned void Canvas*, uint8_t, uint8_t, Align, Align, const char* Canvas*, int32_t, int32_t, Align, Align, const char*
864 Function + elements_multiline_text_framed void Canvas*, uint8_t, uint8_t, const char* Canvas*, int32_t, int32_t, const char*
865 Function + elements_progress_bar void Canvas*, uint8_t, uint8_t, uint8_t, float Canvas*, int32_t, int32_t, size_t, float
866 Function + elements_progress_bar_with_text void Canvas*, uint8_t, uint8_t, uint8_t, float, const char* Canvas*, int32_t, int32_t, size_t, float, const char*
867 Function + elements_scrollable_text_line void Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool Canvas*, int32_t, int32_t, size_t, FuriString*, size_t, _Bool
868 Function + elements_scrollbar void Canvas*, uint16_t, uint16_t Canvas*, size_t, size_t
869 Function + elements_scrollbar_pos void Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t Canvas*, int32_t, int32_t, size_t, size_t, size_t
870 Function + elements_slightly_rounded_box void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
871 Function + elements_slightly_rounded_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
872 Function + elements_string_fit_width void Canvas*, FuriString*, uint8_t Canvas*, FuriString*, size_t
873 Function + elements_text_box void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool
874 Function + elf_resolve_from_hashtable _Bool const ElfApiInterface*, uint32_t, Elf32_Addr*
875 Function + elf_symbolname_hash uint32_t const char*
876 Function + empty_screen_alloc EmptyScreen*
1205 Function + furi_hal_gpio_remove_int_callback void const GpioPin*
1206 Function + furi_hal_hid_consumer_key_press _Bool uint16_t
1207 Function + furi_hal_hid_consumer_key_release _Bool uint16_t
1208 Function + furi_hal_hid_consumer_key_release_all _Bool
1209 Function + furi_hal_hid_get_led_state uint8_t
1210 Function + furi_hal_hid_is_connected _Bool
1211 Function + furi_hal_hid_kb_press _Bool uint16_t

View File

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,59.0,,
Version,+,60.3,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
@ -789,7 +789,6 @@ Function,+,calloc,void*,"size_t, size_t"
Function,+,canvas_clear,void,Canvas*
Function,+,canvas_commit,void,Canvas*
Function,+,canvas_current_font_height,size_t,const Canvas*
Function,+,canvas_current_font_width,size_t,const Canvas*
Function,+,canvas_draw_bitmap,void,"Canvas*, int32_t, int32_t, size_t, size_t, const uint8_t*"
Function,+,canvas_draw_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,canvas_draw_circle,void,"Canvas*, int32_t, int32_t, size_t"
@ -799,7 +798,6 @@ Function,+,canvas_draw_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,canvas_draw_glyph,void,"Canvas*, int32_t, int32_t, uint16_t"
Function,+,canvas_draw_icon,void,"Canvas*, int32_t, int32_t, const Icon*"
Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, IconAnimation*"
Function,+,canvas_draw_icon_bitmap,void,"Canvas*, uint8_t, uint8_t, int16_t, int16_t, const Icon*"
Function,+,canvas_draw_icon_ex,void,"Canvas*, int32_t, int32_t, const Icon*, IconRotation"
Function,+,canvas_draw_line,void,"Canvas*, int32_t, int32_t, int32_t, int32_t"
Function,+,canvas_draw_rbox,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
@ -930,26 +928,25 @@ Function,-,dprintf,int,"int, const char*, ..."
Function,-,drand48,double,
Function,-,drem,double,"double, double"
Function,-,dremf,float,"float, float"
Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align"
Function,+,elements_bold_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble_str,void,"Canvas*, int32_t, int32_t, const char*, Align, Align"
Function,+,elements_button_center,void,"Canvas*, const char*"
Function,+,elements_button_left,void,"Canvas*, const char*"
Function,+,elements_button_right,void,"Canvas*, const char*"
Function,+,elements_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*"
Function,+,elements_scrollable_text_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool"
Function,+,elements_scrollable_text_line_str,void,"Canvas*, uint8_t, uint8_t, uint8_t, const char*, size_t, _Bool, _Bool"
Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t"
Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool"
Function,+,elements_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_multiline_text,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, int32_t, int32_t, size_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, int32_t, int32_t, size_t, float, const char*"
Function,+,elements_scrollable_text_line,void,"Canvas*, int32_t, int32_t, size_t, FuriString*, size_t, _Bool"
Function,+,elements_scrollbar,void,"Canvas*, size_t, size_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t"
Function,+,elements_text_box,void,"Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool"
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
Function,+,elf_symbolname_hash,uint32_t,const char*
Function,+,empty_screen_alloc,EmptyScreen*,
@ -1308,6 +1305,7 @@ Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release_all,_Bool,
Function,+,furi_hal_hid_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t
@ -1358,9 +1356,9 @@ Function,+,furi_hal_infrared_async_tx_set_signal_sent_isr_callback,void,"FuriHal
Function,+,furi_hal_infrared_async_tx_start,void,"uint32_t, float"
Function,+,furi_hal_infrared_async_tx_stop,void,
Function,+,furi_hal_infrared_async_tx_wait_termination,void,
Function,+,furi_hal_infrared_get_debug_out_status,_Bool,
Function,+,furi_hal_infrared_detect_tx_output,FuriHalInfraredTxPin,
Function,+,furi_hal_infrared_is_busy,_Bool,
Function,+,furi_hal_infrared_set_debug_out,void,_Bool
Function,+,furi_hal_infrared_set_tx_output,void,FuriHalInfraredTxPin
Function,-,furi_hal_init,void,
Function,-,furi_hal_init_early,void,
Function,-,furi_hal_interrupt_init,void,

1 entry status name type params
2 Version + 59.0 60.3
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
789 Function + canvas_clear void Canvas*
790 Function + canvas_commit void Canvas*
791 Function + canvas_current_font_height size_t const Canvas*
Function + canvas_current_font_width size_t const Canvas*
792 Function + canvas_draw_bitmap void Canvas*, int32_t, int32_t, size_t, size_t, const uint8_t*
793 Function + canvas_draw_box void Canvas*, int32_t, int32_t, size_t, size_t
794 Function + canvas_draw_circle void Canvas*, int32_t, int32_t, size_t
798 Function + canvas_draw_glyph void Canvas*, int32_t, int32_t, uint16_t
799 Function + canvas_draw_icon void Canvas*, int32_t, int32_t, const Icon*
800 Function + canvas_draw_icon_animation void Canvas*, int32_t, int32_t, IconAnimation*
Function + canvas_draw_icon_bitmap void Canvas*, uint8_t, uint8_t, int16_t, int16_t, const Icon*
801 Function + canvas_draw_icon_ex void Canvas*, int32_t, int32_t, const Icon*, IconRotation
802 Function + canvas_draw_line void Canvas*, int32_t, int32_t, int32_t, int32_t
803 Function + canvas_draw_rbox void Canvas*, int32_t, int32_t, size_t, size_t, size_t
928 Function - drand48 double
929 Function - drem double double, double
930 Function - dremf float float, float
931 Function + elements_bold_rounded_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
932 Function + elements_bubble void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
933 Function + elements_bubble_str void Canvas*, uint8_t, uint8_t, const char*, Align, Align Canvas*, int32_t, int32_t, const char*, Align, Align
934 Function + elements_button_center void Canvas*, const char*
935 Function + elements_button_left void Canvas*, const char*
936 Function + elements_button_right void Canvas*, const char*
937 Function + elements_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
938 Function + elements_multiline_text void Canvas*, uint8_t, uint8_t, const char* Canvas*, int32_t, int32_t, const char*
939 Function + elements_multiline_text_aligned void Canvas*, uint8_t, uint8_t, Align, Align, const char* Canvas*, int32_t, int32_t, Align, Align, const char*
940 Function + elements_multiline_text_framed void Canvas*, uint8_t, uint8_t, const char* Canvas*, int32_t, int32_t, const char*
941 Function + elements_progress_bar void Canvas*, uint8_t, uint8_t, uint8_t, float Canvas*, int32_t, int32_t, size_t, float
942 Function + elements_progress_bar_with_text void Canvas*, uint8_t, uint8_t, uint8_t, float, const char* Canvas*, int32_t, int32_t, size_t, float, const char*
943 Function + elements_scrollable_text_line void Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool Canvas*, int32_t, int32_t, size_t, FuriString*, size_t, _Bool
944 Function + elements_scrollable_text_line_str elements_scrollbar void Canvas*, uint8_t, uint8_t, uint8_t, const char*, size_t, _Bool, _Bool Canvas*, size_t, size_t
945 Function + elements_scrollbar elements_scrollbar_pos void Canvas*, uint16_t, uint16_t Canvas*, int32_t, int32_t, size_t, size_t, size_t
946 Function + elements_scrollbar_pos elements_slightly_rounded_box void Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t Canvas*, int32_t, int32_t, size_t, size_t
947 Function + elements_slightly_rounded_box elements_slightly_rounded_frame void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, int32_t, int32_t, size_t, size_t
948 Function + elements_slightly_rounded_frame elements_string_fit_width void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t Canvas*, FuriString*, size_t
949 Function + elements_string_fit_width elements_text_box void Canvas*, FuriString*, uint8_t Canvas*, int32_t, int32_t, size_t, size_t, Align, Align, const char*, _Bool
Function + elements_text_box void Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool
950 Function + elf_resolve_from_hashtable _Bool const ElfApiInterface*, uint32_t, Elf32_Addr*
951 Function + elf_symbolname_hash uint32_t const char*
952 Function + empty_screen_alloc EmptyScreen*
1305 Function + furi_hal_gpio_remove_int_callback void const GpioPin*
1306 Function + furi_hal_hid_consumer_key_press _Bool uint16_t
1307 Function + furi_hal_hid_consumer_key_release _Bool uint16_t
1308 Function + furi_hal_hid_consumer_key_release_all _Bool
1309 Function + furi_hal_hid_get_led_state uint8_t
1310 Function + furi_hal_hid_is_connected _Bool
1311 Function + furi_hal_hid_kb_press _Bool uint16_t
1356 Function + furi_hal_infrared_async_tx_start void uint32_t, float
1357 Function + furi_hal_infrared_async_tx_stop void
1358 Function + furi_hal_infrared_async_tx_wait_termination void
1359 Function + furi_hal_infrared_get_debug_out_status furi_hal_infrared_detect_tx_output _Bool FuriHalInfraredTxPin
1360 Function + furi_hal_infrared_is_busy _Bool
1361 Function + furi_hal_infrared_set_debug_out furi_hal_infrared_set_tx_output void _Bool FuriHalInfraredTxPin
1362 Function - furi_hal_init void
1363 Function - furi_hal_init_early void
1364 Function - furi_hal_interrupt_init void

View File

@ -1,6 +1,7 @@
#include <furi_hal_infrared.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
#include <furi_hal_cortex.h>
#include <furi_hal_bus.h>
#include <stm32wbxx_ll_tim.h>
@ -75,11 +76,17 @@ typedef enum {
InfraredStateMAX,
} InfraredState;
static FuriHalInfraredTxPin infrared_tx_output = FuriHalInfraredTxPinInternal;
static volatile InfraredState furi_hal_infrared_state = InfraredStateIdle;
static InfraredTimTx infrared_tim_tx;
static InfraredTimRx infrared_tim_rx;
static bool infrared_external_output;
static const GpioPin* infrared_tx_pins[FuriHalInfraredTxPinMax] = {
[FuriHalInfraredTxPinInternal] = &gpio_infrared_tx,
[FuriHalInfraredTxPinExtPA7] = &gpio_ext_pa7,
};
static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift);
static void furi_hal_infrared_async_tx_free_resources(void);
static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polarity_shift);
@ -355,18 +362,8 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc
LL_TIM_SetAutoReload(
INFRARED_DMA_TIMER,
__LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq));
if(infrared_external_output) {
LL_TIM_OC_SetCompareCH1(
INFRARED_DMA_TIMER,
((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
/* LL_TIM_OCMODE_PWM2 set by DMA */
LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE);
LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N);
LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER);
} else {
if(infrared_tx_output == FuriHalInfraredTxPinInternal) {
LL_TIM_OC_SetCompareCH3(
INFRARED_DMA_TIMER,
((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
@ -377,7 +374,19 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc
LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N);
LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER);
} else if(infrared_tx_output == FuriHalInfraredTxPinExtPA7) {
LL_TIM_OC_SetCompareCH1(
INFRARED_DMA_TIMER,
((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
/* LL_TIM_OCMODE_PWM2 set by DMA */
LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE);
LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N);
LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER);
}
LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER);
LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER);
LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER);
@ -386,11 +395,13 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc
static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) {
LL_DMA_InitTypeDef dma_config = {0};
if(infrared_external_output) {
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1);
} else {
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2);
if(infrared_tx_output == FuriHalInfraredTxPinInternal) {
dma_config.PeriphOrM2MSrcAddress = (uint32_t)(&(INFRARED_DMA_TIMER->CCMR2));
} else if(infrared_tx_output == FuriHalInfraredTxPinExtPA7) {
dma_config.PeriphOrM2MSrcAddress = (uint32_t)(&(INFRARED_DMA_TIMER->CCMR1));
}
dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_NORMAL;
@ -587,11 +598,8 @@ static void furi_hal_infrared_async_tx_free_resources(void) {
(furi_hal_infrared_state == InfraredStateIdle) ||
(furi_hal_infrared_state == InfraredStateAsyncTxStopped));
if(infrared_external_output) {
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
} else {
furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
}
furi_hal_gpio_init(
infrared_tx_pins[infrared_tx_output], GpioModeAnalog, GpioPullDown, GpioSpeedLow);
furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL);
furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL);
@ -652,22 +660,11 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) {
furi_delay_us(5);
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */
furi_delay_us(5);
if(infrared_external_output) {
LL_GPIO_ResetOutputPin(
gpio_ext_pa7.port, gpio_ext_pa7.pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex(
&gpio_ext_pa7, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1);
} else {
LL_GPIO_ResetOutputPin(
gpio_infrared_tx.port,
gpio_infrared_tx.pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex(
&gpio_infrared_tx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedHigh,
GpioAltFn1TIM1);
}
const GpioPin* tx_gpio = infrared_tx_pins[infrared_tx_output];
LL_GPIO_ResetOutputPin(tx_gpio->port, tx_gpio->pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex(
tx_gpio, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1);
FURI_CRITICAL_ENTER();
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */
@ -712,3 +709,23 @@ void furi_hal_infrared_async_tx_set_signal_sent_isr_callback(
infrared_tim_tx.signal_sent_callback = callback;
infrared_tim_tx.signal_sent_context = context;
}
FuriHalInfraredTxPin furi_hal_infrared_detect_tx_output(void) {
for(FuriHalInfraredTxPin pin = FuriHalInfraredTxPinInternal + 1; //-V1008
pin < FuriHalInfraredTxPinMax;
++pin) {
const GpioPin* gpio = infrared_tx_pins[pin];
furi_hal_gpio_init(gpio, GpioModeInput, GpioPullUp, GpioSpeedLow);
furi_hal_cortex_delay_us(1000U);
const bool level = furi_hal_gpio_read(gpio);
furi_hal_gpio_init(gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
if(!level) return pin;
}
return FuriHalInfraredTxPinInternal;
}
void furi_hal_infrared_set_tx_output(FuriHalInfraredTxPin tx_pin) {
furi_check(tx_pin < FuriHalInfraredTxPinMax);
infrared_tx_output = tx_pin;
}

View File

@ -354,6 +354,13 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) {
return hid_send_report(ReportIdConsumer);
}
bool furi_hal_hid_consumer_key_release_all(void) {
for(uint8_t key_nb = 0; key_nb < HID_CONSUMER_MAX_KEYS; key_nb++) {
hid_report.consumer.btn[key_nb] = 0;
}
return hid_send_report(ReportIdConsumer);
}
static void* hid_set_string_descr(char* str) {
furi_assert(str);

View File

@ -16,6 +16,12 @@ extern "C" {
#define INFRARED_MAX_FREQUENCY 56000
#define INFRARED_MIN_FREQUENCY 10000
typedef enum {
FuriHalInfraredTxPinInternal,
FuriHalInfraredTxPinExtPA7,
FuriHalInfraredTxPinMax,
} FuriHalInfraredTxPin;
typedef enum {
FuriHalInfraredTxGetDataStateOk, /**< New data obtained */
FuriHalInfraredTxGetDataStateDone, /**< New data obtained, and this is end of package */
@ -149,6 +155,29 @@ void furi_hal_infrared_async_tx_set_signal_sent_isr_callback(
FuriHalInfraredTxSignalSentISRCallback callback,
void* context);
/** Detect which pin has an external IR module connected.
*
* External IR modules are detected by enabling a weak pull-up
* on supported pins and testing whether the input is still low.
*
* This method works best on modules that employ a FET with a
* strong pull-down or a BJT for driving IR LEDs.
*
* The module MUST pull the input voltage down to at least 0.9V
* or lower in order for it to be detected.
*
* If no module has been detected, FuriHalInfraredTxPinInternal is returned.
*
* @return numeric identifier of the first pin with a module detected.
*/
FuriHalInfraredTxPin furi_hal_infrared_detect_tx_output(void);
/** Set which pin will be used to transmit infrared signals.
*
* @param[in] tx_pin pin to be used for signal transmission.
*/
void furi_hal_infrared_set_tx_output(FuriHalInfraredTxPin tx_pin);
#ifdef __cplusplus
}
#endif

View File

@ -14,6 +14,11 @@ extern "C" {
/** Max number of simultaneously pressed keys (consumer control) */
#define HID_CONSUMER_MAX_KEYS 2
/** OS-specific consumer keys, defined as "Reserved" in HID Usage Tables document */
#define HID_CONSUMER_BRIGHTNESS_INCREMENT 0x006F
#define HID_CONSUMER_BRIGHTNESS_DECREMENT 0x0070
#define HID_CONSUMER_FN_GLOBE 0x029D
#define HID_KEYBOARD_NONE 0x00
/** HID keyboard modifier keys */
@ -259,6 +264,11 @@ bool furi_hal_hid_consumer_key_press(uint16_t button);
*/
bool furi_hal_hid_consumer_key_release(uint16_t button);
/** Clear all pressed consumer keys and send HID report
*
*/
bool furi_hal_hid_consumer_key_release_all(void);
#ifdef __cplusplus
}
#endif