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

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

This commit is contained in:
MX
2024-03-25 14:23:44 +03:00
58 changed files with 2159 additions and 1328 deletions

View File

@@ -42,6 +42,7 @@ distenv = coreenv.Clone(
"openocd", "openocd",
"blackmagic", "blackmagic",
"jflash", "jflash",
"doxygen",
], ],
ENV=os.environ, ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}", UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
@@ -417,3 +418,18 @@ distenv.PhonyTarget(
"env", "env",
"@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", "@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 // Setup view
Popup* popup = app->popup; 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"; const char* message_text = "Transmission on\nthis frequency is\nrestricted in\nyour region";
if(!furi_hal_region_is_provisioned()) { if(!furi_hal_region_is_provisioned()) {
header_text = "Firmware update needed"; header_text = "Firmware update needed";

View File

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

View File

@@ -1,11 +1,14 @@
#include "bad_usb_app_i.h" #include "bad_usb_app_i.h"
#include "bad_usb_settings_filename.h"
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include <storage/storage.h> #include <storage/storage.h>
#include <lib/toolbox/path.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) { static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context); 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) { static void bad_usb_load_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { FlipperFormat* fff = flipper_format_file_alloc(storage);
char chr; bool state = false;
while((storage_file_read(settings_file, &chr, 1) == 1) &&
!storage_file_eof(settings_file) && !isspace(chr)) { FuriString* temp_str = furi_string_alloc();
furi_string_push_back(app->keyboard_layout, chr); uint32_t version = 0;
} uint32_t interface = 0;
} else {
furi_string_reset(app->keyboard_layout); if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
} do {
storage_file_close(settings_file); if(!flipper_format_read_header(fff, temp_str, &version)) break;
storage_file_free(settings_file); 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); Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info; FileInfo layout_file_info;
FS_Error file_check_err = storage_common_stat( FS_Error file_check_err = storage_common_stat(
fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info); fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
if(file_check_err != FSE_OK) { if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) {
furi_string_reset(app->keyboard_layout); furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
return;
}
if(layout_file_info.size != 256) {
furi_string_reset(app->keyboard_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) { static void bad_usb_save_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { FlipperFormat* fff = flipper_format_file_alloc(storage);
storage_file_write(
settings_file, if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) {
furi_string_get_cstr(app->keyboard_layout), do {
furi_string_size(app->keyboard_layout)); if(!flipper_format_write_header_cstr(
storage_file_write(settings_file, "\n", 1); 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) { BadUsbApp* bad_usb_app_alloc(char* arg) {
@@ -103,13 +129,15 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
view_dispatcher_add_view( view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget)); 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( 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( 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); 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)); furi_check(furi_hal_usb_set_config(NULL, NULL));
if(!furi_string_empty(app->file_path)) { 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); scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else { } else {
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER); furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
@@ -144,15 +170,15 @@ void bad_usb_app_free(BadUsbApp* app) {
// Views // Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork); 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 // Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
widget_free(app->widget); widget_free(app->widget);
// Submenu // Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig); view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
submenu_free(app->submenu); variable_item_list_free(app->var_item_list);
// View dispatcher // View dispatcher
view_dispatcher_free(app->view_dispatcher); view_dispatcher_free(app->view_dispatcher);

View File

@@ -3,12 +3,12 @@
#include "bad_usb_app.h" #include "bad_usb_app.h"
#include "scenes/bad_usb_scene.h" #include "scenes/bad_usb_scene.h"
#include "helpers/ducky_script.h" #include "helpers/ducky_script.h"
#include "helpers/bad_usb_hid.h"
#include <gui/gui.h> #include <gui/gui.h>
#include <assets_icons.h> #include <assets_icons.h>
#include <gui/view_dispatcher.h> #include <gui/view_dispatcher.h>
#include <gui/scene_manager.h> #include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <dialogs/dialogs.h> #include <dialogs/dialogs.h>
#include <notification/notification_messages.h> #include <notification/notification_messages.h>
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
@@ -33,7 +33,7 @@ struct BadUsbApp {
NotificationApp* notifications; NotificationApp* notifications;
DialogsApp* dialogs; DialogsApp* dialogs;
Widget* widget; Widget* widget;
Submenu* submenu; VariableItemList* var_item_list;
BadUsbAppError error; BadUsbAppError error;
FuriString* file_path; FuriString* file_path;
@@ -41,6 +41,7 @@ struct BadUsbApp {
BadUsb* bad_usb_view; BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script; BadUsbScript* bad_usb_script;
BadUsbHidInterface interface;
FuriHalUsbInterface* usb_if_prev; 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 <gui/gui.h>
#include <input/input.h> #include <input/input.h>
#include <lib/toolbox/args.h> #include <lib/toolbox/args.h>
#include <furi_hal_usb_hid.h>
#include <storage/storage.h> #include <storage/storage.h>
#include "ducky_script.h" #include "ducky_script.h"
#include "ducky_script_i.h" #include "ducky_script_i.h"
@@ -71,39 +70,40 @@ bool ducky_get_number(const char* param, uint32_t* val) {
return false; return false;
} }
void ducky_numlock_on(void) { void ducky_numlock_on(BadUsbScript* bad_usb) {
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) { if((bad_usb->hid->get_led_state(bad_usb->hid_inst) & HID_KB_LED_NUM) == 0) {
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK); bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
furi_hal_hid_kb_release(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; if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0']; uint16_t key = numpad_keys[num - '0'];
furi_hal_hid_kb_press(key); bad_usb->hid->kb_press(bad_usb->hid_inst, key);
furi_hal_hid_kb_release(key); bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return true; return true;
} }
bool ducky_altchar(const char* charcode) { bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode) {
uint8_t i = 0; uint8_t i = 0;
bool state = false; 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])) { 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; if(state == false) break;
i++; 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; return state;
} }
bool ducky_altstring(const char* param) { bool ducky_altstring(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0; uint32_t i = 0;
bool state = false; bool state = false;
@@ -116,7 +116,7 @@ bool ducky_altstring(const char* param) {
char temp_str[4]; char temp_str[4];
snprintf(temp_str, 4, "%u", param[i]); snprintf(temp_str, 4, "%u", param[i]);
state = ducky_altchar(temp_str); state = ducky_altchar(bad_usb, temp_str);
if(state == false) break; if(state == false) break;
i++; i++;
} }
@@ -140,12 +140,12 @@ bool ducky_string(BadUsbScript* bad_usb, const char* param) {
if(param[i] != '\n') { if(param[i] != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) { if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode); bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
furi_hal_hid_kb_release(keycode); bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
} }
} else { } else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
} }
i++; i++;
} }
@@ -163,12 +163,12 @@ static bool ducky_string_next(BadUsbScript* bad_usb) {
if(print_char != '\n') { if(print_char != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char); uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char);
if(keycode != HID_KEYBOARD_NONE) { if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode); bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
furi_hal_hid_kb_release(keycode); bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
} }
} else { } else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
} }
bad_usb->string_print_pos++; 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); key |= ducky_get_keycode(bad_usb, line_tmp + offset, true);
} }
} }
furi_hal_hid_kb_press(key); bad_usb->hid->kb_press(bad_usb->hid_inst, key);
furi_hal_hid_kb_release(key); bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0; return 0;
} }
@@ -235,6 +235,17 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
return false; 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) { static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
uint8_t ret = 0; uint8_t ret = 0;
uint32_t line_len = 0; uint32_t line_len = 0;
@@ -269,10 +280,11 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
} }
if(id_set) { 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 { } 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); storage_file_seek(script_file, 0, true);
furi_string_reset(bad_usb->line); 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; 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) { static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get(); uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0); 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->line_prev = furi_string_alloc();
bad_usb->string_print = 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) { while(1) {
if(worker_state == BadUsbStateInit) { // State: initialization if(worker_state == BadUsbStateInit) { // State: initialization
if(storage_file_open( if(storage_file_open(
@@ -396,7 +395,7 @@ static int32_t bad_usb_worker(void* context) {
FSAM_READ, FSAM_READ,
FSOM_OPEN_EXISTING)) { FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) { 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 worker_state = BadUsbStateIdle; // Ready to run
} else { } else {
worker_state = BadUsbStateNotConnected; // USB not connected 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 } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
uint32_t flags = bad_usb_flags_get( uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever); WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
if(flags & WorkerEvtEnd) { if(flags & WorkerEvtEnd) {
break; break;
@@ -494,10 +494,10 @@ static int32_t bad_usb_worker(void* context) {
break; break;
} else if(flags & WorkerEvtStartStop) { } else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script 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) { } else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all(); bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) { } else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateRunning; pause_state = BadUsbStateRunning;
worker_state = BadUsbStatePaused; // Pause worker_state = BadUsbStatePaused; // Pause
@@ -517,12 +517,12 @@ static int32_t bad_usb_worker(void* context) {
delay_val = 0; delay_val = 0;
worker_state = BadUsbStateScriptError; worker_state = BadUsbStateScriptError;
bad_usb->st.state = worker_state; 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 } else if(delay_val == SCRIPT_STATE_END) { // End of script
delay_val = 0; delay_val = 0;
worker_state = BadUsbStateIdle; worker_state = BadUsbStateIdle;
bad_usb->st.state = BadUsbStateDone; bad_usb->st.state = BadUsbStateDone;
furi_hal_hid_kb_release_all(); bad_usb->hid->release_all(bad_usb->hid_inst);
continue; continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_usb->defdelay; delay_val = bad_usb->defdelay;
@@ -550,7 +550,7 @@ static int32_t bad_usb_worker(void* context) {
worker_state = BadUsbStateRunning; worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtDisconnect) { } else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected 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; bad_usb->st.state = worker_state;
continue; continue;
@@ -565,11 +565,11 @@ static int32_t bad_usb_worker(void* context) {
} else if(flags & WorkerEvtStartStop) { } else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->st.state = worker_state; 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) { } else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected worker_state = BadUsbStateNotConnected; // USB disconnected
bad_usb->st.state = worker_state; 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) { } else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadUsbStateRunning) { if(pause_state == BadUsbStateRunning) {
if(delay_val > 0) { if(delay_val > 0) {
@@ -599,10 +599,10 @@ static int32_t bad_usb_worker(void* context) {
break; break;
} else if(flags & WorkerEvtStartStop) { } else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script 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) { } else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all(); bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) { } else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateStringDelay; pause_state = BadUsbStateStringDelay;
worker_state = BadUsbStatePaused; // Pause 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_close(script_file);
storage_file_free(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))); 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); furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); 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.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0'; 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); bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread); furi_thread_start(bad_usb->thread);

View File

@@ -6,6 +6,7 @@ extern "C" {
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include "bad_usb_hid.h"
typedef enum { typedef enum {
BadUsbStateInit, BadUsbStateInit,
@@ -33,7 +34,7 @@ typedef struct {
typedef struct BadUsbScript BadUsbScript; 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); void bad_usb_script_close(BadUsbScript* bad_usb);

View File

@@ -1,5 +1,4 @@
#include <furi_hal.h> #include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script.h" #include "ducky_script.h"
#include "ducky_script_i.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]; line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true); uint16_t key = ducky_get_keycode(bad_usb, line, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key); bad_usb->hid->kb_press(bad_usb->hid_inst, key);
furi_hal_hid_kb_release_all(); bad_usb->hid->release_all(bad_usb->hid_inst);
return 0; return 0;
} }
@@ -103,8 +102,8 @@ static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_
UNUSED(param); UNUSED(param);
line = &line[ducky_get_command_len(line) + 1]; line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(); ducky_numlock_on(bad_usb);
bool state = ducky_altchar(line); bool state = ducky_altchar(bad_usb, line);
if(!state) { if(!state) {
return ducky_error(bad_usb, "Invalid altchar %s", line); 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); UNUSED(param);
line = &line[ducky_get_command_len(line) + 1]; line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(); ducky_numlock_on(bad_usb);
bool state = ducky_altstring(line); bool state = ducky_altstring(bad_usb, line);
if(!state) { if(!state) {
return ducky_error(bad_usb, "Invalid altstring %s", line); 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)) { if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are hold"); 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; 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"); return ducky_error(bad_usb, "No keys are hold");
} }
bad_usb->key_hold_nb--; 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; return 0;
} }
@@ -183,6 +211,8 @@ static const DuckyCmd ducky_commands[] = {
{"HOLD", ducky_fnc_hold, -1}, {"HOLD", ducky_fnc_hold, -1},
{"RELEASE", ducky_fnc_release, -1}, {"RELEASE", ducky_fnc_release, -1},
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1}, {"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
{"MEDIA", ducky_fnc_media, -1},
{"GLOBE", ducky_fnc_globe, -1},
}; };
#define TAG "BadUsb" #define TAG "BadUsb"

