mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 12:42:30 +04:00
Merge branch 'dev' into release
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -30,7 +30,7 @@ bindings/
|
||||
Brewfile.lock.json
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
/.vscode/
|
||||
|
||||
# Kate
|
||||
.kateproject
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,18 +1,23 @@
|
||||
### New changes
|
||||
* **SubGHz: Keyboard lock fixed**
|
||||
### Previous changes
|
||||
* SubGHz: AN-Motors AT4 - Add manually fixes
|
||||
* SubGHz: StarLine ignore option (in Read -> Config) (by @gid9798 | PR #410)
|
||||
* Plugins: Fix `Repeat: 200` bug in SubGHz Remote and Bruteforcer
|
||||
* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) (Steam guard support)
|
||||
* Plugins: Update **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main) (AT commands support)
|
||||
* Plugins: Add IR Scope app. (by @kallanreed | PR #407)
|
||||
* OFW: scripts: sconsdist: added stub file artifact for older ufbt
|
||||
* OFW: Graphics cleanup and icon rotation
|
||||
* OFW: Moved ufbt to fbt codebase
|
||||
* OFW: SD Driver: do not cache sd status.
|
||||
* OFW: Furi: more gpio checks in HAL
|
||||
* OFW: WeatherStation: fix protocol TX141TH-BV2
|
||||
* If you have copied apps into `apps` folder - remove `apps` folder on your microSD before installing this release to avoid issues!
|
||||
* SubGHz: (Bug that I decided to keep as a feature) You can change default button (Ok) for remote by holding custom button and pressing back at same time (same can be used to restore your button if you changed it accidentally) - Be careful, it might be unstable, I will make proper option to change button in next releases
|
||||
* SubGHz: Fixes for custom button bugs in SubGHz Remote app
|
||||
* SubGHz: Add alutech table to enviroment alloc and free
|
||||
* Docs: Fix and update docs - thanks to @lesterrry
|
||||
* Plugins: Bluetooth Remote - implemented YouTube Shorts Remote (may be unstable)
|
||||
* Plugins: Bluetooth Remote - improvements and fixes for TikTok remote (by @krolchonok | PR #420)
|
||||
* Plugins: Implement an array for baudrates on GPS UART app (+ add 19200 baud) (by @p0ns | PR #416)
|
||||
* Plugins: Remove UART Echo from releases since it is locked on 115200 baud, and we have **UART Terminal** with ability to set baudrate
|
||||
* Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator)
|
||||
* Plugins: Update **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main)
|
||||
* OFW: Deep Sleep Idle - **Improves battery usage!!!** -> **Breaking API change, api was changed from 21.x to 22.x**
|
||||
* OFW: FuriHal: pwr pulls for some pins
|
||||
* OFW: Bugfix: ISP Programmer and SubGhz
|
||||
* OFW: AVR_ISP: fix NULL pointer dereference
|
||||
* OFW: Fix gpio state isp programmer
|
||||
* OFW: ufbt: project & debugging updates
|
||||
* OFW: FuriHal: fix gpio naming and add explicit pulls for vibro, speaker and ir_tx -> **Breaking API change, api was changed from 20.x to 21.x**
|
||||
**(this will make your manually copied plugins not work, update them in same way you installed them, or delete `apps` folder and then install firmware, if you using extra pack builds (with `e` in version) all apps in _Extra will be updated automatically)**
|
||||
|
||||
#### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<br>
|
||||
|
||||
Our goal is to make all features possible on this device without any limitations!
|
||||
Most stable custom firmware focused on new features and improvements of original firmware components, with almost no UI changes
|
||||
|
||||
<br>
|
||||
|
||||
@@ -103,7 +103,7 @@ Encoders made by @assasinfil & @xMasterX:
|
||||
|
||||
## Please support development of the project
|
||||
The majority of this project is developed and maintained by me, @xMasterX.
|
||||
I'm unemployed because of the war, and the only income I receive is from your donations.
|
||||
I'm unemployed, and the only income I receive is from your donations.
|
||||
Our team is small and the guys are working on this project as much as they can solely based on the enthusiasm they have for this project and the community.
|
||||
- @assasinfil - SubGHz
|
||||
- @Svaarich - UI design and animations
|
||||
|
||||
@@ -34,7 +34,7 @@ void AccessorApp::run(void) {
|
||||
AccessorApp::AccessorApp()
|
||||
: text_store{0} {
|
||||
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
|
||||
onewire_host = onewire_host_alloc(&ibutton_gpio);
|
||||
onewire_host = onewire_host_alloc(&gpio_ibutton);
|
||||
furi_hal_power_enable_otg();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
App(
|
||||
appid="UART_Echo",
|
||||
name="UART Echo",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="uart_echo_app",
|
||||
cdefines=["APP_UART_ECHO"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=70,
|
||||
fap_icon="uart_10px.png",
|
||||
fap_category="GPIO",
|
||||
fap_category="Debug",
|
||||
)
|
||||
|
||||
@@ -33,10 +33,10 @@ It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it
|
||||
- gpio_ext_pa4
|
||||
- gpio_ext_pa6
|
||||
- gpio_ext_pa7
|
||||
- ibutton_gpio
|
||||
- gpio_ibutton
|
||||
*/
|
||||
|
||||
#define THERMO_GPIO_PIN (ibutton_gpio)
|
||||
#define THERMO_GPIO_PIN (gpio_ibutton)
|
||||
```
|
||||
Do not forget about the external pull-up resistor as these pins do not have one built-in.
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
- gpio_ext_pa4
|
||||
- gpio_ext_pa6
|
||||
- gpio_ext_pa7
|
||||
- ibutton_gpio
|
||||
- gpio_ibutton
|
||||
*/
|
||||
|
||||
#define THERMO_GPIO_PIN (ibutton_gpio)
|
||||
#define THERMO_GPIO_PIN (gpio_ibutton)
|
||||
|
||||
/* Flags which the reader thread responds to */
|
||||
typedef enum {
|
||||
|
||||
@@ -152,6 +152,12 @@ bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,9 +198,10 @@ bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) {
|
||||
}
|
||||
avr_isp_end_pmode(instance->avr_isp);
|
||||
|
||||
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
||||
|
||||
} while(0);
|
||||
|
||||
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
||||
|
||||
if(instance->callback) {
|
||||
if(instance->chip_arr_ind > avr_isp_chip_arr_size) {
|
||||
instance->callback(instance->context, "No detect", instance->chip_detect, 0);
|
||||
|
||||
@@ -196,7 +196,7 @@ static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
|
||||
instance->cfg->lockbytes = instance->buff[6];
|
||||
instance->cfg->fusebytes = instance->buff[7];
|
||||
instance->cfg->flashpoll = instance->buff[8];
|
||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <20>flashpoll<6C>
|
||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <20>flashpoll<6C>
|
||||
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
|
||||
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
|
||||
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
|
||||
@@ -317,6 +317,12 @@ static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->spi) {
|
||||
avr_isp_spi_sw_free(instance->spi);
|
||||
instance->spi = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ struct AvrIspSpiSw {
|
||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
|
||||
AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
|
||||
instance->speed_wait_time = speed;
|
||||
|
||||
instance->miso = AVR_ISP_SPI_SW_MISO;
|
||||
instance->mosi = AVR_ISP_SPI_SW_MOSI;
|
||||
instance->sck = AVR_ISP_SPI_SW_SCK;
|
||||
@@ -40,7 +39,6 @@ void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
|
||||
furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
free(instance);
|
||||
}
|
||||
|
||||
|
||||
20
applications/external/gps_nmea_uart/gps.c
vendored
20
applications/external/gps_nmea_uart/gps.c
vendored
@@ -139,20 +139,14 @@ int32_t gps_app(void* p) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
gps_uart_deinit_thread(gps_uart);
|
||||
switch(gps_uart->baudrate) {
|
||||
case GPS_BAUDRATE_9k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_57k;
|
||||
break;
|
||||
case GPS_BAUDRATE_57k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_115k;
|
||||
break;
|
||||
case GPS_BAUDRATE_115k:
|
||||
gps_uart->baudrate = GPS_BAUDRATE_9k;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
const int baudrate_length =
|
||||
sizeof(gps_baudrates) / sizeof(gps_baudrates[0]);
|
||||
current_gps_baudrate++;
|
||||
if(current_gps_baudrate >= baudrate_length) {
|
||||
current_gps_baudrate = 0;
|
||||
}
|
||||
gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
|
||||
|
||||
gps_uart_init_thread(gps_uart);
|
||||
gps_uart->changing_baudrate = true;
|
||||
view_port_update(view_port);
|
||||
|
||||
@@ -169,7 +169,7 @@ GpsUart* gps_uart_enable() {
|
||||
|
||||
gps_uart->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
gps_uart->baudrate = GPS_BAUDRATE_57k;
|
||||
gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
|
||||
|
||||
gps_uart_init_thread(gps_uart);
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#include <furi_hal.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#define GPS_BAUDRATE_9k 9600
|
||||
#define GPS_BAUDRATE_57k 57600
|
||||
#define GPS_BAUDRATE_115k 115200
|
||||
#define RX_BUF_SIZE 1024
|
||||
|
||||
static const int gps_baudrates[5] = {9600, 19200, 38400, 57600, 115200};
|
||||
static int current_gps_baudrate = 3;
|
||||
|
||||
typedef struct {
|
||||
bool valid;
|
||||
float latitude;
|
||||
|
||||
BIN
applications/external/hid_app/assets/Pause_icon_9x9.png
vendored
Normal file
BIN
applications/external/hid_app/assets/Pause_icon_9x9.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
19
applications/external/hid_app/hid.c
vendored
19
applications/external/hid_app/hid.c
vendored
@@ -10,6 +10,7 @@ enum HidDebugSubmenuIndex {
|
||||
HidSubmenuIndexKeyboard,
|
||||
HidSubmenuIndexMedia,
|
||||
HidSubmenuIndexTikTok,
|
||||
HidSubmenuIndexYTShorts,
|
||||
HidSubmenuIndexMouse,
|
||||
HidSubmenuIndexMouseJiggler,
|
||||
};
|
||||
@@ -32,6 +33,9 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
} else if(index == HidSubmenuIndexTikTok) {
|
||||
app->view_id = BtHidViewTikTok;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok);
|
||||
} else if(index == HidSubmenuIndexYTShorts) {
|
||||
app->view_id = BtHidViewYTShorts;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts);
|
||||
} else if(index == HidSubmenuIndexMouseJiggler) {
|
||||
app->view_id = HidViewMouseJiggler;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
|
||||
@@ -55,6 +59,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
|
||||
hid_mouse_set_connected_status(hid->hid_mouse, connected);
|
||||
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
||||
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
||||
hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected);
|
||||
}
|
||||
|
||||
static void hid_dialog_callback(DialogExResult result, void* context) {
|
||||
@@ -113,6 +118,12 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
HidSubmenuIndexTikTok,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
"YT Shorts Controller",
|
||||
HidSubmenuIndexYTShorts,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
}
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
@@ -166,6 +177,12 @@ Hid* hid_app_alloc_view(void* context) {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok));
|
||||
|
||||
// YTShorts view
|
||||
app->hid_ytshorts = hid_ytshorts_alloc(app);
|
||||
view_set_previous_callback(hid_ytshorts_get_view(app->hid_ytshorts), hid_exit_confirm_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewYTShorts, hid_ytshorts_get_view(app->hid_ytshorts));
|
||||
|
||||
// Mouse view
|
||||
app->hid_mouse = hid_mouse_alloc(app);
|
||||
view_set_previous_callback(hid_mouse_get_view(app->hid_mouse), hid_exit_confirm_view);
|
||||
@@ -209,6 +226,8 @@ void hid_free(Hid* app) {
|
||||
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
||||
hid_tiktok_free(app->hid_tiktok);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewYTShorts);
|
||||
hid_ytshorts_free(app->hid_ytshorts);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Close records
|
||||
|
||||
2
applications/external/hid_app/hid.h
vendored
2
applications/external/hid_app/hid.h
vendored
@@ -22,6 +22,7 @@
|
||||
#include "views/hid_mouse.h"
|
||||
#include "views/hid_mouse_jiggler.h"
|
||||
#include "views/hid_tiktok.h"
|
||||
#include "views/hid_ytshorts.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
||||
|
||||
@@ -45,6 +46,7 @@ struct Hid {
|
||||
HidMouse* hid_mouse;
|
||||
HidMouseJiggler* hid_mouse_jiggler;
|
||||
HidTikTok* hid_tiktok;
|
||||
HidYTShorts* hid_ytshorts;
|
||||
|
||||
HidTransport transport;
|
||||
uint32_t view_id;
|
||||
|
||||
1
applications/external/hid_app/views.h
vendored
1
applications/external/hid_app/views.h
vendored
@@ -6,5 +6,6 @@ typedef enum {
|
||||
HidViewMouse,
|
||||
HidViewMouseJiggler,
|
||||
BtHidViewTikTok,
|
||||
BtHidViewYTShorts,
|
||||
HidViewExitConfirm,
|
||||
} HidView;
|
||||
18
applications/external/hid_app/views/hid_mouse.c
vendored
18
applications/external/hid_app/views/hid_mouse.c
vendored
@@ -93,17 +93,23 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) {
|
||||
|
||||
// Ok
|
||||
if(model->left_mouse_pressed) {
|
||||
canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Back
|
||||
if(model->right_mouse_pressed) {
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) {
|
||||
|
||||
62
applications/external/hid_app/views/hid_tiktok.c
vendored
62
applications/external/hid_app/views/hid_tiktok.c
vendored
@@ -19,6 +19,7 @@ typedef struct {
|
||||
bool ok_pressed;
|
||||
bool connected;
|
||||
bool is_cursor_set;
|
||||
bool back_mouse_pressed;
|
||||
HidTransport transport;
|
||||
} HidTikTokModel;
|
||||
|
||||
@@ -40,53 +41,63 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
// Keypad circles
|
||||
canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47);
|
||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
||||
|
||||
// Pause
|
||||
if(model->back_mouse_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Up
|
||||
if(model->up_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 96, 11, &I_Arr_up_7x9);
|
||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
if(model->down_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 96, 44, &I_Arr_dwn_7x9);
|
||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Left
|
||||
if(model->left_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 81, 29, &I_Voldwn_6x6);
|
||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Right
|
||||
if(model->right_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13);
|
||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 111, 29, &I_Volup_8x6);
|
||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Ok
|
||||
if(model->ok_pressed) {
|
||||
canvas_draw_icon(canvas, 91, 23, &I_Like_pressed_17x17);
|
||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 94, 27, &I_Like_def_11x9);
|
||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
||||
}
|
||||
// Exit
|
||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||
@@ -102,7 +113,8 @@ static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) {
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 20, 120);
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 40, 120);
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 0, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
@@ -120,6 +132,8 @@ static void
|
||||
hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +151,8 @@ static void
|
||||
hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,24 +185,26 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) {
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Emulate up swipe
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
// Emulate down swipe
|
||||
// Swipe to new video
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 6);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 19);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Swipe to previous video
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -19);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -12);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
hid_hal_consumer_key_release_all(hid_tiktok->hid);
|
||||
// Pause
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
|
||||
268
applications/external/hid_app/views/hid_ytshorts.c
vendored
Normal file
268
applications/external/hid_app/views/hid_ytshorts.c
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "hid_ytshorts.h"
|
||||
#include "../hid.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "hid_icons.h"
|
||||
|
||||
#define TAG "HidYTShorts"
|
||||
|
||||
struct HidYTShorts {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool left_pressed;
|
||||
bool up_pressed;
|
||||
bool right_pressed;
|
||||
bool down_pressed;
|
||||
bool ok_pressed;
|
||||
bool connected;
|
||||
bool is_cursor_set;
|
||||
bool back_mouse_pressed;
|
||||
HidTransport transport;
|
||||
} HidYTShortsModel;
|
||||
|
||||
static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidYTShortsModel* model = context;
|
||||
|
||||
// Header
|
||||
if(model->transport == HidTransportBle) {
|
||||
if(model->connected) {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
|
||||
}
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Shorts");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
// Keypad circles
|
||||
canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47);
|
||||
|
||||
// Pause
|
||||
if(model->back_mouse_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Up
|
||||
if(model->up_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Down
|
||||
if(model->down_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Left
|
||||
if(model->left_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Right
|
||||
if(model->right_pressed) {
|
||||
canvas_set_bitmap_mode(canvas, 1);
|
||||
canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13);
|
||||
canvas_set_bitmap_mode(canvas, 0);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Ok
|
||||
if(model->ok_pressed) {
|
||||
canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9);
|
||||
}
|
||||
// Exit
|
||||
canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||
}
|
||||
|
||||
static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) {
|
||||
// Set cursor to the phone's left up corner
|
||||
// Delays to guarantee one packet per connection interval
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, -127, -127);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, 40, 120);
|
||||
hid_hal_mouse_move(hid_ytshorts->hid, 0, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
static void hid_ytshorts_process_press(
|
||||
HidYTShorts* hid_ytshorts,
|
||||
HidYTShortsModel* model,
|
||||
InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = true;
|
||||
hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = true;
|
||||
hid_hal_consumer_key_press(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_ytshorts_process_release(
|
||||
HidYTShorts* hid_ytshorts,
|
||||
HidYTShortsModel* model,
|
||||
InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = false;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = false;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
model->left_pressed = false;
|
||||
hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
} else if(event->key == InputKeyRight) {
|
||||
model->right_pressed = false;
|
||||
hid_hal_consumer_key_release(hid_ytshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
model->back_mouse_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool hid_ytshorts_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidYTShorts* hid_ytshorts = context;
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
hid_ytshorts_process_press(hid_ytshorts, model, event);
|
||||
if(model->connected && !model->is_cursor_set) {
|
||||
hid_ytshorts_reset_cursor(hid_ytshorts);
|
||||
model->is_cursor_set = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_ytshorts_process_release(hid_ytshorts, model, event);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
// Swipe to new video
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 6);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 10);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, 6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Swipe to previous video
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -6);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -10);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -8);
|
||||
hid_hal_mouse_scroll(hid_ytshorts->hid, -6);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
// Pause
|
||||
hid_hal_mouse_press(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_ytshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if(event->key == InputKeyBack) {
|
||||
hid_hal_consumer_key_release_all(hid_ytshorts->hid);
|
||||
model->is_cursor_set = false;
|
||||
consumed = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid) {
|
||||
HidYTShorts* hid_ytshorts = malloc(sizeof(HidYTShorts));
|
||||
hid_ytshorts->hid = bt_hid;
|
||||
hid_ytshorts->view = view_alloc();
|
||||
view_set_context(hid_ytshorts->view, hid_ytshorts);
|
||||
view_allocate_model(hid_ytshorts->view, ViewModelTypeLocking, sizeof(HidYTShortsModel));
|
||||
view_set_draw_callback(hid_ytshorts->view, hid_ytshorts_draw_callback);
|
||||
view_set_input_callback(hid_ytshorts->view, hid_ytshorts_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{ model->transport = bt_hid->transport; },
|
||||
true);
|
||||
|
||||
return hid_ytshorts;
|
||||
}
|
||||
|
||||
void hid_ytshorts_free(HidYTShorts* hid_ytshorts) {
|
||||
furi_assert(hid_ytshorts);
|
||||
view_free(hid_ytshorts->view);
|
||||
free(hid_ytshorts);
|
||||
}
|
||||
|
||||
View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts) {
|
||||
furi_assert(hid_ytshorts);
|
||||
return hid_ytshorts->view;
|
||||
}
|
||||
|
||||
void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected) {
|
||||
furi_assert(hid_ytshorts);
|
||||
with_view_model(
|
||||
hid_ytshorts->view,
|
||||
HidYTShortsModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
model->is_cursor_set = false;
|
||||
},
|
||||
true);
|
||||
}
|
||||
14
applications/external/hid_app/views/hid_ytshorts.h
vendored
Normal file
14
applications/external/hid_app/views/hid_ytshorts.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidYTShorts HidYTShorts;
|
||||
|
||||
HidYTShorts* hid_ytshorts_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_ytshorts_free(HidYTShorts* hid_ytshorts);
|
||||
|
||||
View* hid_ytshorts_get_view(HidYTShorts* hid_ytshorts);
|
||||
|
||||
void hid_ytshorts_set_connected_status(HidYTShorts* hid_ytshorts, bool connected);
|
||||
@@ -121,6 +121,19 @@ void totp_cli_command_pin_handle(PluginState* plugin_state, FuriString* args, Cl
|
||||
memset(&new_pin[0], 0, TOTP_IV_SIZE);
|
||||
}
|
||||
|
||||
char* backup_path = totp_config_file_backup();
|
||||
if(backup_path != NULL) {
|
||||
TOTP_CLI_PRINTF_WARNING("Backup conf file %s has been created\r\n", backup_path);
|
||||
TOTP_CLI_PRINTF_WARNING(
|
||||
"Once you make sure everything is fine and works as expected, please delete this backup file\r\n");
|
||||
free(backup_path);
|
||||
} else {
|
||||
memset_s(&new_pin[0], TOTP_IV_SIZE, 0, TOTP_IV_SIZE);
|
||||
TOTP_CLI_PRINTF_ERROR(
|
||||
"An error has occurred during taking backup of config file\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(plugin_state->current_scene == TotpSceneGenerateToken) {
|
||||
totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
|
||||
load_generate_token_scene = true;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "reset.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi/core/string.h>
|
||||
#include "../../cli_helpers.h"
|
||||
#include "../../../services/config/config.h"
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,14 +22,14 @@ static const uint8_t dtable[] = {0x3e, 0x80, 0x80, 0x80, 0x3f, 0x34, 0x35, 0x36,
|
||||
0x80, 0x80, 0x80, 0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
|
||||
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33};
|
||||
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static uint8_t get_dtable_value(uint8_t index) {
|
||||
return (index < 43 || index > 122) ? 0x80 : dtable[index - 43];
|
||||
}
|
||||
|
||||
uint8_t* base64_decode(const uint8_t* src, size_t len, size_t* out_len, size_t* out_size) {
|
||||
uint8_t *out;
|
||||
uint8_t *pos;
|
||||
uint8_t* out;
|
||||
uint8_t* pos;
|
||||
uint8_t in[4];
|
||||
uint8_t block[4];
|
||||
uint8_t tmp;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
#pragma weak strnlen
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
size_t strnlen(const char* s, size_t maxlen);
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
|
||||
#define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
|
||||
#define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
|
||||
#define CONFIG_FILE_BACKUP_BASE_PATH CONFIG_FILE_PATH ".backup"
|
||||
#define CONFIG_FILE_TEMP_PATH CONFIG_FILE_PATH ".tmp"
|
||||
#define CONFIG_FILE_ORIG_PATH CONFIG_FILE_PATH ".orig"
|
||||
#define CONFIG_FILE_PATH_PREVIOUS EXT_PATH("apps/Misc") "/totp.conf"
|
||||
@@ -39,6 +39,34 @@ static void totp_close_config_file(FlipperFormat* file) {
|
||||
flipper_format_free(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to take a config file backup
|
||||
* @param storage storage record
|
||||
* @return backup path if backup successfully taken; \c NULL otherwise
|
||||
*/
|
||||
static char* totp_config_file_backup_i(Storage* storage) {
|
||||
uint8_t backup_path_size = sizeof(CONFIG_FILE_BACKUP_BASE_PATH) + 5;
|
||||
char* backup_path = malloc(backup_path_size);
|
||||
furi_check(backup_path != NULL);
|
||||
memcpy(backup_path, CONFIG_FILE_BACKUP_BASE_PATH, sizeof(CONFIG_FILE_BACKUP_BASE_PATH));
|
||||
uint16_t i = 1;
|
||||
bool backup_file_exists;
|
||||
while((backup_file_exists = storage_common_exists(storage, backup_path)) && i <= 9999) {
|
||||
snprintf(backup_path, backup_path_size, CONFIG_FILE_BACKUP_BASE_PATH ".%" PRIu16, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
if(backup_file_exists ||
|
||||
storage_common_copy(storage, CONFIG_FILE_PATH, backup_path) != FSE_OK) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Unable to take a backup");
|
||||
free(backup_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", backup_path);
|
||||
return backup_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Opens or creates TOTP application standard config file
|
||||
* @param storage storage record to use
|
||||
@@ -250,6 +278,13 @@ static TotpConfigFileUpdateResult
|
||||
return update_result;
|
||||
}
|
||||
|
||||
char* totp_config_file_backup() {
|
||||
Storage* storage = totp_open_storage();
|
||||
char* result = totp_config_file_backup_i(storage);
|
||||
totp_close_storage();
|
||||
return result;
|
||||
}
|
||||
|
||||
TotpConfigFileUpdateResult totp_config_file_save_new_token(const TokenInfo* token_info) {
|
||||
Storage* cfg_storage = totp_open_storage();
|
||||
FlipperFormat* file;
|
||||
@@ -513,20 +548,16 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st
|
||||
CONFIG_FILE_ACTUAL_VERSION);
|
||||
totp_close_config_file(fff_data_file);
|
||||
|
||||
if(storage_common_stat(storage, CONFIG_FILE_BACKUP_PATH, NULL) == FSE_OK) {
|
||||
storage_simply_remove(storage, CONFIG_FILE_BACKUP_PATH);
|
||||
}
|
||||
char* backup_path = totp_config_file_backup_i(storage);
|
||||
|
||||
if(storage_common_copy(storage, CONFIG_FILE_PATH, CONFIG_FILE_BACKUP_PATH) == FSE_OK) {
|
||||
FURI_LOG_I(LOGGING_TAG, "Took config file backup to %s", CONFIG_FILE_BACKUP_PATH);
|
||||
if(backup_path != NULL) {
|
||||
if(totp_open_config_file(storage, &fff_data_file) != TotpConfigFileOpenSuccess) {
|
||||
result = TotpConfigFileOpenError;
|
||||
break;
|
||||
}
|
||||
|
||||
FlipperFormat* fff_backup_data_file = flipper_format_file_alloc(storage);
|
||||
if(!flipper_format_file_open_existing(
|
||||
fff_backup_data_file, CONFIG_FILE_BACKUP_PATH)) {
|
||||
if(!flipper_format_file_open_existing(fff_backup_data_file, backup_path)) {
|
||||
flipper_format_file_close(fff_backup_data_file);
|
||||
flipper_format_free(fff_backup_data_file);
|
||||
result = TotpConfigFileOpenError;
|
||||
@@ -551,12 +582,12 @@ TotpConfigFileOpenResult totp_config_file_load_base(PluginState* const plugin_st
|
||||
flipper_format_file_close(fff_backup_data_file);
|
||||
flipper_format_free(fff_backup_data_file);
|
||||
flipper_format_rewind(fff_data_file);
|
||||
free(backup_path);
|
||||
} else {
|
||||
FURI_LOG_E(
|
||||
LOGGING_TAG,
|
||||
"An error occurred during taking backup of %s into %s before migration",
|
||||
CONFIG_FILE_PATH,
|
||||
CONFIG_FILE_BACKUP_PATH);
|
||||
"An error occurred during taking backup of %s before migration",
|
||||
CONFIG_FILE_PATH);
|
||||
result = TotpConfigFileOpenError;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <furi.h>
|
||||
#include "../../types/plugin_state.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "constants.h"
|
||||
@@ -60,6 +59,12 @@ enum TotpConfigFileUpdateResults {
|
||||
TotpConfigFileUpdateError
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tries to take a config file backup
|
||||
* @return backup path if backup successfully taken; \c NULL otherwise
|
||||
*/
|
||||
char* totp_config_file_backup();
|
||||
|
||||
/**
|
||||
* @brief Saves all the settings and tokens to an application config file
|
||||
* @param plugin_state application state
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
|
||||
#define CONFIG_FILE_ACTUAL_VERSION 4
|
||||
#define CONFIG_FILE_ACTUAL_VERSION (4)
|
||||
|
||||
#define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
|
||||
#define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "crypto.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_crypto.h>
|
||||
#include <furi_hal_random.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include "../config/config.h"
|
||||
#include "../../types/common.h"
|
||||
#include "memset_s.h"
|
||||
|
||||
#define CRYPTO_KEY_SLOT 2
|
||||
#define CRYPTO_KEY_SLOT (2)
|
||||
#define CRYPTO_VERIFY_KEY "FFF_Crypto_pass"
|
||||
#define CRYPTO_VERIFY_KEY_LENGTH 16
|
||||
#define CRYPTO_ALIGNMENT_FACTOR 16
|
||||
#define CRYPTO_VERIFY_KEY_LENGTH (16)
|
||||
#define CRYPTO_ALIGNMENT_FACTOR (16)
|
||||
|
||||
uint8_t* totp_crypto_encrypt(
|
||||
const uint8_t* plain_data,
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
#define _GLHMAC_CONCAT_(prefix, suffix) prefix##suffix
|
||||
#define _GLHMAC_CONCAT(prefix, suffix) _GLHMAC_CONCAT_(prefix, suffix)
|
||||
|
||||
#if GL_HMAC_NAME == 5
|
||||
#define HMAC_ALG md5
|
||||
#else
|
||||
#define HMAC_ALG _GLHMAC_CONCAT(sha, GL_HMAC_NAME)
|
||||
#endif
|
||||
|
||||
#define GL_HMAC_CTX _GLHMAC_CONCAT(HMAC_ALG, _ctx)
|
||||
#define GL_HMAC_FN _GLHMAC_CONCAT(hmac_, HMAC_ALG)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#include "totp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <timezone_utils.h>
|
||||
#include "../hmac/hmac_sha1.h"
|
||||
#include "../hmac/hmac_sha256.h"
|
||||
#include "../hmac/hmac_sha512.h"
|
||||
#include "../hmac/byteswap.h"
|
||||
#include "../../lib/timezone_utils/timezone_utils.h"
|
||||
|
||||
#define HMAC_MAX_RESULT_SIZE HMAC_SHA512_RESULT_SIZE
|
||||
|
||||
|
||||
13
applications/external/totp/totp_app.c
vendored
13
applications/external/totp/totp_app.c
vendored
@@ -1,10 +1,7 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <stdlib.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
@@ -21,7 +18,7 @@
|
||||
#include "services/crypto/crypto.h"
|
||||
#include "cli/cli.h"
|
||||
|
||||
#define IDLE_TIMEOUT 60000
|
||||
#define IDLE_TIMEOUT (60000)
|
||||
|
||||
static void render_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
@@ -97,6 +94,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||
plugin_state->gui = furi_record_open(RECORD_GUI);
|
||||
plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
|
||||
plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
|
||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
||||
|
||||
if(totp_config_file_load_base(plugin_state) != TotpConfigFileOpenSuccess) {
|
||||
totp_dialogs_config_loading_error(plugin_state);
|
||||
@@ -104,10 +102,6 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
|
||||
}
|
||||
|
||||
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(plugin_state->mutex == NULL) {
|
||||
FURI_LOG_E(LOGGING_TAG, "Cannot create mutex\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
if(plugin_state->automation_method & AutomationMethodBadBt) {
|
||||
@@ -162,7 +156,7 @@ int32_t totp_app() {
|
||||
}
|
||||
|
||||
TotpCliContext* cli_context = totp_cli_register_command_handler(plugin_state, event_queue);
|
||||
totp_scene_director_init_scenes(plugin_state);
|
||||
|
||||
if(!totp_activate_initial_scene(plugin_state)) {
|
||||
FURI_LOG_E(LOGGING_TAG, "An error ocurred during activating initial scene\r\n");
|
||||
totp_plugin_state_free(plugin_state);
|
||||
@@ -210,7 +204,6 @@ int32_t totp_app() {
|
||||
|
||||
totp_cli_unregister_command_handler(cli_context);
|
||||
totp_scene_director_deactivate_active_scene(plugin_state);
|
||||
totp_scene_director_dispose(plugin_state);
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(plugin_state->gui, view_port);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "../workers/bt_type_code/bt_type_code.h"
|
||||
#endif
|
||||
|
||||
#define TOTP_IV_SIZE 16
|
||||
#define TOTP_IV_SIZE (16)
|
||||
|
||||
/**
|
||||
* @brief Application state structure
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "token_info.h"
|
||||
#include <furi_hal.h>
|
||||
#include <base32.h>
|
||||
#include <base64.h>
|
||||
#include <memset_s.h>
|
||||
#include <strnlen.h>
|
||||
#include "common.h"
|
||||
#include "../services/crypto/crypto.h"
|
||||
|
||||
|
||||
19
applications/external/totp/types/token_info.h
vendored
19
applications/external/totp/types/token_info.h
vendored
@@ -2,15 +2,15 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi/core/string.h>
|
||||
|
||||
#define TOTP_TOKEN_DURATION_DEFAULT 30
|
||||
#define TOTP_TOKEN_DURATION_DEFAULT (30)
|
||||
|
||||
#define TOTP_TOKEN_ALGO_SHA1_NAME "sha1"
|
||||
#define TOTP_TOKEN_ALGO_STEAM_NAME "steam"
|
||||
#define TOTP_TOKEN_ALGO_SHA256_NAME "sha256"
|
||||
#define TOTP_TOKEN_ALGO_SHA512_NAME "sha512"
|
||||
#define TOTP_TOKEN_MAX_LENGTH 255
|
||||
#define TOTP_TOKEN_MAX_LENGTH (255)
|
||||
|
||||
#define PLAIN_TOKEN_ENCODING_BASE32_NAME "base32"
|
||||
#define PLAIN_TOKEN_ENCODING_BASE64_NAME "base64"
|
||||
@@ -95,12 +95,23 @@ enum TokenAutomationFeatures {
|
||||
TOKEN_AUTOMATION_FEATURE_TYPE_SLOWER = 0b100
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Plain token secret encodings.
|
||||
*/
|
||||
enum PlainTokenSecretEncodings {
|
||||
|
||||
/**
|
||||
* @brief Base32 encoding
|
||||
*/
|
||||
PLAIN_TOKEN_ENCODING_BASE32 = 0,
|
||||
|
||||
/**
|
||||
* @brief Base64 encoding
|
||||
*/
|
||||
PLAIN_TOKEN_ENCODING_BASE64 = 1
|
||||
};
|
||||
|
||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT 8
|
||||
#define TOTP_TOKEN_DIGITS_MAX_COUNT (8)
|
||||
|
||||
/**
|
||||
* @brief TOTP token information
|
||||
|
||||
4
applications/external/totp/ui/constants.h
vendored
4
applications/external/totp/ui/constants.h
vendored
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define SCREEN_WIDTH 128
|
||||
#define SCREEN_HEIGHT 64
|
||||
#define SCREEN_WIDTH (128)
|
||||
#define SCREEN_HEIGHT (64)
|
||||
#define SCREEN_WIDTH_CENTER (SCREEN_WIDTH >> 1)
|
||||
#define SCREEN_HEIGHT_CENTER (SCREEN_HEIGHT >> 1)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "mode_nine.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* GENERATED BY https://github.com/pavius/the-dot-factory */
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
/* GENERATED BY https://github.com/pavius/the-dot-factory */
|
||||
|
||||
#include "../font_info.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Font data for ModeNine 15pt */
|
||||
extern const FONT_INFO modeNine_15ptFontInfo;
|
||||
|
||||
16
applications/external/totp/ui/scene_director.c
vendored
16
applications/external/totp/ui/scene_director.c
vendored
@@ -62,14 +62,6 @@ void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state
|
||||
}
|
||||
}
|
||||
|
||||
void totp_scene_director_init_scenes(PluginState* const plugin_state) {
|
||||
totp_scene_authenticate_init(plugin_state);
|
||||
totp_scene_generate_token_init(plugin_state);
|
||||
totp_scene_add_new_token_init(plugin_state);
|
||||
totp_scene_token_menu_init(plugin_state);
|
||||
totp_scene_app_settings_init(plugin_state);
|
||||
}
|
||||
|
||||
void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state) {
|
||||
switch(plugin_state->current_scene) {
|
||||
case TotpSceneGenerateToken:
|
||||
@@ -94,14 +86,6 @@ void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_
|
||||
}
|
||||
}
|
||||
|
||||
void totp_scene_director_dispose(const PluginState* const plugin_state) {
|
||||
totp_scene_generate_token_free(plugin_state);
|
||||
totp_scene_authenticate_free(plugin_state);
|
||||
totp_scene_add_new_token_free(plugin_state);
|
||||
totp_scene_token_menu_free(plugin_state);
|
||||
totp_scene_app_settings_free(plugin_state);
|
||||
}
|
||||
|
||||
bool totp_scene_director_handle_event(PluginEvent* const event, PluginState* const plugin_state) {
|
||||
bool processing = true;
|
||||
switch(plugin_state->current_scene) {
|
||||
|
||||
12
applications/external/totp/ui/scene_director.h
vendored
12
applications/external/totp/ui/scene_director.h
vendored
@@ -22,12 +22,6 @@ void totp_scene_director_activate_scene(
|
||||
*/
|
||||
void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Initializes all the available scenes
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_init_scenes(PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Renders current scene
|
||||
* @param canvas canvas to render at
|
||||
@@ -35,12 +29,6 @@ void totp_scene_director_init_scenes(PluginState* const plugin_state);
|
||||
*/
|
||||
void totp_scene_director_render(Canvas* const canvas, PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Disposes all the available scenes
|
||||
* @param plugin_state application state
|
||||
*/
|
||||
void totp_scene_director_dispose(const PluginState* const plugin_state);
|
||||
|
||||
/**
|
||||
* @brief Handles application event for the current scene
|
||||
* @param event event to be handled
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "totp_input_text.h"
|
||||
#include <gui/view_i.h>
|
||||
#include "../../../lib/polyfills/strnlen.h"
|
||||
|
||||
void view_draw(View* view, Canvas* canvas) {
|
||||
furi_assert(view);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
#define INPUT_BUFFER_SIZE (255)
|
||||
|
||||
typedef struct {
|
||||
char* user_input;
|
||||
size_t user_input_length;
|
||||
@@ -20,8 +22,6 @@ typedef struct {
|
||||
void* callback_data;
|
||||
} InputTextSceneContext;
|
||||
|
||||
#define INPUT_BUFFER_SIZE 255
|
||||
|
||||
typedef struct {
|
||||
TextInput* text_input;
|
||||
View* text_input_view;
|
||||
|
||||
@@ -44,10 +44,6 @@ typedef struct {
|
||||
FuriString* duration_text;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_add_new_token_init(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
static void on_token_name_user_comitted(InputTextSceneCallbackResult* result) {
|
||||
SceneState* scene_state = result->callback_data;
|
||||
free(scene_state->token_name);
|
||||
@@ -354,7 +350,3 @@ void totp_scene_add_new_token_deactivate(PluginState* plugin_state) {
|
||||
free(plugin_state->current_scene_state);
|
||||
plugin_state->current_scene_state = NULL;
|
||||
}
|
||||
|
||||
void totp_scene_add_new_token_free(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
@@ -10,11 +8,9 @@ typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} TokenAddEditSceneContext;
|
||||
|
||||
void totp_scene_add_new_token_init(const PluginState* plugin_state);
|
||||
void totp_scene_add_new_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenAddEditSceneContext* context);
|
||||
void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState* plugin_state);
|
||||
void totp_scene_add_new_token_deactivate(PluginState* plugin_state);
|
||||
void totp_scene_add_new_token_free(const PluginState* plugin_state);
|
||||
|
||||
@@ -44,10 +44,6 @@ typedef struct {
|
||||
Control selected_control;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_app_settings_init(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
void totp_scene_app_settings_activate(
|
||||
PluginState* plugin_state,
|
||||
const AppSettingsSceneContext* context) {
|
||||
@@ -332,7 +328,3 @@ void totp_scene_app_settings_deactivate(PluginState* plugin_state) {
|
||||
free(plugin_state->current_scene_state);
|
||||
plugin_state->current_scene_state = NULL;
|
||||
}
|
||||
|
||||
void totp_scene_app_settings_free(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
@@ -8,7 +8,6 @@ typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} AppSettingsSceneContext;
|
||||
|
||||
void totp_scene_app_settings_init(const PluginState* plugin_state);
|
||||
void totp_scene_app_settings_activate(
|
||||
PluginState* plugin_state,
|
||||
const AppSettingsSceneContext* context);
|
||||
@@ -16,5 +15,4 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
|
||||
bool totp_scene_app_settings_handle_event(
|
||||
const PluginEvent* const event,
|
||||
PluginState* plugin_state);
|
||||
void totp_scene_app_settings_deactivate(PluginState* plugin_state);
|
||||
void totp_scene_app_settings_free(const PluginState* plugin_state);
|
||||
void totp_scene_app_settings_deactivate(PluginState* plugin_state);
|
||||
@@ -18,10 +18,6 @@ typedef struct {
|
||||
uint8_t code_length;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_authenticate_init(PluginState* plugin_state) {
|
||||
memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
|
||||
}
|
||||
|
||||
void totp_scene_authenticate_activate(PluginState* plugin_state) {
|
||||
SceneState* scene_state = malloc(sizeof(SceneState));
|
||||
furi_check(scene_state != NULL);
|
||||
@@ -162,7 +158,3 @@ void totp_scene_authenticate_deactivate(PluginState* plugin_state) {
|
||||
free(plugin_state->current_scene_state);
|
||||
plugin_state->current_scene_state = NULL;
|
||||
}
|
||||
|
||||
void totp_scene_authenticate_free(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@
|
||||
#include "../../../types/plugin_state.h"
|
||||
#include "../../../types/plugin_event.h"
|
||||
|
||||
void totp_scene_authenticate_init(PluginState* plugin_state);
|
||||
void totp_scene_authenticate_activate(PluginState* plugin_state);
|
||||
void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_authenticate_handle_event(
|
||||
const PluginEvent* const event,
|
||||
PluginState* plugin_state);
|
||||
void totp_scene_authenticate_deactivate(PluginState* plugin_state);
|
||||
void totp_scene_authenticate_free(const PluginState* plugin_state);
|
||||
|
||||
@@ -2,39 +2,44 @@
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <totp_icons.h>
|
||||
#include <roll_value.h>
|
||||
#include "totp_scene_generate_token.h"
|
||||
#include "../../../types/token_info.h"
|
||||
#include "../../../types/common.h"
|
||||
#include "../../constants.h"
|
||||
#include "../../../services/totp/totp.h"
|
||||
#include "../../../services/config/config.h"
|
||||
#include "../../../services/crypto/crypto.h"
|
||||
#include "../../../services/convert/convert.h"
|
||||
#include "../../../lib/polyfills/memset_s.h"
|
||||
#include "../../../lib/roll_value/roll_value.h"
|
||||
#include "../../scene_director.h"
|
||||
#include "../token_menu/totp_scene_token_menu.h"
|
||||
#include "../../../features_config.h"
|
||||
#include "../../../workers/generate_totp_code/generate_totp_code.h"
|
||||
#include "../../../workers/usb_type_code/usb_type_code.h"
|
||||
#ifdef TOTP_BADBT_TYPE_ENABLED
|
||||
#include "../../../workers/bt_type_code/bt_type_code.h"
|
||||
#endif
|
||||
#include "../../fonts/mode-nine/mode_nine.h"
|
||||
|
||||
static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
static const uint8_t PROGRESS_BAR_MARGIN = 3;
|
||||
static const uint8_t PROGRESS_BAR_HEIGHT = 4;
|
||||
#define PROGRESS_BAR_MARGIN (3)
|
||||
#define PROGRESS_BAR_HEIGHT (4)
|
||||
|
||||
typedef struct {
|
||||
uint8_t progress_bar_x;
|
||||
uint8_t progress_bar_width;
|
||||
uint8_t code_total_length;
|
||||
uint8_t code_offset_x;
|
||||
uint8_t code_offset_x_inc;
|
||||
uint8_t code_offset_y;
|
||||
} UiPrecalculatedDimensions;
|
||||
|
||||
typedef struct {
|
||||
uint16_t current_token_index;
|
||||
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
|
||||
bool need_token_update;
|
||||
TokenInfo* current_token;
|
||||
uint32_t last_token_gen_time;
|
||||
TotpUsbTypeCodeWorkerContext* usb_type_code_worker_context;
|
||||
NotificationMessage const** notification_sequence_new_token;
|
||||
NotificationMessage const** notification_sequence_badusb;
|
||||
NotificationMessage const** notification_sequence_automation;
|
||||
FuriMutex* last_code_update_sync;
|
||||
TotpGenerateCodeWorkerContext* generate_code_worker_context;
|
||||
UiPrecalculatedDimensions ui_precalculated_dimensions;
|
||||
} SceneState;
|
||||
|
||||
static const NotificationSequence*
|
||||
@@ -80,7 +85,7 @@ static const NotificationSequence*
|
||||
|
||||
static const NotificationSequence*
|
||||
get_notification_sequence_automation(const PluginState* plugin_state, SceneState* scene_state) {
|
||||
if(scene_state->notification_sequence_badusb == NULL) {
|
||||
if(scene_state->notification_sequence_automation == NULL) {
|
||||
uint8_t i = 0;
|
||||
uint8_t length = 3;
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
@@ -91,110 +96,100 @@ static const NotificationSequence*
|
||||
length += 6;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length);
|
||||
furi_check(scene_state->notification_sequence_badusb != NULL);
|
||||
scene_state->notification_sequence_automation = malloc(sizeof(void*) * length);
|
||||
furi_check(scene_state->notification_sequence_automation != NULL);
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = &message_blue_255;
|
||||
scene_state->notification_sequence_automation[i++] = &message_blue_255;
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_vibro_on;
|
||||
scene_state->notification_sequence_automation[i++] = &message_vibro_on;
|
||||
}
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_e4;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_badusb[i++] = &message_note_f3;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_d5; //-V525
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_e4;
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_note_f3;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = &message_delay_50;
|
||||
scene_state->notification_sequence_automation[i++] = &message_delay_50;
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodVibro) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_vibro_off;
|
||||
scene_state->notification_sequence_automation[i++] = &message_vibro_off;
|
||||
}
|
||||
|
||||
if(plugin_state->notification_method & NotificationMethodSound) {
|
||||
scene_state->notification_sequence_badusb[i++] = &message_sound_off;
|
||||
scene_state->notification_sequence_automation[i++] = &message_sound_off;
|
||||
}
|
||||
|
||||
scene_state->notification_sequence_badusb[i++] = NULL;
|
||||
scene_state->notification_sequence_automation[i++] = NULL;
|
||||
}
|
||||
|
||||
return (NotificationSequence*)scene_state->notification_sequence_badusb;
|
||||
}
|
||||
|
||||
static void
|
||||
int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
|
||||
if(i_token_code == OTP_ERROR) {
|
||||
memset(&str[0], '-', len);
|
||||
} else {
|
||||
if(algo == STEAM) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
|
||||
i_token_code = i_token_code / 26;
|
||||
}
|
||||
} else {
|
||||
for(int8_t i = len - 1; i >= 0; i--) {
|
||||
str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
|
||||
i_token_code = i_token_code / 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str[len] = '\0';
|
||||
}
|
||||
|
||||
static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
|
||||
switch(algo) {
|
||||
case SHA1:
|
||||
case STEAM:
|
||||
return TOTP_ALGO_SHA1;
|
||||
case SHA256:
|
||||
return TOTP_ALGO_SHA256;
|
||||
case SHA512:
|
||||
return TOTP_ALGO_SHA512;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return (NotificationSequence*)scene_state->notification_sequence_automation;
|
||||
}
|
||||
|
||||
static void update_totp_params(PluginState* const plugin_state) {
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
if(scene_state->current_token_index < plugin_state->tokens_count) {
|
||||
TokenInfo* tokenInfo =
|
||||
scene_state->current_token =
|
||||
list_element_at(plugin_state->tokens_list, scene_state->current_token_index)->data;
|
||||
|
||||
scene_state->need_token_update = true;
|
||||
scene_state->current_token = tokenInfo;
|
||||
totp_generate_code_worker_notify(
|
||||
scene_state->generate_code_worker_context, TotpGenerateCodeWorkerEventForceUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_totp_code(Canvas* const canvas, const SceneState* const scene_state) {
|
||||
uint8_t code_length = scene_state->current_token->digits;
|
||||
uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x;
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
uint8_t total_length = code_length * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
uint8_t offset_x = (SCREEN_WIDTH - total_length) >> 1;
|
||||
uint8_t offset_y = SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1);
|
||||
uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc;
|
||||
for(uint8_t i = 0; i < code_length; i++) {
|
||||
char ch = scene_state->last_code[i];
|
||||
uint8_t char_index = ch - modeNine_15ptFontInfo.startChar;
|
||||
canvas_draw_xbm(
|
||||
canvas,
|
||||
offset_x,
|
||||
offset_y,
|
||||
char_width,
|
||||
modeNine_15ptFontInfo.height,
|
||||
&modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]);
|
||||
if(ch >= modeNine_15ptFontInfo.startChar && ch <= modeNine_15ptFontInfo.endChar) {
|
||||
uint8_t char_index = ch - modeNine_15ptFontInfo.startChar;
|
||||
canvas_draw_xbm(
|
||||
canvas,
|
||||
offset_x,
|
||||
scene_state->ui_precalculated_dimensions.code_offset_y,
|
||||
char_width,
|
||||
modeNine_15ptFontInfo.height,
|
||||
&modeNine_15ptFontInfo.data[modeNine_15ptFontInfo.charInfo[char_index].offset]);
|
||||
}
|
||||
|
||||
offset_x += char_width + modeNine_15ptFontInfo.spacePixels;
|
||||
offset_x += offset_x_inc;
|
||||
}
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_init(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
static void on_new_token_code_generated(bool time_left, void* context) {
|
||||
const PluginState* plugin_state = context;
|
||||
SceneState* scene_state = plugin_state->current_scene_state;
|
||||
uint8_t char_width = modeNine_15ptFontInfo.charInfo[0].width;
|
||||
scene_state->ui_precalculated_dimensions.code_total_length =
|
||||
scene_state->current_token->digits * (char_width + modeNine_15ptFontInfo.spacePixels);
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x =
|
||||
(SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
|
||||
scene_state->ui_precalculated_dimensions.code_offset_x_inc =
|
||||
char_width + modeNine_15ptFontInfo.spacePixels;
|
||||
scene_state->ui_precalculated_dimensions.code_offset_y =
|
||||
SCREEN_HEIGHT_CENTER - (modeNine_15ptFontInfo.height >> 1);
|
||||
|
||||
if(time_left) {
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_new_token(plugin_state, plugin_state->current_scene_state));
|
||||
}
|
||||
}
|
||||
|
||||
static void on_code_lifetime_updated_generated(float code_lifetime_percent, void* context) {
|
||||
SceneState* scene_state = context;
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width =
|
||||
(uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * code_lifetime_percent);
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_x =
|
||||
((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) -
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width) >>
|
||||
1) +
|
||||
PROGRESS_BAR_MARGIN;
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_activate(
|
||||
@@ -234,15 +229,14 @@ void totp_scene_generate_token_activate(
|
||||
} else {
|
||||
scene_state->current_token_index = context->current_token_index;
|
||||
}
|
||||
scene_state->need_token_update = true;
|
||||
|
||||
plugin_state->current_scene_state = scene_state;
|
||||
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
|
||||
update_totp_params(plugin_state);
|
||||
|
||||
scene_state->last_code_update_sync = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||
scene_state->usb_type_code_worker_context = totp_usb_type_code_worker_start(
|
||||
&scene_state->last_code[0],
|
||||
scene_state->last_code,
|
||||
TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
|
||||
scene_state->last_code_update_sync);
|
||||
}
|
||||
@@ -255,11 +249,28 @@ void totp_scene_generate_token_activate(
|
||||
}
|
||||
totp_bt_type_code_worker_start(
|
||||
plugin_state->bt_type_code_worker_context,
|
||||
&scene_state->last_code[0],
|
||||
scene_state->last_code,
|
||||
TOTP_TOKEN_DIGITS_MAX_COUNT + 1,
|
||||
scene_state->last_code_update_sync);
|
||||
}
|
||||
#endif
|
||||
|
||||
scene_state->generate_code_worker_context = totp_generate_code_worker_start(
|
||||
scene_state->last_code,
|
||||
&scene_state->current_token,
|
||||
scene_state->last_code_update_sync,
|
||||
plugin_state->timezone_offset,
|
||||
plugin_state->iv);
|
||||
|
||||
totp_generate_code_worker_set_code_generated_handler(
|
||||
scene_state->generate_code_worker_context, &on_new_token_code_generated, plugin_state);
|
||||
|
||||
totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
scene_state->generate_code_worker_context,
|
||||
&on_code_lifetime_updated_generated,
|
||||
scene_state);
|
||||
|
||||
update_totp_params(plugin_state);
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
|
||||
@@ -281,54 +292,7 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
return;
|
||||
}
|
||||
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
FuriHalRtcDateTime curr_dt;
|
||||
furi_hal_rtc_get_datetime(&curr_dt);
|
||||
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
|
||||
|
||||
bool is_new_token_time = curr_ts % scene_state->current_token->duration == 0;
|
||||
if(is_new_token_time && scene_state->last_token_gen_time != curr_ts) {
|
||||
scene_state->need_token_update = true;
|
||||
}
|
||||
|
||||
if(scene_state->need_token_update) {
|
||||
scene_state->need_token_update = false;
|
||||
scene_state->last_token_gen_time = curr_ts;
|
||||
|
||||
const TokenInfo* tokenInfo = scene_state->current_token;
|
||||
|
||||
if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
|
||||
furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever);
|
||||
size_t key_length;
|
||||
uint8_t* key = totp_crypto_decrypt(
|
||||
tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
|
||||
|
||||
int_token_to_str(
|
||||
totp_at(
|
||||
get_totp_algo_impl(tokenInfo->algo),
|
||||
key,
|
||||
key_length,
|
||||
curr_ts,
|
||||
plugin_state->timezone_offset,
|
||||
tokenInfo->duration),
|
||||
scene_state->last_code,
|
||||
tokenInfo->digits,
|
||||
tokenInfo->algo);
|
||||
memset_s(key, key_length, 0, key_length);
|
||||
free(key);
|
||||
} else {
|
||||
furi_mutex_acquire(scene_state->last_code_update_sync, FuriWaitForever);
|
||||
int_token_to_str(0, scene_state->last_code, tokenInfo->digits, tokenInfo->algo);
|
||||
}
|
||||
|
||||
furi_mutex_release(scene_state->last_code_update_sync);
|
||||
|
||||
if(is_new_token_time) {
|
||||
notification_message(
|
||||
plugin_state->notification_app,
|
||||
get_notification_sequence_new_token(plugin_state, scene_state));
|
||||
}
|
||||
}
|
||||
const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
uint16_t token_name_width = canvas_string_width(canvas, scene_state->current_token->name);
|
||||
@@ -356,17 +320,11 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
|
||||
|
||||
draw_totp_code(canvas, scene_state);
|
||||
|
||||
const uint8_t TOKEN_LIFETIME = scene_state->current_token->duration;
|
||||
float percentDone = (float)(TOKEN_LIFETIME - curr_ts % TOKEN_LIFETIME) / (float)TOKEN_LIFETIME;
|
||||
uint8_t barWidth = (uint8_t)((float)(SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1)) * percentDone);
|
||||
uint8_t barX =
|
||||
((SCREEN_WIDTH - (PROGRESS_BAR_MARGIN << 1) - barWidth) >> 1) + PROGRESS_BAR_MARGIN;
|
||||
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
barX,
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_x,
|
||||
SCREEN_HEIGHT - PROGRESS_BAR_MARGIN - PROGRESS_BAR_HEIGHT,
|
||||
barWidth,
|
||||
scene_state->ui_precalculated_dimensions.progress_bar_width,
|
||||
PROGRESS_BAR_HEIGHT);
|
||||
|
||||
if(plugin_state->tokens_count > 1) {
|
||||
@@ -496,6 +454,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
||||
if(plugin_state->current_scene_state == NULL) return;
|
||||
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
|
||||
|
||||
totp_generate_code_worker_stop(scene_state->generate_code_worker_context);
|
||||
|
||||
if(plugin_state->automation_method & AutomationMethodBadUsb) {
|
||||
totp_usb_type_code_worker_stop(scene_state->usb_type_code_worker_context);
|
||||
}
|
||||
@@ -509,8 +469,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
||||
free(scene_state->notification_sequence_new_token);
|
||||
}
|
||||
|
||||
if(scene_state->notification_sequence_badusb != NULL) {
|
||||
free(scene_state->notification_sequence_badusb);
|
||||
if(scene_state->notification_sequence_automation != NULL) {
|
||||
free(scene_state->notification_sequence_automation);
|
||||
}
|
||||
|
||||
furi_mutex_free(scene_state->last_code_update_sync);
|
||||
@@ -518,7 +478,3 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
|
||||
free(scene_state);
|
||||
plugin_state->current_scene_state = NULL;
|
||||
}
|
||||
|
||||
void totp_scene_generate_token_free(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} GenerateTokenSceneContext;
|
||||
|
||||
void totp_scene_generate_token_init(const PluginState* plugin_state);
|
||||
void totp_scene_generate_token_activate(
|
||||
PluginState* plugin_state,
|
||||
const GenerateTokenSceneContext* context);
|
||||
@@ -17,4 +16,3 @@ bool totp_scene_generate_token_handle_event(
|
||||
const PluginEvent* const event,
|
||||
PluginState* plugin_state);
|
||||
void totp_scene_generate_token_deactivate(PluginState* plugin_state);
|
||||
void totp_scene_generate_token_free(const PluginState* plugin_state);
|
||||
|
||||
@@ -24,10 +24,6 @@ typedef struct {
|
||||
TotpNullable_uint16_t current_token_index;
|
||||
} SceneState;
|
||||
|
||||
void totp_scene_token_menu_init(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
void totp_scene_token_menu_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenMenuSceneContext* context) {
|
||||
@@ -204,7 +200,3 @@ void totp_scene_token_menu_deactivate(PluginState* plugin_state) {
|
||||
free(plugin_state->current_scene_state);
|
||||
plugin_state->current_scene_state = NULL;
|
||||
}
|
||||
|
||||
void totp_scene_token_menu_free(const PluginState* plugin_state) {
|
||||
UNUSED(plugin_state);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,9 @@ typedef struct {
|
||||
uint16_t current_token_index;
|
||||
} TokenMenuSceneContext;
|
||||
|
||||
void totp_scene_token_menu_init(const PluginState* plugin_state);
|
||||
void totp_scene_token_menu_activate(
|
||||
PluginState* plugin_state,
|
||||
const TokenMenuSceneContext* context);
|
||||
void totp_scene_token_menu_render(Canvas* const canvas, PluginState* plugin_state);
|
||||
bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginState* plugin_state);
|
||||
void totp_scene_token_menu_deactivate(PluginState* plugin_state);
|
||||
void totp_scene_token_menu_free(const PluginState* plugin_state);
|
||||
|
||||
4
applications/external/totp/ui/ui_controls.c
vendored
4
applications/external/totp/ui/ui_controls.c
vendored
@@ -2,8 +2,8 @@
|
||||
#include <totp_icons.h>
|
||||
#include "constants.h"
|
||||
|
||||
#define TEXT_BOX_HEIGHT 13
|
||||
#define TEXT_BOX_MARGIN 4
|
||||
#define TEXT_BOX_HEIGHT (13)
|
||||
#define TEXT_BOX_MARGIN (4)
|
||||
|
||||
void ui_control_text_box_render(
|
||||
Canvas* const canvas,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "bt_type_code.h"
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
#include <storage/storage.h>
|
||||
#include "../../types/common.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../common.h"
|
||||
#include "../type_code_common.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("authenticator/.bt_hid.keys")
|
||||
|
||||
@@ -16,15 +17,15 @@ static inline bool totp_type_code_worker_stop_requested() {
|
||||
static void totp_type_code_worker_bt_set_app_mac(uint8_t* mac) {
|
||||
uint8_t max_i;
|
||||
size_t uid_size = furi_hal_version_uid_size();
|
||||
if(uid_size < 6) {
|
||||
if(uid_size < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN) {
|
||||
max_i = uid_size;
|
||||
} else {
|
||||
max_i = 6;
|
||||
max_i = TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN;
|
||||
}
|
||||
|
||||
const uint8_t* uid = furi_hal_version_uid();
|
||||
memcpy(mac, uid, max_i);
|
||||
for(uint8_t i = max_i; i < 6; i++) {
|
||||
for(uint8_t i = max_i; i < TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN; i++) {
|
||||
mac[i] = 0;
|
||||
}
|
||||
|
||||
@@ -39,23 +40,21 @@ static void totp_type_code_worker_type_code(TotpBtTypeCodeWorkerContext* context
|
||||
i++;
|
||||
} while(!context->is_connected && i < 100 && !totp_type_code_worker_stop_requested());
|
||||
|
||||
if(context->is_connected && furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
|
||||
if(context->is_connected &&
|
||||
furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
|
||||
totp_type_code_worker_execute_automation(
|
||||
&furi_hal_bt_hid_kb_press,
|
||||
&furi_hal_bt_hid_kb_release,
|
||||
context->string,
|
||||
context->string_length,
|
||||
context->code_buffer,
|
||||
context->code_buffer_size,
|
||||
context->flags);
|
||||
furi_mutex_release(context->string_sync);
|
||||
furi_mutex_release(context->code_buffer_sync);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t totp_type_code_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(context_mutex == NULL) {
|
||||
return 251;
|
||||
}
|
||||
|
||||
TotpBtTypeCodeWorkerContext* bt_context = context;
|
||||
|
||||
@@ -92,13 +91,13 @@ static void connection_status_changed_callback(BtStatus status, void* context) {
|
||||
|
||||
void totp_bt_type_code_worker_start(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync) {
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync) {
|
||||
furi_check(context != NULL);
|
||||
context->string = code_buf;
|
||||
context->string_length = code_buf_length;
|
||||
context->string_sync = code_buf_update_sync;
|
||||
context->code_buffer = code_buffer;
|
||||
context->code_buffer_size = code_buffer_size;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(context->thread, "TOTPBtHidWorker");
|
||||
furi_thread_set_stack_size(context->thread, 1024);
|
||||
@@ -137,7 +136,6 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
|
||||
bt_keys_storage_set_storage_path(context->bt, HID_BT_KEYS_STORAGE_PATH);
|
||||
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
totp_type_code_worker_bt_set_app_mac(&context->bt_mac[0]);
|
||||
memcpy(
|
||||
&context->previous_bt_name[0],
|
||||
furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
|
||||
@@ -148,8 +146,10 @@ TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init() {
|
||||
TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN);
|
||||
char new_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
snprintf(new_name, sizeof(new_name), "%s TOTP Auth", furi_hal_version_get_name_ptr());
|
||||
uint8_t new_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
totp_type_code_worker_bt_set_app_mac(new_bt_mac);
|
||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, new_name);
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, context->bt_mac);
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, new_bt_mac);
|
||||
#endif
|
||||
|
||||
if(!bt_set_profile(context->bt, BtProfileHidKeyboard)) {
|
||||
|
||||
@@ -1,49 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/string.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include "../../features_config.h"
|
||||
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
#define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN 18
|
||||
#define TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH
|
||||
#define TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE
|
||||
#endif
|
||||
|
||||
typedef uint8_t TotpBtTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* string;
|
||||
uint8_t string_length;
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* string_sync;
|
||||
FuriMutex* code_buffer_sync;
|
||||
Bt* bt;
|
||||
bool is_advertising;
|
||||
bool is_connected;
|
||||
#if TOTP_TARGET_FIRMWARE == TOTP_FIRMWARE_XTREME
|
||||
uint8_t bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN + 1];
|
||||
char previous_bt_name[TOTP_BT_WORKER_BT_ADV_NAME_MAX_LEN];
|
||||
uint8_t previous_bt_mac[TOTP_BT_WORKER_BT_MAC_ADDRESS_LEN];
|
||||
#endif
|
||||
} TotpBtTypeCodeWorkerContext;
|
||||
|
||||
enum TotpBtTypeCodeWorkerEvents {
|
||||
TotpBtTypeCodeWorkerEventReserved = 0b0000,
|
||||
TotpBtTypeCodeWorkerEventStop = 0b0100,
|
||||
TotpBtTypeCodeWorkerEventType = 0b1000
|
||||
TotpBtTypeCodeWorkerEventReserved = 0b00,
|
||||
TotpBtTypeCodeWorkerEventStop = 0b01,
|
||||
TotpBtTypeCodeWorkerEventType = 0b10
|
||||
};
|
||||
|
||||
TotpBtTypeCodeWorkerContext* totp_bt_type_code_worker_init();
|
||||
void totp_bt_type_code_worker_free(TotpBtTypeCodeWorkerContext* context);
|
||||
void totp_bt_type_code_worker_start(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync);
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
void totp_bt_type_code_worker_stop(TotpBtTypeCodeWorkerContext* context);
|
||||
void totp_bt_type_code_worker_notify(
|
||||
TotpBtTypeCodeWorkerContext* context,
|
||||
TotpBtTypeCodeWorkerEvent event,
|
||||
uint8_t flags);
|
||||
uint8_t flags);
|
||||
|
||||
181
applications/external/totp/workers/generate_totp_code/generate_totp_code.c
vendored
Normal file
181
applications/external/totp/workers/generate_totp_code/generate_totp_code.c
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "generate_totp_code.h"
|
||||
#include "../../services/crypto/crypto.h"
|
||||
#include "../../services/totp/totp.h"
|
||||
#include "../../services/convert/convert.h"
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <memset_s.h>
|
||||
|
||||
#define ONE_SEC_MS (1000)
|
||||
|
||||
static const char* STEAM_ALGO_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
|
||||
static void
|
||||
int_token_to_str(uint64_t i_token_code, char* str, TokenDigitsCount len, TokenHashAlgo algo) {
|
||||
str[len] = '\0';
|
||||
if(i_token_code == OTP_ERROR) {
|
||||
memset(&str[0], '-', len);
|
||||
} else {
|
||||
if(algo == STEAM) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
str[i] = STEAM_ALGO_ALPHABET[i_token_code % 26];
|
||||
i_token_code = i_token_code / 26;
|
||||
}
|
||||
} else {
|
||||
for(int8_t i = len - 1; i >= 0; i--) {
|
||||
str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
|
||||
i_token_code = i_token_code / 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
|
||||
switch(algo) {
|
||||
case SHA1:
|
||||
case STEAM:
|
||||
return TOTP_ALGO_SHA1;
|
||||
case SHA256:
|
||||
return TOTP_ALGO_SHA256;
|
||||
case SHA512:
|
||||
return TOTP_ALGO_SHA512;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void generate_totp_code(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
const TokenInfo* token_info,
|
||||
uint32_t current_ts) {
|
||||
if(token_info->token != NULL && token_info->token_length > 0) {
|
||||
size_t key_length;
|
||||
uint8_t* key = totp_crypto_decrypt(
|
||||
token_info->token, token_info->token_length, context->iv, &key_length);
|
||||
|
||||
int_token_to_str(
|
||||
totp_at(
|
||||
get_totp_algo_impl(token_info->algo),
|
||||
key,
|
||||
key_length,
|
||||
current_ts,
|
||||
context->timezone_offset,
|
||||
token_info->duration),
|
||||
context->code_buffer,
|
||||
token_info->digits,
|
||||
token_info->algo);
|
||||
memset_s(key, key_length, 0, key_length);
|
||||
free(key);
|
||||
} else {
|
||||
int_token_to_str(0, context->code_buffer, token_info->digits, token_info->algo);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t totp_generate_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
|
||||
TotpGenerateCodeWorkerContext* t_context = context;
|
||||
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
TotpGenerateCodeWorkerEventStop | TotpGenerateCodeWorkerEventForceUpdate,
|
||||
FuriFlagWaitAny,
|
||||
ONE_SEC_MS);
|
||||
|
||||
if(flags ==
|
||||
(uint32_t)
|
||||
FuriFlagErrorTimeout) { // If timeout, consider as no error, as we expect this and can handle gracefully
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
furi_check((flags & FuriFlagError) == 0); //-V562
|
||||
|
||||
if(flags & TotpGenerateCodeWorkerEventStop) break;
|
||||
|
||||
const TokenInfo* token_info = *(t_context->token_info);
|
||||
if(token_info == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t curr_ts = furi_hal_rtc_get_timestamp();
|
||||
|
||||
bool time_left = false;
|
||||
if(flags & TotpGenerateCodeWorkerEventForceUpdate ||
|
||||
(time_left = (curr_ts % token_info->duration) == 0)) {
|
||||
if(furi_mutex_acquire(t_context->code_buffer_sync, FuriWaitForever) == FuriStatusOk) {
|
||||
generate_totp_code(t_context, token_info, curr_ts);
|
||||
curr_ts = furi_hal_rtc_get_timestamp();
|
||||
furi_mutex_release(t_context->code_buffer_sync);
|
||||
if(t_context->on_new_code_generated_handler != NULL) {
|
||||
(*(t_context->on_new_code_generated_handler))(
|
||||
time_left, t_context->on_new_code_generated_handler_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(t_context->on_code_lifetime_changed_handler != NULL) {
|
||||
(*(t_context->on_code_lifetime_changed_handler))(
|
||||
(float)(token_info->duration - curr_ts % token_info->duration) /
|
||||
(float)token_info->duration,
|
||||
t_context->on_code_lifetime_changed_handler_context);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv) {
|
||||
TotpGenerateCodeWorkerContext* context = malloc(sizeof(TotpGenerateCodeWorkerContext));
|
||||
furi_check(context != NULL);
|
||||
context->code_buffer = code_buffer;
|
||||
context->token_info = token_info;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->timezone_offset = timezone_offset;
|
||||
context->iv = iv;
|
||||
context->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(context->thread, "TOTPGenerateWorker");
|
||||
furi_thread_set_stack_size(context->thread, 2048);
|
||||
furi_thread_set_context(context->thread, context);
|
||||
furi_thread_set_callback(context->thread, totp_generate_worker_callback);
|
||||
furi_thread_start(context->thread);
|
||||
return context;
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context) {
|
||||
furi_check(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), TotpGenerateCodeWorkerEventStop);
|
||||
furi_thread_join(context->thread);
|
||||
furi_thread_free(context->thread);
|
||||
free(context);
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_notify(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TotpGenerateCodeWorkerEvent event) {
|
||||
furi_check(context != NULL);
|
||||
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_set_code_generated_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||
void* on_new_code_generated_handler_context) {
|
||||
furi_check(context != NULL);
|
||||
context->on_new_code_generated_handler = on_new_code_generated_handler;
|
||||
context->on_new_code_generated_handler_context = on_new_code_generated_handler_context;
|
||||
}
|
||||
|
||||
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||
void* on_code_lifetime_changed_handler_context) {
|
||||
furi_check(context != NULL);
|
||||
context->on_code_lifetime_changed_handler = on_code_lifetime_changed_handler;
|
||||
context->on_code_lifetime_changed_handler_context = on_code_lifetime_changed_handler_context;
|
||||
}
|
||||
49
applications/external/totp/workers/generate_totp_code/generate_totp_code.h
vendored
Normal file
49
applications/external/totp/workers/generate_totp_code/generate_totp_code.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include "../../types/token_info.h"
|
||||
|
||||
typedef uint8_t TotpGenerateCodeWorkerEvent;
|
||||
|
||||
typedef void (*TOTP_NEW_CODE_GENERATED_HANDLER)(bool time_left, void* context);
|
||||
typedef void (*TOTP_CODE_LIFETIME_CHANGED_HANDLER)(float code_lifetime_percent, void* context);
|
||||
|
||||
typedef struct {
|
||||
char* code_buffer;
|
||||
FuriThread* thread;
|
||||
FuriMutex* code_buffer_sync;
|
||||
TokenInfo** token_info;
|
||||
float timezone_offset;
|
||||
uint8_t* iv;
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler;
|
||||
void* on_new_code_generated_handler_context;
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler;
|
||||
void* on_code_lifetime_changed_handler_context;
|
||||
} TotpGenerateCodeWorkerContext;
|
||||
|
||||
enum TotGenerateCodeWorkerEvents {
|
||||
TotpGenerateCodeWorkerEventReserved = 0b00,
|
||||
TotpGenerateCodeWorkerEventStop = 0b01,
|
||||
TotpGenerateCodeWorkerEventForceUpdate = 0b10
|
||||
};
|
||||
|
||||
TotpGenerateCodeWorkerContext* totp_generate_code_worker_start(
|
||||
char* code_buffer,
|
||||
TokenInfo** token_info,
|
||||
FuriMutex* code_buffer_sync,
|
||||
float timezone_offset,
|
||||
uint8_t* iv);
|
||||
void totp_generate_code_worker_stop(TotpGenerateCodeWorkerContext* context);
|
||||
void totp_generate_code_worker_notify(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TotpGenerateCodeWorkerEvent event);
|
||||
void totp_generate_code_worker_set_code_generated_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_NEW_CODE_GENERATED_HANDLER on_new_code_generated_handler,
|
||||
void* on_new_code_generated_handler_context);
|
||||
void totp_generate_code_worker_set_lifetime_changed_handler(
|
||||
TotpGenerateCodeWorkerContext* context,
|
||||
TOTP_CODE_LIFETIME_CHANGED_HANDLER on_code_lifetime_changed_handler,
|
||||
void* on_code_lifetime_changed_handler_context);
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common.h"
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "type_code_common.h"
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include "../../services/convert/convert.h"
|
||||
|
||||
static const uint8_t hid_number_keys[] = {
|
||||
@@ -42,18 +42,18 @@ static void totp_type_code_worker_press_key(
|
||||
void totp_type_code_worker_execute_automation(
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||
const char* string,
|
||||
uint8_t string_length,
|
||||
const char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
TokenAutomationFeature features) {
|
||||
furi_delay_ms(500);
|
||||
uint8_t i = 0;
|
||||
totp_type_code_worker_press_key(
|
||||
HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features);
|
||||
|
||||
while(i < string_length && string[i] != 0) {
|
||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(string[i]);
|
||||
while(i < code_buffer_size && code_buffer[i] != 0) {
|
||||
uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]);
|
||||
if(char_index > 9) {
|
||||
char_index = string[i] - 0x41 + 10;
|
||||
char_index = code_buffer[i] - 0x41 + 10;
|
||||
}
|
||||
|
||||
if(char_index > 35) break;
|
||||
@@ -7,6 +7,6 @@ typedef bool (*TOTP_AUTOMATION_KEY_HANDLER)(uint16_t key);
|
||||
void totp_type_code_worker_execute_automation(
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_press_fn,
|
||||
TOTP_AUTOMATION_KEY_HANDLER key_release_fn,
|
||||
const char* string,
|
||||
uint8_t string_length,
|
||||
const char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
TokenAutomationFeature features);
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "usb_type_code.h"
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "../../services/convert/convert.h"
|
||||
#include "../../types/token_info.h"
|
||||
#include "../common.h"
|
||||
#include "../type_code_common.h"
|
||||
|
||||
static void totp_type_code_worker_restore_usb_mode(TotpUsbTypeCodeWorkerContext* context) {
|
||||
if(context->usb_mode_prev != NULL) {
|
||||
@@ -25,14 +26,14 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
|
||||
} while(!furi_hal_hid_is_connected() && i < 100 && !totp_type_code_worker_stop_requested());
|
||||
|
||||
if(furi_hal_hid_is_connected() &&
|
||||
furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
|
||||
furi_mutex_acquire(context->code_buffer_sync, 500) == FuriStatusOk) {
|
||||
totp_type_code_worker_execute_automation(
|
||||
&furi_hal_hid_kb_press,
|
||||
&furi_hal_hid_kb_release,
|
||||
context->string,
|
||||
context->string_length,
|
||||
context->code_buffer,
|
||||
context->code_buffer_size,
|
||||
context->flags);
|
||||
furi_mutex_release(context->string_sync);
|
||||
furi_mutex_release(context->code_buffer_sync);
|
||||
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
@@ -43,9 +44,6 @@ static void totp_type_code_worker_type_code(TotpUsbTypeCodeWorkerContext* contex
|
||||
static int32_t totp_type_code_worker_callback(void* context) {
|
||||
furi_check(context);
|
||||
FuriMutex* context_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(context_mutex == NULL) {
|
||||
return 251;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
@@ -70,14 +68,14 @@ static int32_t totp_type_code_worker_callback(void* context) {
|
||||
}
|
||||
|
||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync) {
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync) {
|
||||
TotpUsbTypeCodeWorkerContext* context = malloc(sizeof(TotpUsbTypeCodeWorkerContext));
|
||||
furi_check(context != NULL);
|
||||
context->string = code_buf;
|
||||
context->string_length = code_buf_length;
|
||||
context->string_sync = code_buf_update_sync;
|
||||
context->code_buffer = code_buffer;
|
||||
context->code_buffer_size = code_buffer_size;
|
||||
context->code_buffer_sync = code_buffer_sync;
|
||||
context->thread = furi_thread_alloc();
|
||||
context->usb_mode_prev = NULL;
|
||||
furi_thread_set_name(context->thread, "TOTPUsbHidWorker");
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <furi/furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi/core/thread.h>
|
||||
#include <furi/core/mutex.h>
|
||||
#include <furi/core/kernel.h>
|
||||
#include <furi/core/check.h>
|
||||
#include <furi_hal_usb.h>
|
||||
|
||||
typedef uint8_t TotpUsbTypeCodeWorkerEvent;
|
||||
|
||||
typedef struct {
|
||||
char* string;
|
||||
uint8_t string_length;
|
||||
char* code_buffer;
|
||||
uint8_t code_buffer_size;
|
||||
uint8_t flags;
|
||||
FuriThread* thread;
|
||||
FuriMutex* string_sync;
|
||||
FuriMutex* code_buffer_sync;
|
||||
FuriHalUsbInterface* usb_mode_prev;
|
||||
} TotpUsbTypeCodeWorkerContext;
|
||||
|
||||
@@ -22,9 +25,9 @@ enum TotpUsbTypeCodeWorkerEvents {
|
||||
};
|
||||
|
||||
TotpUsbTypeCodeWorkerContext* totp_usb_type_code_worker_start(
|
||||
char* code_buf,
|
||||
uint8_t code_buf_length,
|
||||
FuriMutex* code_buf_update_sync);
|
||||
char* code_buffer,
|
||||
uint8_t code_buffer_size,
|
||||
FuriMutex* code_buffer_sync);
|
||||
void totp_usb_type_code_worker_stop(TotpUsbTypeCodeWorkerContext* context);
|
||||
void totp_usb_type_code_worker_notify(
|
||||
TotpUsbTypeCodeWorkerContext* context,
|
||||
|
||||
@@ -114,13 +114,9 @@ void uart_terminal_scene_console_output_on_enter(void* context) {
|
||||
// Send command with CR+LF or newline '\n'
|
||||
if(app->is_command && app->selected_tx_string) {
|
||||
if(app->TERMINAL_MODE == 1) {
|
||||
// char buffer[240];
|
||||
// snprintf(buffer, 240, "%s\r\n", (app->selected_tx_string));
|
||||
// uart_terminal_uart_tx((unsigned char *)buffer, strlen(buffer));
|
||||
uart_terminal_uart_tx(
|
||||
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
||||
uart_terminal_uart_tx((uint8_t*)("\r"), 1);
|
||||
uart_terminal_uart_tx((uint8_t*)("\n"), 1);
|
||||
uart_terminal_uart_tx((uint8_t*)("\r\n"), 2);
|
||||
} else {
|
||||
uart_terminal_uart_tx(
|
||||
(uint8_t*)(app->selected_tx_string), strlen(app->selected_tx_string));
|
||||
@@ -149,9 +145,4 @@ void uart_terminal_scene_console_output_on_exit(void* context) {
|
||||
|
||||
// Unregister rx callback
|
||||
uart_terminal_uart_set_handle_rx_data_cb(app->uart, NULL);
|
||||
|
||||
// Automatically logut when exiting view
|
||||
//if(app->is_command) {
|
||||
// uart_terminal_uart_tx((uint8_t*)("exit\n"), strlen("exit\n"));
|
||||
//}
|
||||
}
|
||||
2
applications/external/unitemp/Sensors.c
vendored
2
applications/external/unitemp/Sensors.c
vendored
@@ -45,7 +45,7 @@ static const GPIO GPIOList[] = {
|
||||
{14, "14 (RX)", &RX_14},
|
||||
{15, "15 (C1)", &gpio_ext_pc1},
|
||||
{16, "16 (C0)", &gpio_ext_pc0},
|
||||
{17, "17 (1W)", &ibutton_gpio}};
|
||||
{17, "17 (1W)", &gpio_ibutton}};
|
||||
|
||||
//Список интерфейсов, которые прикреплены к GPIO (определяется индексом)
|
||||
//NULL - порт свободен, указатель на интерфейс - порт занят этим интерфейсом
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
@@ -23,8 +24,6 @@ struct FapLoader {
|
||||
Loading* loading;
|
||||
};
|
||||
|
||||
volatile bool fap_loader_debug_active = false;
|
||||
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
@@ -134,7 +133,7 @@ static bool fap_loader_run_selected_app(FapLoader* loader, bool ignore_mismatch)
|
||||
FuriThread* thread = flipper_application_spawn(loader->app, NULL);
|
||||
|
||||
/* This flag is set by the debugger - to break on app start */
|
||||
if(fap_loader_debug_active) {
|
||||
if(furi_hal_debug_is_gdb_session_active()) {
|
||||
FURI_LOG_W(TAG, "Triggering BP for debugger");
|
||||
/* After hitting this, you can set breakpoints in your .fap's code
|
||||
* Note that you have to toggle breakpoints that were set before */
|
||||
|
||||
@@ -25,7 +25,7 @@ static void onewire_cli_print_usage() {
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
OneWireHost* onewire = onewire_host_alloc(&gpio_ibutton);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
|
||||
@@ -239,7 +239,11 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
subghz_read_raw_set_status(
|
||||
subghz->subghz_read_raw,
|
||||
SubGhzReadRAWStatusIDLE,
|
||||
"",
|
||||
subghz->txrx->raw_threshold_rssi);
|
||||
} else {
|
||||
if(scene_manager_has_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSaved) ||
|
||||
|
||||
@@ -74,9 +74,7 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
|
||||
(subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
|
||||
if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
} else {
|
||||
if(subghz_tx_start(subghz, subghz->txrx->fff_data)) {
|
||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||
subghz_scene_transmitter_update_data_show(subghz);
|
||||
DOLPHIN_DEED(DolphinDeedSubGhzSend);
|
||||
|
||||
@@ -106,9 +106,11 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
|
||||
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
||||
furi_hal_gpio_init(
|
||||
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
subghz_speaker_on(subghz);
|
||||
bool ret = furi_hal_subghz_tx();
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
|
||||
if(ret) {
|
||||
subghz_speaker_on(subghz);
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -116,6 +118,7 @@ void subghz_idle(SubGhz* subghz) {
|
||||
furi_assert(subghz);
|
||||
furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
|
||||
furi_hal_subghz_idle();
|
||||
subghz_speaker_off(subghz);
|
||||
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
|
||||
}
|
||||
|
||||
@@ -611,7 +614,7 @@ void subghz_hopper_update(SubGhz* subghz) {
|
||||
|
||||
void subghz_speaker_on(SubGhz* subghz) {
|
||||
if(subghz->txrx->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio);
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
||||
}
|
||||
|
||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
@@ -656,7 +659,7 @@ void subghz_speaker_mute(SubGhz* subghz) {
|
||||
|
||||
void subghz_speaker_unmute(SubGhz* subghz) {
|
||||
if(subghz->txrx->debug_pin_state) {
|
||||
furi_hal_subghz_set_async_mirror_pin(&ibutton_gpio);
|
||||
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
||||
}
|
||||
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
||||
if(furi_hal_speaker_is_mine()) {
|
||||
|
||||
@@ -137,6 +137,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
|
||||
true);
|
||||
|
||||
if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
|
||||
subghz_custom_btn_set(0);
|
||||
with_view_model(
|
||||
subghz_transmitter->view,
|
||||
SubGhzViewTransmitterModel * model,
|
||||
|
||||
@@ -354,6 +354,8 @@ bool subghz_remote_key_load(
|
||||
|
||||
bool res = false;
|
||||
|
||||
subghz_custom_btn_set(0);
|
||||
|
||||
do {
|
||||
// load frequency from file
|
||||
if(!flipper_format_read_uint32(fff_file, "Frequency", &preset->frequency, 1)) {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <assets_icons.h>
|
||||
#include <locale/locale.h>
|
||||
|
||||
#define LOW_CHARGE_THRESHOLD 10
|
||||
#define HIGH_DRAIN_CURRENT_THRESHOLD 100
|
||||
#define LOW_CHARGE_THRESHOLD (10)
|
||||
#define HIGH_DRAIN_CURRENT_THRESHOLD (-100)
|
||||
|
||||
struct BatteryInfo {
|
||||
View* view;
|
||||
@@ -25,14 +25,13 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
char header[20] = {};
|
||||
char value[20] = {};
|
||||
|
||||
int32_t drain_current = data->gauge_current * (-1000);
|
||||
uint32_t charge_current = data->gauge_current * 1000;
|
||||
int32_t current = 1000.0f * data->gauge_current;
|
||||
|
||||
// Draw battery
|
||||
canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28);
|
||||
if(charge_current > 0) {
|
||||
if(current > 0) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14);
|
||||
} else if(drain_current > HIGH_DRAIN_CURRENT_THRESHOLD) {
|
||||
} else if(current < HIGH_DRAIN_CURRENT_THRESHOLD) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14);
|
||||
} else if(data->charge < LOW_CHARGE_THRESHOLD) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14);
|
||||
@@ -44,7 +43,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
elements_bubble(canvas, 53, 0, 71, 39);
|
||||
|
||||
// Set text
|
||||
if(charge_current > 0) {
|
||||
if(current > 0) {
|
||||
snprintf(emote, sizeof(emote), "%s", "Yummy!");
|
||||
snprintf(header, sizeof(header), "%s", "Charging at");
|
||||
snprintf(
|
||||
@@ -53,34 +52,36 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
"%lu.%luV %lumA",
|
||||
(uint32_t)(data->vbus_voltage),
|
||||
(uint32_t)(data->vbus_voltage * 10) % 10,
|
||||
charge_current);
|
||||
} else if(drain_current > 0) {
|
||||
current);
|
||||
} else if(current < 0) {
|
||||
snprintf(
|
||||
emote,
|
||||
sizeof(emote),
|
||||
"%s",
|
||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!");
|
||||
current < HIGH_DRAIN_CURRENT_THRESHOLD ? "Oh no!" : "Om-nom-nom!");
|
||||
snprintf(header, sizeof(header), "%s", "Consumption is");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%ld %s",
|
||||
drain_current,
|
||||
drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
||||
} else if(drain_current != 0) {
|
||||
snprintf(header, 20, "...");
|
||||
} else if(data->charge_voltage_limit < 4.2) {
|
||||
// Non-default battery charging limit, mention it
|
||||
snprintf(emote, sizeof(emote), "Charged!");
|
||||
snprintf(header, sizeof(header), "Limited to");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%lu.%luV",
|
||||
(uint32_t)(data->charge_voltage_limit),
|
||||
(uint32_t)(data->charge_voltage_limit * 10) % 10);
|
||||
ABS(current),
|
||||
current < HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA");
|
||||
} else if(data->vbus_voltage > 0) {
|
||||
if(data->charge_voltage_limit < 4.2) {
|
||||
// Non-default battery charging limit, mention it
|
||||
snprintf(emote, sizeof(emote), "Charged!");
|
||||
snprintf(header, sizeof(header), "Limited to");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%lu.%luV",
|
||||
(uint32_t)(data->charge_voltage_limit),
|
||||
(uint32_t)(data->charge_voltage_limit * 10) % 10);
|
||||
} else {
|
||||
snprintf(header, sizeof(header), "Charged!");
|
||||
}
|
||||
} else {
|
||||
snprintf(header, sizeof(header), "Charged!");
|
||||
snprintf(header, sizeof(header), "Napping...");
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
|
||||
|
||||
@@ -141,6 +141,21 @@ static void hand_orient_changed(VariableItem* item) {
|
||||
loader_update_menu();
|
||||
}
|
||||
|
||||
const char* const sleep_method[] = {
|
||||
"Default",
|
||||
"Legacy",
|
||||
};
|
||||
|
||||
static void sleep_method_changed(VariableItem* item) {
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, sleep_method[index]);
|
||||
if(index) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagLegacySleep);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagLegacySleep);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t system_settings_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
@@ -218,6 +233,12 @@ SystemSettings* system_settings_alloc() {
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, heap_trace_mode_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->var_item_list, "Sleep Method", COUNT_OF(sleep_method), sleep_method_changed, app);
|
||||
value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) ? 1 : 0;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, sleep_method[value_index]);
|
||||
|
||||
view_set_previous_callback(
|
||||
variable_item_list_get_view(app->var_item_list), system_settings_exit);
|
||||
view_dispatcher_add_view(
|
||||
|
||||
@@ -135,6 +135,7 @@ class FlipperAppStateHelper:
|
||||
self.app_list_ptr = None
|
||||
self.app_list_entry_type = None
|
||||
self._current_apps: list[AppState] = []
|
||||
self.set_debug_mode(True)
|
||||
|
||||
def _walk_app_list(self, list_head):
|
||||
while list_head:
|
||||
@@ -195,7 +196,7 @@ class FlipperAppStateHelper:
|
||||
self.set_debug_mode(False)
|
||||
|
||||
def set_debug_mode(self, mode: bool) -> None:
|
||||
gdb.execute(f"set variable fap_loader_debug_active = {int(mode)}")
|
||||
gdb.execute(f"set variable furi_hal_debug_gdb_session_active = {int(mode)}")
|
||||
|
||||
|
||||
# Init additional 'fap-set-debug-elf-root' command and set up hooks
|
||||
|
||||
26
documentation/FuriHalDebuging.md
Normal file
26
documentation/FuriHalDebuging.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Furi HAL Debugging
|
||||
|
||||
Some Furi subsystem got additional debugging features that can be enabled by adding additional defines to firmware compilation.
|
||||
Usually they are used for low level tracing and profiling or signal redirection/duplication.
|
||||
|
||||
|
||||
## FuriHalOs
|
||||
|
||||
`--extra-define=FURI_HAL_OS_DEBUG` enables tick, tick suppression, idle and time flow.
|
||||
|
||||
There are 3 signals that will be exposed to external GPIO pins:
|
||||
|
||||
- `AWAKE` - `PA7` - High when system is busy with computations, low when sleeping. Can be used to track transitions to sleep mode.
|
||||
- `TICK` - `PA6` - Flipped on system tick, only flips when no tick suppression in progress. Can be used to track tick skew and abnormal task scheduling.
|
||||
- `SECOND` - `PA4` - Flipped each second. Can be used for tracing RT issue: time flow disturbance means system doesn't conforms Hard RT.
|
||||
|
||||
|
||||
|
||||
## FuriHalPower
|
||||
|
||||
`--extra-define=FURI_HAL_POWER_DEBUG` enables power subsystem mode transitions tracing.
|
||||
|
||||
There are 2 signals that will be exposed to external GPIO pins:
|
||||
|
||||
- `WFI` - `PB2` - Light sleep (wait for interrupt) used. Basically this is lightest and most non-breaking things power save mode. All function and debug should work correctly in this mode.
|
||||
- `STOP` - `PC3` - STOP mode used. Platform deep sleep mode. Extremely fragile mode where most of the silicon is disabled or in unusable state. Debugging MCU in this mode is nearly impossible.
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
For development:
|
||||
- Git
|
||||
- Python3
|
||||
- VSCode
|
||||
|
||||
## Clone the Repository
|
||||
@@ -16,15 +15,24 @@ You should clone with
|
||||
```shell
|
||||
$ git clone --recursive https://github.com/DarkFlippers/unleashed-firmware.git
|
||||
```
|
||||
## VSCode integration
|
||||
|
||||
`fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu.
|
||||
|
||||
# Build on Linux/macOS
|
||||
|
||||
Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
### Compile plugin and run it on connected flipper
|
||||
|
||||
```sh
|
||||
./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=applications_user/yourplugin
|
||||
```
|
||||
|
||||
### Compile everything for development
|
||||
|
||||
```sh
|
||||
./fbt
|
||||
./fbt FIRMWARE_APP_SET=debug_pack updater_package
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
@@ -35,7 +43,7 @@ Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
Check `dist/` for build outputs.
|
||||
|
||||
Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device.
|
||||
Use **`flipper-z-{target}-update-{suffix}.tgz`** to flash your device.
|
||||
|
||||
|
||||
# Build on Windows
|
||||
@@ -45,7 +53,7 @@ Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
### Compile everything for development
|
||||
|
||||
```sh
|
||||
.\fbt.cmd
|
||||
.\fbt.cmd FIRMWARE_APP_SET=debug_pack updater_package
|
||||
```
|
||||
|
||||
### Compile everything for release + get updater package to update from microSD card
|
||||
@@ -56,7 +64,7 @@ Check out `documentation/fbt.md` for details on building and flashing firmware.
|
||||
|
||||
Check `dist/` for build outputs.
|
||||
|
||||
Use **`flipper-z-{target}-full-{suffix}.dfu`** to flash your device.
|
||||
Use **`flipper-z-{target}-update-{suffix}.tgz`** to flash your device.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio
|
||||
- `--options optionfile.py` (default value `fbt_options.py`) - load a file with multiple configuration values
|
||||
- `--extra-int-apps=app1,app2,appN` - force listed apps to be built as internal with the `firmware` target
|
||||
- `--extra-ext-apps=app1,app2,appN` - force listed apps to be built as external with the `firmware_extapps` target
|
||||
- `--extra-define=A --extra-define=B=C ` - extra global defines that will be passed to the C/C++ compiler, can be specified multiple times
|
||||
- `--proxy-env=VAR1,VAR2` - additional environment variables to expose to subprocesses spawned by `fbt`. By default, `fbt` sanitizes the execution environment and doesn't forward all inherited environment variables. You can find the list of variables that are always forwarded in the `environ.scons` file.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,20.1,,
|
||||
Version,+,22.0,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@@ -901,6 +901,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*"
|
||||
Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t
|
||||
Function,+,furi_hal_debug_disable,void,
|
||||
Function,+,furi_hal_debug_enable,void,
|
||||
Function,+,furi_hal_debug_is_gdb_session_active,_Bool,
|
||||
Function,-,furi_hal_deinit_early,void,
|
||||
Function,-,furi_hal_flash_erase,void,uint8_t
|
||||
Function,-,furi_hal_flash_get_base,size_t,
|
||||
@@ -983,7 +984,6 @@ Function,-,furi_hal_os_init,void,
|
||||
Function,+,furi_hal_os_tick,void,
|
||||
Function,+,furi_hal_power_check_otg_status,void,
|
||||
Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*"
|
||||
Function,+,furi_hal_power_deep_sleep_available,_Bool,
|
||||
Function,+,furi_hal_power_disable_external_3_3v,void,
|
||||
Function,+,furi_hal_power_disable_otg,void,
|
||||
Function,+,furi_hal_power_enable_external_3_3v,void,
|
||||
@@ -1059,6 +1059,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
|
||||
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
|
||||
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
|
||||
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
|
||||
Function,+,furi_hal_rtc_sync_shadow,void,
|
||||
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
|
||||
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
|
||||
Function,-,furi_hal_speaker_deinit,void,
|
||||
@@ -2149,6 +2150,8 @@ Variable,+,gpio_ext_pd0,const GpioPin,
|
||||
Variable,+,gpio_ext_pe4,const GpioPin,
|
||||
Variable,+,gpio_i2c_power_scl,const GpioPin,
|
||||
Variable,+,gpio_i2c_power_sda,const GpioPin,
|
||||
Variable,+,gpio_ibutton,const GpioPin,
|
||||
Variable,+,gpio_periph_power,const GpioPin,
|
||||
Variable,+,gpio_pins,const GpioPinRecord[],
|
||||
Variable,+,gpio_pins_count,const size_t,
|
||||
Variable,+,gpio_sdcard_cd,const GpioPin,
|
||||
@@ -2157,11 +2160,13 @@ Variable,+,gpio_speaker,const GpioPin,
|
||||
Variable,+,gpio_spi_d_miso,const GpioPin,
|
||||
Variable,+,gpio_spi_d_mosi,const GpioPin,
|
||||
Variable,+,gpio_spi_d_sck,const GpioPin,
|
||||
Variable,+,gpio_swclk,const GpioPin,
|
||||
Variable,+,gpio_swdio,const GpioPin,
|
||||
Variable,+,gpio_usart_rx,const GpioPin,
|
||||
Variable,+,gpio_usart_tx,const GpioPin,
|
||||
Variable,+,gpio_usb_dm,const GpioPin,
|
||||
Variable,+,gpio_usb_dp,const GpioPin,
|
||||
Variable,+,ibutton_gpio,const GpioPin,
|
||||
Variable,+,gpio_vibro,const GpioPin,
|
||||
Variable,+,input_pins,const InputPin[],
|
||||
Variable,+,input_pins_count,const size_t,
|
||||
Variable,+,message_blink_set_color_blue,const NotificationMessage,
|
||||
@@ -2309,7 +2314,6 @@ Variable,+,message_red_255,const NotificationMessage,
|
||||
Variable,+,message_sound_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_on,const NotificationMessage,
|
||||
Variable,+,periph_power,const GpioPin,
|
||||
Variable,+,sequence_audiovisual_alert,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_10,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_100,const NotificationSequence,
|
||||
@@ -2364,4 +2368,3 @@ Variable,+,usb_cdc_single,FuriHalUsbInterface,
|
||||
Variable,+,usb_hid,FuriHalUsbInterface,
|
||||
Variable,+,usb_hid_u2f,FuriHalUsbInterface,
|
||||
Variable,+,usbd_devfs,const usbd_driver,
|
||||
Variable,+,vibro_gpio,const GpioPin,
|
||||
|
||||
|
@@ -6,8 +6,11 @@
|
||||
|
||||
#define TAG "FuriHalResources"
|
||||
|
||||
const GpioPin vibro_gpio = {.port = GPIOA, .pin = LL_GPIO_PIN_8};
|
||||
const GpioPin ibutton_gpio = {.port = GPIOB, .pin = LL_GPIO_PIN_14};
|
||||
const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13};
|
||||
const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14};
|
||||
|
||||
const GpioPin gpio_vibro = {.port = GPIOA, .pin = LL_GPIO_PIN_8};
|
||||
const GpioPin gpio_ibutton = {.port = GPIOB, .pin = LL_GPIO_PIN_14};
|
||||
|
||||
const GpioPin gpio_display_cs = {.port = GPIOC, .pin = LL_GPIO_PIN_11};
|
||||
const GpioPin gpio_display_rst_n = {.port = GPIOB, .pin = LL_GPIO_PIN_0};
|
||||
@@ -57,7 +60,7 @@ const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
||||
const GpioPin gpio_speaker = {.port = GPIOB, .pin = LL_GPIO_PIN_8};
|
||||
|
||||
const GpioPin periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3};
|
||||
const GpioPin gpio_periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3};
|
||||
|
||||
const GpioPin gpio_usb_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11};
|
||||
const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12};
|
||||
@@ -118,8 +121,8 @@ void furi_hal_resources_init_early() {
|
||||
furi_hal_resources_init_input_pins(GpioModeInput);
|
||||
|
||||
// SD Card stepdown control
|
||||
furi_hal_gpio_write(&periph_power, 1);
|
||||
furi_hal_gpio_init(&periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_periph_power, 1);
|
||||
furi_hal_gpio_init(&gpio_periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 1);
|
||||
@@ -165,6 +168,11 @@ void furi_hal_resources_init() {
|
||||
// Button pins
|
||||
furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall);
|
||||
|
||||
// Explicit pulls pins
|
||||
LL_PWR_EnablePUPDCfg();
|
||||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker
|
||||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 0);
|
||||
@@ -176,9 +184,7 @@ void furi_hal_resources_init() {
|
||||
furi_hal_gpio_init(&gpio_sdcard_cd, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_sdcard_cd, 0);
|
||||
|
||||
furi_hal_gpio_init(&vibro_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ibutton, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
|
||||
NVIC_EnableIRQ(EXTI0_IRQn);
|
||||
@@ -222,7 +228,7 @@ int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) {
|
||||
return 15;
|
||||
else if(gpio == &gpio_ext_pc0)
|
||||
return 16;
|
||||
else if(gpio == &ibutton_gpio)
|
||||
else if(gpio == &gpio_ibutton)
|
||||
return 17;
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -50,8 +50,11 @@ extern const size_t input_pins_count;
|
||||
extern const GpioPinRecord gpio_pins[];
|
||||
extern const size_t gpio_pins_count;
|
||||
|
||||
extern const GpioPin vibro_gpio;
|
||||
extern const GpioPin ibutton_gpio;
|
||||
extern const GpioPin gpio_swdio;
|
||||
extern const GpioPin gpio_swclk;
|
||||
|
||||
extern const GpioPin gpio_vibro;
|
||||
extern const GpioPin gpio_ibutton;
|
||||
|
||||
extern const GpioPin gpio_display_cs;
|
||||
extern const GpioPin gpio_display_rst_n;
|
||||
@@ -100,7 +103,7 @@ extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
extern const GpioPin gpio_speaker;
|
||||
|
||||
extern const GpioPin periph_power;
|
||||
extern const GpioPin gpio_periph_power;
|
||||
|
||||
extern const GpioPin gpio_usb_dm;
|
||||
extern const GpioPin gpio_usb_dp;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,20.1,,
|
||||
Version,+,22.0,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@@ -1106,6 +1106,7 @@ Function,+,furi_hal_crypto_verify_enclave,_Bool,"uint8_t*, uint8_t*"
|
||||
Function,+,furi_hal_crypto_verify_key,_Bool,uint8_t
|
||||
Function,+,furi_hal_debug_disable,void,
|
||||
Function,+,furi_hal_debug_enable,void,
|
||||
Function,+,furi_hal_debug_is_gdb_session_active,_Bool,
|
||||
Function,-,furi_hal_deinit_early,void,
|
||||
Function,-,furi_hal_flash_erase,void,uint8_t
|
||||
Function,-,furi_hal_flash_get_base,size_t,
|
||||
@@ -1238,7 +1239,6 @@ Function,-,furi_hal_os_init,void,
|
||||
Function,+,furi_hal_os_tick,void,
|
||||
Function,+,furi_hal_power_check_otg_status,void,
|
||||
Function,+,furi_hal_power_debug_get,void,"PropertyValueCallback, void*"
|
||||
Function,+,furi_hal_power_deep_sleep_available,_Bool,
|
||||
Function,+,furi_hal_power_disable_external_3_3v,void,
|
||||
Function,+,furi_hal_power_disable_otg,void,
|
||||
Function,+,furi_hal_power_enable_external_3_3v,void,
|
||||
@@ -1338,6 +1338,7 @@ Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
|
||||
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
|
||||
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
|
||||
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
|
||||
Function,+,furi_hal_rtc_sync_shadow,void,
|
||||
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
|
||||
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
|
||||
Function,-,furi_hal_speaker_deinit,void,
|
||||
@@ -4736,10 +4737,12 @@ Variable,+,gpio_ext_pc1,const GpioPin,
|
||||
Variable,+,gpio_ext_pc3,const GpioPin,
|
||||
Variable,+,gpio_i2c_power_scl,const GpioPin,
|
||||
Variable,+,gpio_i2c_power_sda,const GpioPin,
|
||||
Variable,+,gpio_ibutton,const GpioPin,
|
||||
Variable,+,gpio_infrared_rx,const GpioPin,
|
||||
Variable,+,gpio_infrared_tx,const GpioPin,
|
||||
Variable,+,gpio_nfc_cs,const GpioPin,
|
||||
Variable,+,gpio_nfc_irq_rfid_pull,const GpioPin,
|
||||
Variable,+,gpio_periph_power,const GpioPin,
|
||||
Variable,+,gpio_pins,const GpioPinRecord[],
|
||||
Variable,+,gpio_pins_count,const size_t,
|
||||
Variable,+,gpio_rf_sw_0,const GpioPin,
|
||||
@@ -4760,11 +4763,13 @@ Variable,+,gpio_spi_r_sck,const GpioPin,
|
||||
Variable,+,gpio_spi_r_sck_ext,const GpioPin,
|
||||
Variable,+,gpio_subghz_cs,const GpioPin,
|
||||
Variable,+,gpio_subghz_cs_ext,const GpioPin,
|
||||
Variable,+,gpio_swclk,const GpioPin,
|
||||
Variable,+,gpio_swdio,const GpioPin,
|
||||
Variable,+,gpio_usart_rx,const GpioPin,
|
||||
Variable,+,gpio_usart_tx,const GpioPin,
|
||||
Variable,+,gpio_usb_dm,const GpioPin,
|
||||
Variable,+,gpio_usb_dp,const GpioPin,
|
||||
Variable,+,ibutton_gpio,const GpioPin,
|
||||
Variable,+,gpio_vibro,const GpioPin,
|
||||
Variable,+,input_pins,const InputPin[],
|
||||
Variable,+,input_pins_count,const size_t,
|
||||
Variable,+,lfrfid_protocols,const ProtocolBase*[],
|
||||
@@ -4913,7 +4918,6 @@ Variable,+,message_red_255,const NotificationMessage,
|
||||
Variable,+,message_sound_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_off,const NotificationMessage,
|
||||
Variable,+,message_vibro_on,const NotificationMessage,
|
||||
Variable,+,periph_power,const GpioPin,
|
||||
Variable,+,sequence_audiovisual_alert,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_10,const NotificationSequence,
|
||||
Variable,+,sequence_blink_blue_100,const NotificationSequence,
|
||||
@@ -6920,4 +6924,3 @@ Variable,+,usb_cdc_single,FuriHalUsbInterface,
|
||||
Variable,+,usb_hid,FuriHalUsbInterface,
|
||||
Variable,+,usb_hid_u2f,FuriHalUsbInterface,
|
||||
Variable,+,usbd_devfs,const usbd_driver,
|
||||
Variable,+,vibro_gpio,const GpioPin,
|
||||
|
||||
|
@@ -58,12 +58,6 @@ void ble_glue_init() {
|
||||
ble_glue = malloc(sizeof(BleGlue));
|
||||
ble_glue->status = BleGlueStatusStartup;
|
||||
|
||||
// Configure the system Power Mode
|
||||
// Select HSI as system clock source after Wake Up from Stop mode
|
||||
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
|
||||
/* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
|
||||
#ifdef BLE_GLUE_DEBUG
|
||||
APPD_Init();
|
||||
#endif
|
||||
|
||||
@@ -63,6 +63,10 @@ void furi_hal_clock_init() {
|
||||
LL_RCC_HSI_Enable();
|
||||
while(!HS_CLOCK_IS_READY())
|
||||
;
|
||||
/* Select HSI as system clock source after Wake Up from Stop mode
|
||||
* Must be set before enabling CSS */
|
||||
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
|
||||
|
||||
LL_RCC_HSE_EnableCSS();
|
||||
|
||||
/* LSE and LSI1 configuration and activation */
|
||||
@@ -215,11 +219,14 @@ void furi_hal_clock_switch_to_hsi() {
|
||||
void furi_hal_clock_switch_to_pll() {
|
||||
LL_RCC_HSE_Enable();
|
||||
LL_RCC_PLL_Enable();
|
||||
LL_RCC_PLLSAI1_Enable();
|
||||
|
||||
while(!LL_RCC_HSE_IsReady())
|
||||
;
|
||||
while(!LL_RCC_PLL_IsReady())
|
||||
;
|
||||
while(!LL_RCC_PLLSAI1_IsReady())
|
||||
;
|
||||
|
||||
LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
|
||||
|
||||
@@ -296,4 +303,4 @@ void furi_hal_clock_mco_disable() {
|
||||
LL_RCC_MSI_Disable();
|
||||
while(LL_RCC_MSI_IsReady() != 0)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,26 @@
|
||||
#include <stm32wbxx_ll_exti.h>
|
||||
#include <stm32wbxx_ll_system.h>
|
||||
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
volatile bool furi_hal_debug_gdb_session_active = false;
|
||||
|
||||
void furi_hal_debug_enable() {
|
||||
// Low power mode debug
|
||||
LL_DBGMCU_EnableDBGSleepMode();
|
||||
LL_DBGMCU_EnableDBGStopMode();
|
||||
LL_DBGMCU_EnableDBGStandbyMode();
|
||||
LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_48);
|
||||
// SWD GPIO
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_swdio,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullUp,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn0JTMS_SWDIO);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_swclk, GpioModeAltFunctionPushPull, GpioPullDown, GpioSpeedLow, GpioAltFn0JTCK_SWCLK);
|
||||
}
|
||||
|
||||
void furi_hal_debug_disable() {
|
||||
@@ -17,4 +31,11 @@ void furi_hal_debug_disable() {
|
||||
LL_DBGMCU_DisableDBGStopMode();
|
||||
LL_DBGMCU_DisableDBGStandbyMode();
|
||||
LL_EXTI_DisableIT_32_63(LL_EXTI_LINE_48);
|
||||
// SWD GPIO
|
||||
furi_hal_gpio_init_simple(&gpio_swdio, GpioModeAnalog);
|
||||
furi_hal_gpio_init_simple(&gpio_swclk, GpioModeAnalog);
|
||||
}
|
||||
|
||||
bool furi_hal_debug_is_gdb_session_active() {
|
||||
return furi_hal_debug_gdb_session_active;
|
||||
}
|
||||
@@ -93,15 +93,15 @@ void furi_hal_ibutton_emulate_stop() {
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_configure() {
|
||||
furi_hal_gpio_write(&ibutton_gpio, true);
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_ibutton, true);
|
||||
furi_hal_gpio_init(&gpio_ibutton, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_reset() {
|
||||
furi_hal_gpio_write(&ibutton_gpio, true);
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_ibutton, true);
|
||||
furi_hal_gpio_init(&gpio_ibutton, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
void furi_hal_ibutton_pin_write(const bool state) {
|
||||
furi_hal_gpio_write(&ibutton_gpio, state);
|
||||
furi_hal_gpio_write(&gpio_ibutton, state);
|
||||
}
|
||||
|
||||
@@ -570,9 +570,9 @@ static void furi_hal_infrared_async_tx_free_resources(void) {
|
||||
(furi_hal_infrared_state == InfraredStateAsyncTxStopped));
|
||||
|
||||
if(infrared_external_output) {
|
||||
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
} else {
|
||||
furi_hal_gpio_init(&gpio_infrared_tx, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
}
|
||||
furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL);
|
||||
furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL);
|
||||
|
||||
@@ -28,11 +28,24 @@
|
||||
// Arbitrary (but small) number for better tick consistency
|
||||
#define FURI_HAL_OS_EXTRA_CNT 3
|
||||
|
||||
#ifndef FURI_HAL_OS_DEBUG_AWAKE_GPIO
|
||||
#define FURI_HAL_OS_DEBUG_AWAKE_GPIO (&gpio_ext_pa7)
|
||||
#endif
|
||||
|
||||
#ifndef FURI_HAL_OS_DEBUG_TICK_GPIO
|
||||
#define FURI_HAL_OS_DEBUG_TICK_GPIO (&gpio_ext_pa6)
|
||||
#endif
|
||||
|
||||
#ifndef FURI_HAL_OS_DEBUG_SECOND_GPIO
|
||||
#define FURI_HAL_OS_DEBUG_SECOND_GPIO (&gpio_ext_pa4)
|
||||
#endif
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
#include <stm32wbxx_ll_gpio.h>
|
||||
|
||||
void furi_hal_os_timer_callback() {
|
||||
furi_hal_gpio_write(&gpio_ext_pa4, !furi_hal_gpio_read(&gpio_ext_pa4));
|
||||
furi_hal_gpio_write(
|
||||
FURI_HAL_OS_DEBUG_SECOND_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_SECOND_GPIO));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,9 +57,11 @@ void furi_hal_os_init() {
|
||||
furi_hal_idle_timer_init();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_AWAKE_GPIO, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_TICK_GPIO, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(FURI_HAL_OS_DEBUG_SECOND_GPIO, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1);
|
||||
|
||||
FuriTimer* second_timer =
|
||||
furi_timer_alloc(furi_hal_os_timer_callback, FuriTimerTypePeriodic, NULL);
|
||||
furi_timer_start(second_timer, FURI_HAL_OS_TICK_HZ);
|
||||
@@ -58,7 +73,8 @@ void furi_hal_os_init() {
|
||||
void furi_hal_os_tick() {
|
||||
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pa6, !furi_hal_gpio_read(&gpio_ext_pa6));
|
||||
furi_hal_gpio_write(
|
||||
FURI_HAL_OS_DEBUG_TICK_GPIO, !furi_hal_gpio_read(FURI_HAL_OS_DEBUG_TICK_GPIO));
|
||||
#endif
|
||||
xPortSysTickHandler();
|
||||
}
|
||||
@@ -121,14 +137,14 @@ static inline uint32_t furi_hal_os_sleep(TickType_t expected_idle_ticks) {
|
||||
furi_hal_idle_timer_start(FURI_HAL_OS_TICKS_TO_IDLE_CNT(expected_idle_ticks));
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pa7, 0);
|
||||
furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 0);
|
||||
#endif
|
||||
|
||||
// Go to sleep mode
|
||||
furi_hal_power_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pa7, 1);
|
||||
furi_hal_gpio_write(FURI_HAL_OS_DEBUG_AWAKE_GPIO, 1);
|
||||
#endif
|
||||
|
||||
// Calculate how much time we spent in the sleep
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <furi_hal_vibro.h>
|
||||
#include <furi_hal_resources.h>
|
||||
#include <furi_hal_uart.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_debug.h>
|
||||
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_pwr.h>
|
||||
@@ -19,15 +21,16 @@
|
||||
|
||||
#define TAG "FuriHalPower"
|
||||
|
||||
#ifdef FURI_HAL_POWER_DEEP_SLEEP_ENABLED
|
||||
#define FURI_HAL_POWER_DEEP_INSOMNIA 0
|
||||
#else
|
||||
#define FURI_HAL_POWER_DEEP_INSOMNIA 1
|
||||
#ifndef FURI_HAL_POWER_DEBUG_WFI_GPIO
|
||||
#define FURI_HAL_POWER_DEBUG_WFI_GPIO (&gpio_ext_pb2)
|
||||
#endif
|
||||
|
||||
#ifndef FURI_HAL_POWER_DEBUG_STOP_GPIO
|
||||
#define FURI_HAL_POWER_DEBUG_STOP_GPIO (&gpio_ext_pc3)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
volatile uint8_t insomnia;
|
||||
volatile uint8_t deep_insomnia;
|
||||
volatile uint8_t suppress_charge;
|
||||
|
||||
uint8_t gauge_initialized;
|
||||
@@ -36,7 +39,6 @@ typedef struct {
|
||||
|
||||
static volatile FuriHalPower furi_hal_power = {
|
||||
.insomnia = 0,
|
||||
.deep_insomnia = FURI_HAL_POWER_DEEP_INSOMNIA,
|
||||
.suppress_charge = 0,
|
||||
};
|
||||
|
||||
@@ -79,19 +81,23 @@ const ParamCEDV cedv = {
|
||||
};
|
||||
|
||||
void furi_hal_power_init() {
|
||||
#ifdef FURI_HAL_POWER_DEBUG
|
||||
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_WFI_GPIO, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(FURI_HAL_POWER_DEBUG_STOP_GPIO, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0);
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0);
|
||||
#endif
|
||||
|
||||
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
|
||||
LL_PWR_SMPS_SetMode(LL_PWR_SMPS_STEP_DOWN);
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
|
||||
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
|
||||
bq27220_init(&furi_hal_i2c_handle_power, &cedv);
|
||||
bq25896_init(&furi_hal_i2c_handle_power);
|
||||
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pb2, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pc3, GpioModeOutputPushPull);
|
||||
#endif
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
@@ -140,11 +146,12 @@ bool furi_hal_power_sleep_available() {
|
||||
return furi_hal_power.insomnia == 0;
|
||||
}
|
||||
|
||||
bool furi_hal_power_deep_sleep_available() {
|
||||
return furi_hal_bt_is_alive() && furi_hal_power.deep_insomnia == 0;
|
||||
static inline bool furi_hal_power_deep_sleep_available() {
|
||||
return furi_hal_bt_is_alive() && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagLegacySleep) &&
|
||||
!furi_hal_debug_is_gdb_session_active();
|
||||
}
|
||||
|
||||
void furi_hal_power_light_sleep() {
|
||||
static inline void furi_hal_power_light_sleep() {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
@@ -152,17 +159,15 @@ static inline void furi_hal_power_suspend_aux_periphs() {
|
||||
// Disable USART
|
||||
furi_hal_uart_suspend(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_suspend(FuriHalUartIdLPUART1);
|
||||
// TODO: Disable USB
|
||||
}
|
||||
|
||||
static inline void furi_hal_power_resume_aux_periphs() {
|
||||
// Re-enable USART
|
||||
furi_hal_uart_resume(FuriHalUartIdUSART1);
|
||||
furi_hal_uart_resume(FuriHalUartIdLPUART1);
|
||||
// TODO: Re-enable USB
|
||||
}
|
||||
|
||||
void furi_hal_power_deep_sleep() {
|
||||
static inline void furi_hal_power_deep_sleep() {
|
||||
furi_hal_power_suspend_aux_periphs();
|
||||
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID))
|
||||
@@ -187,8 +192,6 @@ void furi_hal_power_deep_sleep() {
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
// Prepare deep sleep
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
|
||||
LL_LPM_EnableDeepSleep();
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
@@ -200,13 +203,6 @@ void furi_hal_power_deep_sleep() {
|
||||
|
||||
LL_LPM_EnableSleep();
|
||||
|
||||
// Make sure that values differ to prevent disaster on wfi
|
||||
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0);
|
||||
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
|
||||
|
||||
LL_PWR_ClearFlag_C1STOP_C1STB();
|
||||
LL_PWR_ClearFlag_C2STOP_C2STB();
|
||||
|
||||
/* Release ENTRY_STOP_MODE semaphore */
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
|
||||
|
||||
@@ -220,28 +216,25 @@ void furi_hal_power_deep_sleep() {
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||
|
||||
furi_hal_power_resume_aux_periphs();
|
||||
furi_hal_rtc_sync_shadow();
|
||||
}
|
||||
|
||||
void furi_hal_power_sleep() {
|
||||
if(furi_hal_power_deep_sleep_available()) {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pc3, 1);
|
||||
#ifdef FURI_HAL_POWER_DEBUG
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 1);
|
||||
#endif
|
||||
|
||||
furi_hal_power_deep_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pc3, 0);
|
||||
#ifdef FURI_HAL_POWER_DEBUG
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_STOP_GPIO, 0);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pb2, 1);
|
||||
#ifdef FURI_HAL_POWER_DEBUG
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 1);
|
||||
#endif
|
||||
|
||||
furi_hal_power_light_sleep();
|
||||
|
||||
#ifdef FURI_HAL_OS_DEBUG
|
||||
furi_hal_gpio_write(&gpio_ext_pb2, 0);
|
||||
#ifdef FURI_HAL_POWER_DEBUG
|
||||
furi_hal_gpio_write(FURI_HAL_POWER_DEBUG_WFI_GPIO, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -440,11 +433,11 @@ float furi_hal_power_get_usb_voltage() {
|
||||
}
|
||||
|
||||
void furi_hal_power_enable_external_3_3v() {
|
||||
furi_hal_gpio_write(&periph_power, 1);
|
||||
furi_hal_gpio_write(&gpio_periph_power, 1);
|
||||
}
|
||||
|
||||
void furi_hal_power_disable_external_3_3v() {
|
||||
furi_hal_gpio_write(&periph_power, 0);
|
||||
furi_hal_gpio_write(&gpio_periph_power, 0);
|
||||
}
|
||||
|
||||
void furi_hal_power_suppress_charge_enter() {
|
||||
|
||||
@@ -9,19 +9,35 @@
|
||||
|
||||
#define TAG "FuriHalRandom"
|
||||
|
||||
static uint32_t furi_hal_random_read_rng() {
|
||||
while(LL_RNG_IsActiveFlag_CECS(RNG) && LL_RNG_IsActiveFlag_SECS(RNG) &&
|
||||
!LL_RNG_IsActiveFlag_DRDY(RNG)) {
|
||||
/* Error handling as described in RM0434, pg. 582-583 */
|
||||
if(LL_RNG_IsActiveFlag_CECS(RNG)) {
|
||||
/* Clock error occurred */
|
||||
LL_RNG_ClearFlag_CEIS(RNG);
|
||||
}
|
||||
|
||||
if(LL_RNG_IsActiveFlag_SECS(RNG)) {
|
||||
/* Noise source error occurred */
|
||||
LL_RNG_ClearFlag_SEIS(RNG);
|
||||
|
||||
for(uint32_t i = 0; i < 12; ++i) {
|
||||
const volatile uint32_t discard = LL_RNG_ReadRandData32(RNG);
|
||||
UNUSED(discard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return LL_RNG_ReadRandData32(RNG);
|
||||
}
|
||||
|
||||
uint32_t furi_hal_random_get() {
|
||||
while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID))
|
||||
;
|
||||
LL_RNG_Enable(RNG);
|
||||
|
||||
while(!LL_RNG_IsActiveFlag_DRDY(RNG))
|
||||
;
|
||||
|
||||
if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) {
|
||||
furi_crash("TRNG error");
|
||||
}
|
||||
|
||||
uint32_t random_val = LL_RNG_ReadRandData32(RNG);
|
||||
const uint32_t random_val = furi_hal_random_read_rng();
|
||||
|
||||
LL_RNG_Disable(RNG);
|
||||
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0);
|
||||
@@ -35,15 +51,7 @@ void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) {
|
||||
LL_RNG_Enable(RNG);
|
||||
|
||||
for(uint32_t i = 0; i < len; i += 4) {
|
||||
while(!LL_RNG_IsActiveFlag_DRDY(RNG))
|
||||
;
|
||||
|
||||
if((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) {
|
||||
furi_crash("TRNG error");
|
||||
}
|
||||
|
||||
uint32_t random_val = LL_RNG_ReadRandData32(RNG);
|
||||
|
||||
const uint32_t random_val = furi_hal_random_read_rng();
|
||||
uint8_t len_cur = ((i + 4) < len) ? (4) : (len - i);
|
||||
memcpy(&buf[i], &random_val, len_cur);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
|
||||
#define TAG "FuriHalResources"
|
||||
|
||||
const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
const GpioPin gpio_swdio = {.port = GPIOA, .pin = LL_GPIO_PIN_13};
|
||||
const GpioPin gpio_swclk = {.port = GPIOA, .pin = LL_GPIO_PIN_14};
|
||||
|
||||
const GpioPin gpio_vibro = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin gpio_ibutton = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
|
||||
const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin};
|
||||
const GpioPin gpio_cc1101_g0_ext = {.port = GPIOB, .pin = LL_GPIO_PIN_2};
|
||||
@@ -64,7 +67,7 @@ const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9};
|
||||
|
||||
const GpioPin gpio_speaker = {.port = GPIOB, .pin = LL_GPIO_PIN_8};
|
||||
|
||||
const GpioPin periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3};
|
||||
const GpioPin gpio_periph_power = {.port = GPIOA, .pin = LL_GPIO_PIN_3};
|
||||
|
||||
const GpioPin gpio_usb_dm = {.port = GPIOA, .pin = LL_GPIO_PIN_11};
|
||||
const GpioPin gpio_usb_dp = {.port = GPIOA, .pin = LL_GPIO_PIN_12};
|
||||
@@ -111,8 +114,8 @@ void furi_hal_resources_init_early() {
|
||||
furi_hal_resources_init_input_pins(GpioModeInput);
|
||||
|
||||
// SD Card stepdown control
|
||||
furi_hal_gpio_write(&periph_power, 1);
|
||||
furi_hal_gpio_init(&periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_periph_power, 1);
|
||||
furi_hal_gpio_init(&gpio_periph_power, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 1);
|
||||
@@ -158,6 +161,12 @@ void furi_hal_resources_init() {
|
||||
// Button pins
|
||||
furi_hal_resources_init_input_pins(GpioModeInterruptRiseFall);
|
||||
|
||||
// Explicit, surviving reset, pulls
|
||||
LL_PWR_EnablePUPDCfg();
|
||||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_9); // gpio_infrared_tx
|
||||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_B, LL_PWR_GPIO_BIT_8); // gpio_speaker
|
||||
LL_PWR_EnableGPIOPullDown(LL_PWR_GPIO_A, LL_PWR_GPIO_BIT_8); // gpio_vibro
|
||||
|
||||
// Display pins
|
||||
furi_hal_gpio_init(&gpio_display_rst_n, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_display_rst_n, 0);
|
||||
@@ -169,9 +178,7 @@ void furi_hal_resources_init() {
|
||||
furi_hal_gpio_init(&gpio_sdcard_cd, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_sdcard_cd, 0);
|
||||
|
||||
furi_hal_gpio_init(&vibro_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ibutton, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeInterruptRise, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
@@ -218,7 +225,7 @@ int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) {
|
||||
return 15;
|
||||
else if(gpio == &gpio_ext_pc0)
|
||||
return 16;
|
||||
else if(gpio == &ibutton_gpio)
|
||||
else if(gpio == &gpio_ibutton)
|
||||
return 17;
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -50,8 +50,11 @@ extern const size_t input_pins_count;
|
||||
extern const GpioPinRecord gpio_pins[];
|
||||
extern const size_t gpio_pins_count;
|
||||
|
||||
extern const GpioPin vibro_gpio;
|
||||
extern const GpioPin ibutton_gpio;
|
||||
extern const GpioPin gpio_swdio;
|
||||
extern const GpioPin gpio_swclk;
|
||||
|
||||
extern const GpioPin gpio_vibro;
|
||||
extern const GpioPin gpio_ibutton;
|
||||
|
||||
extern const GpioPin gpio_cc1101_g0;
|
||||
extern const GpioPin gpio_cc1101_g0_ext;
|
||||
@@ -107,7 +110,7 @@ extern const GpioPin gpio_i2c_power_scl;
|
||||
|
||||
extern const GpioPin gpio_speaker;
|
||||
|
||||
extern const GpioPin periph_power;
|
||||
extern const GpioPin gpio_periph_power;
|
||||
|
||||
extern const GpioPin gpio_usb_dm;
|
||||
extern const GpioPin gpio_usb_dp;
|
||||
|
||||
@@ -165,6 +165,14 @@ void furi_hal_rtc_init() {
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_rtc_sync_shadow() {
|
||||
if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) {
|
||||
LL_RTC_ClearFlag_RS(RTC);
|
||||
while(!LL_RTC_IsActiveFlag_RS(RTC)) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg) {
|
||||
return LL_RTC_BAK_GetRegister(RTC, reg);
|
||||
}
|
||||
@@ -312,12 +320,7 @@ void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
|
||||
/* Exit Initialization mode */
|
||||
LL_RTC_DisableInitMode(RTC);
|
||||
|
||||
/* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */
|
||||
if(!LL_RTC_IsShadowRegBypassEnabled(RTC)) {
|
||||
LL_RTC_ClearFlag_RS(RTC);
|
||||
while(!LL_RTC_IsActiveFlag_RS(RTC)) {
|
||||
};
|
||||
}
|
||||
furi_hal_rtc_sync_shadow();
|
||||
|
||||
/* Enable write protection */
|
||||
LL_RTC_EnableWriteProtection(RTC);
|
||||
|
||||
@@ -52,7 +52,7 @@ void furi_hal_speaker_release() {
|
||||
furi_check(furi_hal_speaker_is_mine());
|
||||
|
||||
furi_hal_speaker_stop();
|
||||
furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
|
||||
furi_hal_power_insomnia_exit();
|
||||
|
||||
furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk);
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
#define TAG "FuriHalVibro"
|
||||
|
||||
void furi_hal_vibro_init() {
|
||||
furi_hal_gpio_init(&vibro_gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&vibro_gpio, false);
|
||||
furi_hal_gpio_init(&gpio_vibro, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_vibro, false);
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_vibro_on(bool value) {
|
||||
furi_hal_gpio_write(&vibro_gpio, value);
|
||||
furi_hal_gpio_write(&gpio_vibro, value);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ void furi_hal_debug_enable();
|
||||
/** Disable MCU debug */
|
||||
void furi_hal_debug_disable();
|
||||
|
||||
/** Check if GDB debug session is active */
|
||||
bool furi_hal_debug_is_gdb_session_active();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -58,12 +58,6 @@ void furi_hal_power_insomnia_exit();
|
||||
*/
|
||||
bool furi_hal_power_sleep_available();
|
||||
|
||||
/** Check if deep sleep availble
|
||||
*
|
||||
* @return true if available
|
||||
*/
|
||||
bool furi_hal_power_deep_sleep_available();
|
||||
|
||||
/** Go to sleep
|
||||
*/
|
||||
void furi_hal_power_sleep();
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef enum {
|
||||
FuriHalRtcFlagLock = (1 << 2),
|
||||
FuriHalRtcFlagC2Update = (1 << 3),
|
||||
FuriHalRtcFlagHandOrient = (1 << 4),
|
||||
FuriHalRtcFlagLegacySleep = (1 << 5),
|
||||
} FuriHalRtcFlag;
|
||||
|
||||
typedef enum {
|
||||
@@ -85,6 +86,9 @@ void furi_hal_rtc_deinit_early();
|
||||
/** Initialize RTC subsystem */
|
||||
void furi_hal_rtc_init();
|
||||
|
||||
/** Force sync shadow registers */
|
||||
void furi_hal_rtc_sync_shadow();
|
||||
|
||||
/** Get RTC register content
|
||||
*
|
||||
* @param[in] reg The register identifier
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <furi_hal_console.h>
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_rtc.h>
|
||||
#include <furi_hal_debug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
@@ -117,6 +118,8 @@ FURI_NORETURN void __furi_crash() {
|
||||
if(debug) {
|
||||
furi_hal_console_puts("\r\nSystem halted. Connect debugger for more info\r\n");
|
||||
furi_hal_console_puts("\033[0m\r\n");
|
||||
furi_hal_debug_enable();
|
||||
|
||||
RESTORE_REGISTERS_AND_HALT_MCU(true);
|
||||
} else {
|
||||
furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message);
|
||||
|
||||
@@ -24,6 +24,10 @@ extern "C" {
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(a) ({ (a) < 0 ? -(a) : (a); })
|
||||
#endif
|
||||
|
||||
#ifndef ROUND_UP_TO
|
||||
#define ROUND_UP_TO(a, b) \
|
||||
({ \
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user