View File

@@ -7,6 +7,7 @@ extern "C" {
#include <furi.h> #include <furi.h>
#include <furi_hal.h> #include <furi_hal.h>
#include "ducky_script.h" #include "ducky_script.h"
#include "bad_usb_hid.h"
#define SCRIPT_STATE_ERROR (-1) #define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2) #define SCRIPT_STATE_END (-2)
@@ -19,6 +20,8 @@ extern "C" {
struct BadUsbScript { struct BadUsbScript {
FuriHalUsbHidConfig hid_cfg; FuriHalUsbHidConfig hid_cfg;
const BadUsbHidApi* hid;
void* hid_inst;
FuriThread* thread; FuriThread* thread;
BadUsbState st; 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_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); 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); bool ducky_string(BadUsbScript* bad_usb, const char* param);

View File

@@ -1,5 +1,4 @@
#include <furi_hal.h> #include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script_i.h" #include "ducky_script_i.h"
typedef struct { typedef struct {
@@ -78,6 +77,37 @@ static const DuckyKey ducky_keys[] = {
{"F24", HID_KEYBOARD_F24}, {"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) { uint16_t ducky_get_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) { for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name); 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; 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 "../bad_usb_app_i.h"
#include "furi_hal_power.h" #include "furi_hal_power.h"
#include "furi_hal_usb.h"
enum SubmenuIndex { 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; 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) { void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context; BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu; VariableItemList* var_item_list = bad_usb->var_item_list;
submenu_add_item( variable_item_list_set_enter_callback(
submenu, var_item_list, bad_usb_scene_config_select_callback, bad_usb);
"Keyboard Layout (global)", draw_menu(bad_usb);
SubmenuIndexKeyboardLayout, variable_item_list_set_selected_item(var_item_list, 0);
bad_usb_scene_config_submenu_callback,
bad_usb);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig));
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig); 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; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event);
consumed = true; consumed = true;
if(event.event == SubmenuIndexKeyboardLayout) { if(event.event == ConfigIndexKeyboardLayout) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout); 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 { } else {
furi_crash("Unknown key type"); 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) { void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = 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 "../bad_usb_app_i.h"
#include "furi_hal_power.h" #include "furi_hal_power.h"
#include "furi_hal_usb.h"
#include <storage/storage.h> #include <storage/storage.h>
static bool bad_usb_layout_select(BadUsbApp* bad_usb) { 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) { } else if(app->error == BadUsbAppErrorCloseRpc) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element( 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( widget_add_string_multiline_element(
app->widget, app->widget,
3, 3,

View File

@@ -1,6 +1,5 @@
#include "../bad_usb_app_i.h" #include "../bad_usb_app_i.h"
#include <furi_hal_power.h> #include <furi_hal_power.h>
#include <furi_hal_usb.h>
#include <storage/storage.h> #include <storage/storage.h>
static bool bad_usb_file_select(BadUsbApp* bad_usb) { 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)) { 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); scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else { } else {
view_dispatcher_stop(bad_usb->view_dispatcher); 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.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) { 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); scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
} }
consumed = true; consumed = true;
@@ -28,7 +31,7 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
} }
} else if(event.type == SceneManagerEventTypeTick) { } 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; 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) { void bad_usb_scene_work_on_enter(void* context) {
BadUsbApp* app = 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; FuriString* file_name;
file_name = furi_string_alloc(); file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true); 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); furi_string_free(file_name);
FuriString* layout; FuriString* layout;
layout = furi_string_alloc(); layout = furi_string_alloc();
path_extract_filename(app->keyboard_layout, layout, true); 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); 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_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_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect"); 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) { } else if(state == BadUsbStateWillRun) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18); canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
@@ -193,7 +193,7 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) {
return consumed; return consumed;
} }
BadUsb* bad_usb_alloc(void) { BadUsb* bad_usb_view_alloc(void) {
BadUsb* bad_usb = malloc(sizeof(BadUsb)); BadUsb* bad_usb = malloc(sizeof(BadUsb));
bad_usb->view = view_alloc(); bad_usb->view = view_alloc();
@@ -205,18 +205,21 @@ BadUsb* bad_usb_alloc(void) {
return bad_usb; return bad_usb;
} }
void bad_usb_free(BadUsb* bad_usb) { void bad_usb_view_free(BadUsb* bad_usb) {
furi_assert(bad_usb); furi_assert(bad_usb);
view_free(bad_usb->view); view_free(bad_usb->view);
free(bad_usb); free(bad_usb);
} }
View* bad_usb_get_view(BadUsb* bad_usb) { View* bad_usb_view_get_view(BadUsb* bad_usb) {
furi_assert(bad_usb); furi_assert(bad_usb);
return bad_usb->view; 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(bad_usb);
furi_assert(callback); furi_assert(callback);
with_view_model( with_view_model(
@@ -230,7 +233,7 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback,
true); 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); furi_assert(name);
with_view_model( with_view_model(
bad_usb->view, bad_usb->view,
@@ -239,7 +242,7 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
true); 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); furi_assert(layout);
with_view_model( with_view_model(
bad_usb->view, bad_usb->view,
@@ -248,7 +251,7 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
true); 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); furi_assert(st);
with_view_model( with_view_model(
bad_usb->view, bad_usb->view,
@@ -263,7 +266,7 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
true); true);
} }
bool bad_usb_is_idle_state(BadUsb* bad_usb) { bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false; bool is_idle = false;
with_view_model( with_view_model(
bad_usb->view, bad_usb->view,

View File

@@ -6,18 +6,21 @@
typedef struct BadUsb BadUsb; typedef struct BadUsb BadUsb;
typedef void (*BadUsbButtonCallback)(InputKey key, void* context); 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_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element( 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( widget_add_string_multiline_element(
app->widget, app->widget,
3, 3,

View File

@@ -6,7 +6,7 @@ void infrared_scene_learn_done_on_enter(void* context) {
if(infrared->app_state.is_learning_new_remote) { if(infrared->app_state.is_learning_new_remote) {
popup_set_icon(popup, 48, 6, &I_DolphinDone_80x58); 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 { } else {
popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58); popup_set_icon(popup, 36, 5, &I_DolphinSaved_92x58);
popup_set_header(popup, "Saved", 15, 19, AlignLeft, AlignBottom); 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_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned( 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 size_t btn_number = InfraredMoveViewItemArray_size(model->labels);
const bool show_scrollbar = btn_number > LIST_ITEMS; 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) { } else if(app->error == U2fAppErrorCloseRpc) {
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
widget_add_string_multiline_element( 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( widget_add_string_multiline_element(
app->widget, app->widget,
3, 3,

View File

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

View File

@@ -29,7 +29,7 @@ extern "C" {
* @param width progress bar width * @param width progress bar width
* @param progress progress (0.0 - 1.0) * @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. /** 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( void elements_progress_bar_with_text(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t width, size_t width,
float progress, float progress,
const char* text); const char* text);
@@ -59,11 +59,11 @@ void elements_progress_bar_with_text(
*/ */
void elements_scrollbar_pos( void elements_scrollbar_pos(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t height, size_t height,
uint16_t pos, size_t pos,
uint16_t total); size_t total);
/** Draw scrollbar on canvas. /** Draw scrollbar on canvas.
* @note width 3px, height equal to canvas height * @note width 3px, height equal to canvas height
@@ -72,7 +72,7 @@ void elements_scrollbar_pos(
* @param pos current element of total elements * @param pos current element of total elements
* @param total 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 /** 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 x, y top left corner coordinates
* @param width, height frame width and height * @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 /** Draw button in left corner
* *
@@ -112,8 +112,8 @@ void elements_button_center(Canvas* canvas, const char* str);
*/ */
void elements_multiline_text_aligned( void elements_multiline_text_aligned(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text); const char* text);
@@ -124,7 +124,7 @@ void elements_multiline_text_aligned(
* @param x, y top left corner coordinates * @param x, y top left corner coordinates
* @param text string (possible multiline) * @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 /** 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 x, y top left corner coordinates
* @param text string (possible multiline) * @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 /** 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( void elements_slightly_rounded_frame(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t width, size_t width,
uint8_t height); size_t height);
/** Draw slightly rounded box /** Draw slightly rounded box
* *
@@ -155,10 +155,10 @@ void elements_slightly_rounded_frame(
*/ */
void elements_slightly_rounded_box( void elements_slightly_rounded_box(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t width, size_t width,
uint8_t height); size_t height);
/** Draw bold rounded frame /** Draw bold rounded frame
* *
@@ -166,12 +166,7 @@ void elements_slightly_rounded_box(
* @param x, y top left corner coordinates * @param x, y top left corner coordinates
* @param width, height size of frame * @param width, height size of frame
*/ */
void elements_bold_rounded_frame( void elements_bold_rounded_frame(Canvas* canvas, int32_t x, int32_t y, size_t width, size_t height);
Canvas* canvas,
uint8_t x,
uint8_t y,
uint8_t width,
uint8_t height);
/** Draw bubble frame for text /** Draw bubble frame for text
* *
@@ -181,7 +176,7 @@ void elements_bold_rounded_frame(
* @param width bubble width * @param width bubble width
* @param height bubble height * @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 /** 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( void elements_bubble_str(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
const char* text, const char* text,
Align horizontal, Align horizontal,
Align vertical); Align vertical);
@@ -206,7 +201,7 @@ void elements_bubble_str(
* @param string string to trim * @param string string to trim
* @param width max width * @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 /** 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( void elements_scrollable_text_line(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t width, size_t width,
FuriString* string, FuriString* string,
size_t scroll, size_t scroll,
bool ellipsis); bool ellipsis);
@@ -254,10 +249,10 @@ void elements_scrollable_text_line_str(
*/ */
void elements_text_box( void elements_text_box(
Canvas* canvas, Canvas* canvas,
uint8_t x, int32_t x,
uint8_t y, int32_t y,
uint8_t width, size_t width,
uint8_t height, size_t height,
Align horizontal, Align horizontal,
Align vertical, Align vertical,
const char* text, const char* text,

View File

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

View File

@@ -100,7 +100,7 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
line_num++; line_num++;
model->text = furi_string_get_cstr(model->text_formatted); model->text = furi_string_get_cstr(model->text_formatted);
model->text_pos = (char*)model->text; 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) { if(model->focus == TextBoxFocusEnd && line_num > lines_on_screen) {
// Set text position to 5th line from the end // Set text position to 5th line from the end
const char* end = model->text + furi_string_size(model->text_formatted); 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); void view_holder_stop(ViewHolder* view_holder);
/** View Update Handler /** 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); 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. submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch.
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); 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_context(app->popup, app);
popup_set_callback(app->popup, pin_disable_back_callback); popup_set_callback(app->popup, pin_disable_back_callback);
popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_119x62); 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_set_timeout(app->popup, 1500);
popup_enable_timeout(app->popup); popup_enable_timeout(app->popup);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); 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) { if(!app->settings.pin_code.length) {
submenu_add_item( submenu_add_item(
submenu, submenu,
"Set Pin", "Set PIN",
SCENE_EVENT_SET_PIN, SCENE_EVENT_SET_PIN,
desktop_settings_scene_pin_menu_submenu_callback, desktop_settings_scene_pin_menu_submenu_callback,
app); app);
@@ -30,7 +30,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
} else { } else {
submenu_add_item( submenu_add_item(
submenu, submenu,
"Change Pin", "Change PIN",
SCENE_EVENT_CHANGE_PIN, SCENE_EVENT_CHANGE_PIN,
desktop_settings_scene_pin_menu_submenu_callback, desktop_settings_scene_pin_menu_submenu_callback,
app); app);
@@ -43,7 +43,7 @@ void desktop_settings_scene_pin_menu_on_enter(void* context) {
app); 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); submenu_set_selected_item(app->submenu, app->menu_idx);
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); 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_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_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_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( desktop_view_pin_input_set_label_secondary(
app->pin_input_view, 7, 45, "Remember or write it down"); app->pin_input_view, 7, 45, "Remember or write it down");
desktop_view_pin_input_lock_input(app->pin_input_view); 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"); elements_button_right(canvas, "Next");
canvas_set_font(canvas, FontPrimary); 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); canvas_set_font(canvas, FontSecondary);
elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols"); 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; PowerSettingsApp* app = context;
DialogEx* dialog = app->dialog; 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_ex_set_text(
dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop); dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52); 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; PowerSettingsApp* app = context;
Submenu* submenu = app->submenu; Submenu* submenu = app->submenu;
submenu_set_header(submenu, "Reboot type"); submenu_set_header(submenu, "Reboot Type");
submenu_add_item( submenu_add_item(
submenu, submenu,
"Firmware upgrade", "Firmware Upgrade",
PowerSettingsRebootSubmenuIndexDfu, PowerSettingsRebootSubmenuIndexDfu,
power_settings_scene_reboot_submenu_callback, power_settings_scene_reboot_submenu_callback,
app); 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 # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # doxygen (www.doxygen.org) for a project.
@@ -12,6 +12,16 @@
# For lists, items can also be appended using: # For lists, items can also be appended using:
# TAG += value [value, ...] # TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \"). # 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 # Project related configuration options
@@ -51,25 +61,43 @@ PROJECT_BRIEF =
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory. # 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 # 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 # 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 # entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used. # 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- # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
# directories (in 2 levels) under the output directory of each output format and # sub-directories (in 2 levels) under the output directory of each output format
# will distribute the generated files over these directories. Enabling this # 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 # 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 # 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. # The default value is: NO.
CREATE_SUBDIRS = 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 # 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 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 # 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 # The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this # documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language. # information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # English messages), Korean, Korean-en (Korean with English messages), Latvian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
# Ukrainian and Vietnamese. # Swedish, Turkish, Ukrainian and Vietnamese.
# The default value is: English. # The default value is: English.
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
@@ -341,13 +369,24 @@ MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5 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 # When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can # 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 # be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO. # globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES. # 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 # 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 # 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 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 # 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 # 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 # 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 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 # 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 # 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 # 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 # 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. # The default value is: NO.
HIDE_UNDOC_CLASSES = 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 # 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 # 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 # 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 # 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 # 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 # references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option # 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 # to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES. # YES.
# The default value is: system dependent. # Possible values are: SYSTEM, NO and YES.
# The default value is: SYSTEM.
CASE_SENSE_NAMES = NO CASE_SENSE_NAMES = NO
@@ -793,7 +842,7 @@ CITE_BIB_FILES =
# messages are off. # messages are off.
# The default value is: NO. # The default value is: NO.
QUIET = NO QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are # 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 # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
@@ -809,7 +858,7 @@ WARNINGS = YES
# will automatically be disabled. # will automatically be disabled.
# The default value is: YES. # 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 # 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 # potential errors in the documentation, such as documenting some parameters in
@@ -834,16 +883,31 @@ WARN_IF_INCOMPLETE_DOC = YES
# WARN_IF_INCOMPLETE_DOC # WARN_IF_INCOMPLETE_DOC
# The default value is: NO. # 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 # 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 # 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 # 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. # 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. # 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 # 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 # 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 # 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 # be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER) # FILE_VERSION_FILTER)
# See also: WARN_LINE_FORMAT
# The default value is: $file:$line: $text. # The default value is: $file:$line: $text.
WARN_FORMAT = "$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 # 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 # 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 = WARN_LOGFILE =
@@ -871,20 +949,34 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = applications \ INPUT = $(DOXY_SRC_ROOT)/applications \
lib \ $(DOXY_SRC_ROOT)/documentation \
firmware \ $(DOXY_SRC_ROOT)/targets \
furi $(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 # 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 # 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 # libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: # documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings. # https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8. # The default value is: UTF-8.
INPUT_ENCODING = 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 # 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 # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories. # *.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 # Note the list of default checked file patterns might differ from the list of
# default file extension mappings. # default file extension mappings.
# #
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl,
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d,
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.vhdl, *.ucf, *.qsf and *.ice. # *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
*.cc \ *.cc \
@@ -927,19 +1019,45 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is # Note that relative paths are relative to the directory from which doxygen is
# run. # run.
EXCLUDE = \ EXCLUDE = $(DOXY_SRC_ROOT)/lib/mlib \
lib/mlib \ $(DOXY_SRC_ROOT)/lib/STM32CubeWB \
lib/stm32wb_cmsis \ $(DOXY_SRC_ROOT)/lib/littlefs \
lib/stm32wb_copro \ $(DOXY_SRC_ROOT)/lib/nanopb \
lib/stm32wb_hal_driver \ $(DOXY_SRC_ROOT)/assets/protobuf \
lib/littlefs \ $(DOXY_SRC_ROOT)/lib/libusb_stm32 \
lib/nanopb \ $(DOXY_SRC_ROOT)/lib/FreeRTOS-Kernel \
assets/protobuf \ $(DOXY_SRC_ROOT)/lib/microtar \
lib/libusb_stm32 \ $(DOXY_SRC_ROOT)/lib/mbedtls \
lib/FreeRTOS-Kernel \ $(DOXY_SRC_ROOT)/lib/cxxheaderparser \
lib/microtar \ $(DOXY_SRC_ROOT)/lib/ST25RFAL002 \
lib/mbedtls \ $(DOXY_SRC_ROOT)/lib/fatfs \
lib/cxxheaderparser $(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 # 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 # 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 # (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 # output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass, # wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test # ANamespace::AClass, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS = EXCLUDE_SYMBOLS =
@@ -1009,6 +1124,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added # code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly. # 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 # 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 # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen. # properly processed by doxygen.
@@ -1050,6 +1170,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = 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 # Configuration options related to source browsing
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -1064,7 +1193,8 @@ USE_MDFILE_AS_MAINPAGE =
SOURCE_BROWSER = NO SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body of functions, # 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. # The default value is: NO.
INLINE_SOURCES = NO INLINE_SOURCES = NO
@@ -1147,10 +1277,11 @@ VERBATIM_HEADERS = YES
ALPHABETICAL_INDEX = YES ALPHABETICAL_INDEX = YES
# In case all classes in a project start with a common prefix, all classes will # The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # that should be ignored while generating the index headers. The IGNORE_PREFIX
# can be used to specify a prefix (or a list of prefixes) that should be ignored # tag works for classes, function and member names. The entity will be placed in
# while generating the index headers. # 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. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX = IGNORE_PREFIX =
@@ -1229,7 +1360,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory. # 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 # 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 # 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. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET = HTML_EXTRA_STYLESHEET =
@@ -1244,6 +1380,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES = 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 # 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 # 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 # 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 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 # 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 # documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will # are dynamically created via JavaScript. If disabled, the navigation index will
@@ -1302,6 +1442,33 @@ HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO 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 # 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 # shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to # and collapse entries dynamically later on. Doxygen will expand the tree to
@@ -1338,6 +1505,13 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs" 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 # This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g. # set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name. # com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@@ -1425,6 +1599,16 @@ BINARY_TOC = NO
TOC_EXPAND = 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 # 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 # 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 # 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 # 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 # YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the # 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. # DISABLE_INDEX is set to NO, this option has no effect.
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1573,6 +1757,13 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO 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 # 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 # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for # https://inkscape.org) to generate formulas as SVG images instead of PNGs for
@@ -1593,17 +1784,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10 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 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See # to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details. # 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 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example # 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 # for MathJax version 2 (see
# #tex-and-latex-extensions): # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# For example for MathJax version 3 (see # For example for MathJax version 3 (see
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
@@ -1917,9 +2097,16 @@ PDF_HYPERLINKS = YES
USE_PDFLATEX = YES USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
# command to the generated LaTeX files. This will instruct LaTeX to keep running # Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
# if errors occur, instead of asking the user for help. # 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. # The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES. # This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1940,14 +2127,6 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain 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) # 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, # 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 # 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 # 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 # the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment. # is still experimental and incomplete at the moment.
# The default value is: NO. # The default value is: NO.
GENERATE_AUTOGEN_DEF = 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 # 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 # 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 # 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. # This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH = INCLUDE_PATH =
@@ -2261,15 +2467,15 @@ TAGFILES =
GENERATE_TAGFILE = GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in # If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
# the class index. If set to NO, only the inherited external classes will be # will be listed in the class and namespace index. If set to NO, only the
# listed. # inherited external classes will be listed.
# The default value is: NO. # The default value is: NO.
ALLEXTERNALS = NO ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed # 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. # listed.
# The default value is: YES. # The default value is: YES.
@@ -2283,25 +2489,9 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = 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 # 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. # and usage relations if the target is undocumented or is not a class.
# The default value is: YES. # 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 # 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: # 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 # Bell Labs. The other options in this section have no effect if this option is
# set to NO # set to NO
# The default value is: NO. # The default value is: NO.
@@ -2327,49 +2517,77 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0 DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen # DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# generates you can specify the font name using DOT_FONTNAME. You need to make # subgraphs. When you want a differently looking font in the dot files that
# sure dot is able to find the font, which can be done by putting it in a # doxygen generates you can specify fontname, fontcolor and fontsize attributes.
# standard location or by setting the DOTFONTPATH environment variable or by # For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
# setting DOT_FONTPATH to the directory containing the font. # Edge and Graph Attributes specification</a> You need to make sure dot is able
# The default value is: Helvetica. # 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. # 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_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
# dot graphs. # add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
# Minimum value: 4, maximum value: 24, default value: 10. # 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. # 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_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set # around nodes set 'shape=plain' or 'shape=plaintext' <a
# the path where dot can find it using this tag. # 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. # This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH = DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
# each documented class showing the direct and indirect inheritance relations. # generate a graph for each documented class showing the direct and indirect
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # 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 # graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES COLLABORATION_GRAPH = YES
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to 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 # 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 # 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 # significantly it will be wrapped across multiple lines. Some heuristics are
# to avoid ugly line breaks. # applied to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17. # Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES. # 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 # 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 # YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to 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 # 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 # 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 # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to 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 # 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 # dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES. # This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = 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 # 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 # generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see: # 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 # 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 # to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement). # requirement).
@@ -2524,11 +2757,12 @@ DOT_PATH =
DOTFILE_DIRS = DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that # You can include diagrams made with dia in doxygen documentation. Doxygen will
# contain msc files that are included in the documentation (see the \mscfile # then run dia to produce the diagram and insert it in the documentation. The
# command). # 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 # 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 # contain dia files that are included in the documentation (see the \diafile
@@ -2537,10 +2771,10 @@ MSCFILE_DIRS =
DIAFILE_DIRS = DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # 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 # path where java can find the plantuml.jar file or to the filename of jar file
# PlantUML is not used or called during a preprocessing step. Doxygen will # to be used. If left blank, it is assumed PlantUML is not used or called during
# generate a warning when it encounters a \startuml command in this case and # a preprocessing step. Doxygen will generate a warning when it encounters a
# will not generate output for the diagram. # \startuml command in this case and will not generate output for the diagram.
PLANTUML_JAR_PATH = PLANTUML_JAR_PATH =
@@ -2578,18 +2812,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0 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 # 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 # 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 # 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 # 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 # explaining the meaning of the various boxes and arrows in the dot generated
# graphs. # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to 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. # The default value is: YES.
DOT_CLEANUP = 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} # 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). **For Linux & macOS:**
![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:
```text ```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. **For Windows:**
### 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:
```text ```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. 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 ```text
ls /dev/cu.* 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 ```text
ls /dev/tty* ls /dev/tty*
``` ```
View the devices in the list. 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) ![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. Switch your Developer Board to Bootloader mode:
3.1. Press and hold the **BOOT** button. 3.1. Press and hold the **BOOT** button.
3.2. Press the **RESET** button while holding the **BOOT** button. 3.2. Press the **RESET** button while holding the **BOOT** button.
3.3. Release 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) ![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. 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 ## 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 ## If flashing failed
cat flash.command
```
If you see a similar output, you can proceed to the Flashing step: If you get an error message during the flashing process, such as this:
```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:
```text ```text
A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption. A fatal error occurred: Serial data stream stopped: Possible serial noise or corruption.
``` ```
or Or this:
```text ```text
FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01' FileNotFoundError: [Errno 2] No such file or directory: '/dev/cu.usbmodem01'
@@ -239,8 +112,11 @@ Try doing the following:
## Finishing the installation ## 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) ![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. 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. 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 ## 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** * **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 ```text
xcode-select --install xcode-select --install
@@ -26,11 +26,11 @@ Youll need Git installed on your computer to clone the firmware repository. I
* **Linux** * **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 ```text
sudo apt install git sudo apt install git
``` ```
For other distributions, refer to your package manager documentation. 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. 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 ## 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: 2. On your computer, open the **Terminal** and run the following:
* **MacOS** * **MacOS**
```text ```text
ls /dev/cu.* ls /dev/cu.*
``` ```
* **Linux** * **Linux**
```text ```text
ls /dev/tty* 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. 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:** 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). > **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 ## 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) ![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) ![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: 3. Connect to the network:
* Name: **blackmagic** * Name: **blackmagic**
* Password: **iamwitcher** * Password: **iamwitcher**
4. To configure the Developer Board, open a browser and go to `http://192.168.4.1`. 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) ![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`. 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. 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) ![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) ![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: Open the **Terminal** in the **flipperzero-firmware** directory that you cloned earlier and run the following command:
```text ```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: 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. 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) ![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. > **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 ## 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) ![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: 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 ```text
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" /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: 2. After installation of Homebrew, run the following command to install minicom:
```text ```text
brew install minicom 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: 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: 2. On your computer, open the Terminal and run the following command:
```text ```text
ls /dev/cu.* 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.\ 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. Rerun the command. Two new devices have to appear: this is the Developer Board. 4. Rerun the command. Two new devices have to appear: this is the Developer Board.
```text ```text
/dev/cu.usbmodemblackmagic1 /dev/cu.usbmodemblackmagic1
/dev/cu.usbmodemblackmagic3 ```
```
```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. 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. 6. View logs of your Flipper Zero in the Terminal.
7. To quit, close the minicom window or quit via the minicom menu. **NOTE:** If no logs are shown in the Terminal, try running the command from Step 5 with another device name.
### 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.
7. To quit, close the minicom window or quit via the minicom menu. 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. 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. 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. 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. 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. 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**. 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. 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`, `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. - `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`. - `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. - `cli` - start a Flipper CLI session over USB.
### Firmware targets ### 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 | | HOLD | Special key or single character | Press and hold key until RELEASE command |
| RELEASE | Special key or single character | Release key | | RELEASE | Special key or single character | Release key |
## Wait for button press ## String
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
| Command | Parameters | Notes | | Command | Parameters | Notes |
| ------- | ----------- | ----------------- | | ------- | ----------- | ----------------- |
@@ -126,7 +118,54 @@ Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key)
| ------- | ---------------- | ----- | | ------- | ---------------- | ----- |
| SYSRQ | Single character | | | 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. 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, FlipperApplicationLoadStatusMissingImports,
} FlipperApplicationLoadStatus; } FlipperApplicationLoadStatus;
/** /** Get text description of preload status
* @brief Get text description of preload status
* @param status Status code * @param status Status code
* @return String pointer to description * @return String pointer to description
*/ */
const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status); const char* flipper_application_preload_status_to_string(FlipperApplicationPreloadStatus status);
/** /** Get text description of load status
* @brief Get text description of load status
* @param status Status code * @param status Status code
* @return String pointer to description * @return String pointer to description
*/ */
@@ -61,8 +59,7 @@ typedef struct {
uint8_t* debug_link; uint8_t* debug_link;
} FlipperApplicationState; } FlipperApplicationState;
/** /** Initialize FlipperApplication object
* @brief Initialize FlipperApplication object
* @param storage Storage instance * @param storage Storage instance
* @param api_interface ELF API interface to use for pre-loading and symbol resolving * @param api_interface ELF API interface to use for pre-loading and symbol resolving
* @return Application instance * @return Application instance
@@ -70,44 +67,44 @@ typedef struct {
FlipperApplication* FlipperApplication*
flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface); flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface);
/** /** Destroy FlipperApplication object
* @brief Destroy FlipperApplication object
* @param app Application pointer * @param app Application pointer
*/ */
void flipper_application_free(FlipperApplication* app); void flipper_application_free(FlipperApplication* app);
/** /** Validate elf file and load application metadata
* @brief Validate elf file and load application metadata *
* @param app Application pointer * @param app Application pointer
* @return Preload result code * @param[in] path The path to fap file
*
* @return Preload result code
*/ */
FlipperApplicationPreloadStatus FlipperApplicationPreloadStatus
flipper_application_preload(FlipperApplication* app, const char* path); flipper_application_preload(FlipperApplication* app, const char* path);
/** /** Validate elf file and load application manifest
* @brief Validate elf file and load application manifest *
* @param app Application pointer * @param app Application pointer
* @return Preload result code * @param[in] path The path to fap file
*
* @return Preload result code
*/ */
FlipperApplicationPreloadStatus FlipperApplicationPreloadStatus
flipper_application_preload_manifest(FlipperApplication* app, const char* path); flipper_application_preload_manifest(FlipperApplication* app, const char* path);
/** /** Get pointer to application manifest for preloaded application
* @brief Get pointer to application manifest for preloaded application
* @param app Application pointer * @param app Application pointer
* @return Pointer to application manifest * @return Pointer to application manifest
*/ */
const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app); const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplication* app);
/** /** Load sections and process relocations for already pre-loaded application
* @brief Load sections and process relocations for already pre-loaded application
* @param app Application pointer * @param app Application pointer
* @return Load result code * @return Load result code
*/ */
FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app); FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app);
/** /** Allocate application thread at entry point address, using app name and
* @brief Allocate application thread at entry point address, using app name and
* stack size from metadata. Returned thread isn't started yet. * stack size from metadata. Returned thread isn't started yet.
* Can be only called once for application instance. * Can be only called once for application instance.
* @param app Applicaiton pointer * @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); FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args);
/** /** Check if application is a plugin (not a runnable standalone app)
* @brief Check if application is a plugin (not a runnable standalone app)
* @param app Application pointer * @param app Application pointer
* @return true if application is a plugin, false otherwise * @return true if application is a plugin, false otherwise
*/ */
bool flipper_application_is_plugin(FlipperApplication* app); bool flipper_application_is_plugin(FlipperApplication* app);
/** /** Entry point prototype for standalone applications
* @brief Entry point prototype for standalone applications
*/ */
typedef int32_t (*FlipperApplicationEntryPoint)(void*); typedef int32_t (*FlipperApplicationEntryPoint)(void*);
/** /** An object that describes a plugin - must be returned by plugin's entry point
* @brief An object that describes a plugin - must be returned by plugin's entry point
*/ */
typedef struct { typedef struct {
const char* appid; const char* appid;
@@ -137,21 +131,18 @@ typedef struct {
const void* entry_point; const void* entry_point;
} FlipperAppPluginDescriptor; } FlipperAppPluginDescriptor;
/** /** Entry point prototype for plugins
* @brief Entry point prototype for plugins
*/ */
typedef const FlipperAppPluginDescriptor* (*FlipperApplicationPluginEntryPoint)(void); typedef const FlipperAppPluginDescriptor* (*FlipperApplicationPluginEntryPoint)(void);
/** /** Get plugin descriptor for preloaded plugin
* @brief Get plugin descriptor for preloaded plugin
* @param app Application pointer * @param app Application pointer
* @return Pointer to plugin descriptor * @return Pointer to plugin descriptor
*/ */
const FlipperAppPluginDescriptor* const FlipperAppPluginDescriptor*
flipper_application_plugin_get_descriptor(FlipperApplication* app); flipper_application_plugin_get_descriptor(FlipperApplication* app);
/** /** Load name and icon from FAP file.
* @brief Load name and icon from FAP file.
* *
* @param path Path to FAP file. * @param path Path to FAP file.
* @param storage Storage instance. * @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 * LFRFID worker
*/ */
@@ -54,37 +53,35 @@ typedef void (*LFRFIDWorkerEmulateRawCallback)(LFRFIDWorkerEmulateRawResult resu
typedef struct LFRFIDWorker LFRFIDWorker; typedef struct LFRFIDWorker LFRFIDWorker;
/** /** Allocate LF-RFID worker
* Allocate LF-RFID worker
* @return LFRFIDWorker* * @return LFRFIDWorker*
*/ */
LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict); LFRFIDWorker* lfrfid_worker_alloc(ProtocolDict* dict);
/** /** Free LF-RFID worker
* Free LF-RFID worker *
* @param worker * @param worker The worker
*/ */
void lfrfid_worker_free(LFRFIDWorker* worker); void lfrfid_worker_free(LFRFIDWorker* worker);
/** /** Start LF-RFID worker thread
* Start LF-RFID worker thread *
* @param worker * @param worker The worker
*/ */
void lfrfid_worker_start_thread(LFRFIDWorker* worker); void lfrfid_worker_start_thread(LFRFIDWorker* worker);
/** /** Stop LF-RFID worker thread
* Stop LF-RFID worker thread *
* @param worker * @param worker The worker
*/ */
void lfrfid_worker_stop_thread(LFRFIDWorker* worker); void lfrfid_worker_stop_thread(LFRFIDWorker* worker);
/** /** Start read mode
* @brief Start read mode
* *
* @param worker * @param worker The worker
* @param type * @param type The type
* @param callback * @param callback The callback
* @param context * @param context The context
*/ */
void lfrfid_worker_read_start( void lfrfid_worker_read_start(
LFRFIDWorker* worker, LFRFIDWorker* worker,
@@ -92,13 +89,12 @@ void lfrfid_worker_read_start(
LFRFIDWorkerReadCallback callback, LFRFIDWorkerReadCallback callback,
void* context); void* context);
/** /** Start write mode
* @brief Start write mode
* *
* @param worker * @param worker The worker
* @param protocol * @param protocol The protocol
* @param callback * @param callback The callback
* @param context * @param context The context
*/ */
void lfrfid_worker_write_start( void lfrfid_worker_write_start(
LFRFIDWorker* worker, LFRFIDWorker* worker,
@@ -126,14 +122,13 @@ void lfrfid_worker_write_and_set_pass_start(
*/ */
void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol); void lfrfid_worker_emulate_start(LFRFIDWorker* worker, LFRFIDProtocol protocol);
/** /** Start raw read mode
* @brief Start raw read mode
* *
* @param worker * @param worker The worker
* @param filename * @param filename The filename
* @param type * @param type The type
* @param callback * @param callback The callback
* @param context * @param context The context
*/ */
void lfrfid_worker_read_raw_start( void lfrfid_worker_read_raw_start(
LFRFIDWorker* worker, LFRFIDWorker* worker,
@@ -142,12 +137,12 @@ void lfrfid_worker_read_raw_start(
LFRFIDWorkerReadRawCallback callback, LFRFIDWorkerReadRawCallback callback,
void* context); void* context);
/** /** Emulate raw read mode
* Emulate raw read mode *
* @param worker * @param worker The worker
* @param filename * @param filename The filename
* @param callback * @param callback The callback
* @param context * @param context The context
*/ */
void lfrfid_worker_emulate_raw_start( void lfrfid_worker_emulate_raw_start(
LFRFIDWorker* worker, LFRFIDWorker* worker,
@@ -155,9 +150,9 @@ void lfrfid_worker_emulate_raw_start(
LFRFIDWorkerEmulateRawCallback callback, LFRFIDWorkerEmulateRawCallback callback,
void* context); void* context);
/** /** Stop all modes
* Stop all modes *
* @param worker * @param worker The worker
*/ */
void lfrfid_worker_stop(LFRFIDWorker* 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; bool protocol_detected = false;
if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { 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); MfDesfireError error = mf_desfire_poller_read_key_version(instance, 0, &key_version);
protocol_detected = (error == MfDesfireErrorNone); protocol_detected = (error == MfDesfireErrorNone);
} }

View File

@@ -143,8 +143,8 @@ MfDesfireError mf_desfire_poller_read_key_version(
MfDesfirePoller* instance, MfDesfirePoller* instance,
uint8_t key_num, uint8_t key_num,
MfDesfireKeyVersion* data) { MfDesfireKeyVersion* data) {
furi_assert(instance); furi_check(instance);
furi_assert(data); furi_check(data);
bit_buffer_set_size_bytes(instance->input_buffer, sizeof(uint8_t) * 2); 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); 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 /** 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); Compress* compress_alloc(uint16_t compress_buff_size);
/** Free encoder and decoder /** Free encoder and decoder
* *
* @param compress Compress instance * @param compress Compress instance
*/ */
void compress_free(Compress* compress); void compress_free(Compress* compress);
/** Encode data /** Encode data
* *
* @param compress Compress instance * @param compress Compress instance
* @param data_in pointer to input data * @param data_in pointer to input data
* @param data_in_size size of input data * @param data_in_size size of input data
* @param data_out maximum size of output data * @param data_out maximum size of output data
* @param data_res_size pointer to result output data size * @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( bool compress_encode(
Compress* compress, Compress* compress,
@@ -75,13 +77,14 @@ bool compress_encode(
/** Decode data /** Decode data
* *
* @param compress Compress instance * @param compress Compress instance
* @param data_in pointer to input data * @param data_in pointer to input data
* @param data_in_size size of input data * @param data_in_size size of input data
* @param data_out maximum size of output data * @param data_out maximum size of output data
* @param data_res_size pointer to result output data size * @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( bool compress_decode(
Compress* compress, 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 bf in GetBuildFailures():
for node in Flatten(bf.node): 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 # macOS
if sys.platform == "darwin": if sys.platform == "darwin":
subprocess.run(["open", node.abspath]) subprocess.run(["open", node.abspath])

View File

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

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,59.0,, Version,+,60.3,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@@ -852,25 +852,25 @@ Function,-,dprintf,int,"int, const char*, ..."
Function,-,drand48,double, Function,-,drand48,double,
Function,-,drem,double,"double, double" Function,-,drem,double,"double, double"
Function,-,dremf,float,"float, float" Function,-,dremf,float,"float, float"
Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bold_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" 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_center,void,"Canvas*, const char*"
Function,+,elements_button_left,void,"Canvas*, const char*" Function,+,elements_button_left,void,"Canvas*, const char*"
Function,+,elements_button_right,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_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,elements_multiline_text,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,elements_multiline_text_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,elements_multiline_text_framed,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float" Function,+,elements_progress_bar,void,"Canvas*, int32_t, int32_t, size_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*" Function,+,elements_progress_bar_with_text,void,"Canvas*, int32_t, int32_t, size_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,void,"Canvas*, int32_t, int32_t, size_t, FuriString*, size_t, _Bool"
Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t" Function,+,elements_scrollbar,void,"Canvas*, size_t, size_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t" Function,+,elements_scrollbar_pos,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_slightly_rounded_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_slightly_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t" Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t"
Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" 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_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,elf_symbolname_hash,uint32_t,const char*
Function,+,empty_screen_alloc,EmptyScreen*, 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_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t 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,_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_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool, Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t 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 entry,status,name,type,params
Version,+,59.0,, Version,+,60.3,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.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_clear,void,Canvas*
Function,+,canvas_commit,void,Canvas* Function,+,canvas_commit,void,Canvas*
Function,+,canvas_current_font_height,size_t,const 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_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_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,canvas_draw_circle,void,"Canvas*, int32_t, int32_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_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,void,"Canvas*, int32_t, int32_t, const Icon*"
Function,+,canvas_draw_icon_animation,void,"Canvas*, int32_t, int32_t, IconAnimation*" 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_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_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" 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,-,drand48,double,
Function,-,drem,double,"double, double" Function,-,drem,double,"double, double"
Function,-,dremf,float,"float, float" Function,-,dremf,float,"float, float"
Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bold_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" 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_center,void,"Canvas*, const char*"
Function,+,elements_button_left,void,"Canvas*, const char*" Function,+,elements_button_left,void,"Canvas*, const char*"
Function,+,elements_button_right,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_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_multiline_text,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,elements_multiline_text,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_multiline_text_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align, const char*" Function,+,elements_multiline_text_aligned,void,"Canvas*, int32_t, int32_t, Align, Align, const char*"
Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const char*" Function,+,elements_multiline_text_framed,void,"Canvas*, int32_t, int32_t, const char*"
Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float" Function,+,elements_progress_bar,void,"Canvas*, int32_t, int32_t, size_t, float"
Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*" Function,+,elements_progress_bar_with_text,void,"Canvas*, int32_t, int32_t, size_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,void,"Canvas*, int32_t, int32_t, size_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*, size_t, size_t"
Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t" Function,+,elements_scrollbar_pos,void,"Canvas*, int32_t, int32_t, size_t, size_t, size_t"
Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t" Function,+,elements_slightly_rounded_box,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_slightly_rounded_frame,void,"Canvas*, int32_t, int32_t, size_t, size_t"
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, size_t"
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t" Function,+,elements_text_box,void,"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"
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*" Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,elf_symbolname_hash,uint32_t,const char*
Function,+,empty_screen_alloc,EmptyScreen*, 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_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t 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,_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_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool, Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t 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_start,void,"uint32_t, float"
Function,+,furi_hal_infrared_async_tx_stop,void, Function,+,furi_hal_infrared_async_tx_stop,void,
Function,+,furi_hal_infrared_async_tx_wait_termination,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_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,void,
Function,-,furi_hal_init_early,void, Function,-,furi_hal_init_early,void,
Function,-,furi_hal_interrupt_init,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_infrared.h>
#include <furi_hal_interrupt.h> #include <furi_hal_interrupt.h>
#include <furi_hal_resources.h> #include <furi_hal_resources.h>
#include <furi_hal_cortex.h>
#include <furi_hal_bus.h> #include <furi_hal_bus.h>
#include <stm32wbxx_ll_tim.h> #include <stm32wbxx_ll_tim.h>
@@ -75,11 +76,17 @@ typedef enum {
InfraredStateMAX, InfraredStateMAX,
} InfraredState; } InfraredState;
static FuriHalInfraredTxPin infrared_tx_output = FuriHalInfraredTxPinInternal;
static volatile InfraredState furi_hal_infrared_state = InfraredStateIdle; static volatile InfraredState furi_hal_infrared_state = InfraredStateIdle;
static InfraredTimTx infrared_tim_tx; static InfraredTimTx infrared_tim_tx;
static InfraredTimRx infrared_tim_rx; static InfraredTimRx infrared_tim_rx;
static bool infrared_external_output; 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_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_async_tx_free_resources(void);
static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polarity_shift); 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( LL_TIM_SetAutoReload(
INFRARED_DMA_TIMER, INFRARED_DMA_TIMER,
__LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq)); __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq));
if(infrared_external_output) {
LL_TIM_OC_SetCompareCH1( if(infrared_tx_output == FuriHalInfraredTxPinInternal) {
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 {
LL_TIM_OC_SetCompareCH3( LL_TIM_OC_SetCompareCH3(
INFRARED_DMA_TIMER, INFRARED_DMA_TIMER,
((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); ((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_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N); LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N);
LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER); 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_DisableMasterSlaveMode(INFRARED_DMA_TIMER);
LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER);
LL_TIM_DisableIT_UPDATE(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) { static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) {
LL_DMA_InitTypeDef dma_config = {0}; LL_DMA_InitTypeDef dma_config = {0};
if(infrared_external_output) {
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); if(infrared_tx_output == FuriHalInfraredTxPinInternal) {
} else { dma_config.PeriphOrM2MSrcAddress = (uint32_t)(&(INFRARED_DMA_TIMER->CCMR2));
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.MemoryOrM2MDstAddress = (uint32_t)NULL;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_NORMAL; 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 == InfraredStateIdle) ||
(furi_hal_infrared_state == InfraredStateAsyncTxStopped)); (furi_hal_infrared_state == InfraredStateAsyncTxStopped));
if(infrared_external_output) { furi_hal_gpio_init(
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow); infrared_tx_pins[infrared_tx_output], GpioModeAnalog, GpioPullDown, GpioSpeedLow);
} else {
furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
}
furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL);
furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_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); furi_delay_us(5);
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */ LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */
furi_delay_us(5); furi_delay_us(5);
if(infrared_external_output) {
LL_GPIO_ResetOutputPin( const GpioPin* tx_gpio = infrared_tx_pins[infrared_tx_output];
gpio_ext_pa7.port, gpio_ext_pa7.pin); /* when disable it prevents false pulse */ LL_GPIO_ResetOutputPin(tx_gpio->port, tx_gpio->pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex( furi_hal_gpio_init_ex(
&gpio_ext_pa7, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); tx_gpio, 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);
}
FURI_CRITICAL_ENTER(); FURI_CRITICAL_ENTER();
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ 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_callback = callback;
infrared_tim_tx.signal_sent_context = context; 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); 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) { static void* hid_set_string_descr(char* str) {
furi_assert(str); furi_assert(str);

View File

@@ -16,6 +16,12 @@ extern "C" {
#define INFRARED_MAX_FREQUENCY 56000 #define INFRARED_MAX_FREQUENCY 56000
#define INFRARED_MIN_FREQUENCY 10000 #define INFRARED_MIN_FREQUENCY 10000
typedef enum {
FuriHalInfraredTxPinInternal,
FuriHalInfraredTxPinExtPA7,
FuriHalInfraredTxPinMax,
} FuriHalInfraredTxPin;
typedef enum { typedef enum {
FuriHalInfraredTxGetDataStateOk, /**< New data obtained */ FuriHalInfraredTxGetDataStateOk, /**< New data obtained */
FuriHalInfraredTxGetDataStateDone, /**< New data obtained, and this is end of package */ 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, FuriHalInfraredTxSignalSentISRCallback callback,
void* context); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -14,6 +14,11 @@ extern "C" {
/** Max number of simultaneously pressed keys (consumer control) */ /** Max number of simultaneously pressed keys (consumer control) */
#define HID_CONSUMER_MAX_KEYS 2 #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 #define HID_KEYBOARD_NONE 0x00
/** HID keyboard modifier keys */ /** 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); 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 #ifdef __cplusplus
} }
#endif #endif