mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge branch 'ul-dev' into xfw-dev
This commit is contained in:
@@ -17,8 +17,8 @@
|
||||
|
||||
#include <iBtn_Fuzzer_icons.h>
|
||||
|
||||
#include <lib/one_wire/ibutton/ibutton_worker.h>
|
||||
#include <lib/one_wire/ibutton/ibutton_key.h>
|
||||
#include <lib/ibutton/ibutton_worker.h>
|
||||
#include <lib/ibutton/ibutton_key.h>
|
||||
|
||||
#define TAG "iBtnFuzzer"
|
||||
|
||||
|
||||
89
applications/external/minesweeper/minesweeper.c
vendored
89
applications/external/minesweeper/minesweeper.c
vendored
@@ -45,9 +45,11 @@ typedef enum {
|
||||
typedef enum { FieldEmpty, FieldMine } Field;
|
||||
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
DialogsApp* dialogs;
|
||||
NotificationApp* notifications;
|
||||
Field minefield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT];
|
||||
TileType playfield[PLAYFIELD_WIDTH][PLAYFIELD_HEIGHT];
|
||||
FuriTimer* timer;
|
||||
int cursor_x;
|
||||
int cursor_y;
|
||||
int mines_left;
|
||||
@@ -55,16 +57,8 @@ typedef struct {
|
||||
int flags_set;
|
||||
bool game_started;
|
||||
uint32_t game_started_tick;
|
||||
FuriMutex* mutex;
|
||||
} Minesweeper;
|
||||
|
||||
static void timer_callback(void* ctx) {
|
||||
UNUSED(ctx);
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(notification, &sequence_reset_vibro);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
@@ -177,7 +171,7 @@ static void setup_playfield(Minesweeper* minesweeper_state) {
|
||||
int rand_y = rand() % PLAYFIELD_HEIGHT;
|
||||
// make sure first guess isn't a mine
|
||||
if(minesweeper_state->minefield[rand_x][rand_y] == FieldEmpty &&
|
||||
(minesweeper_state->cursor_x != rand_x && minesweeper_state->cursor_y != rand_y)) {
|
||||
(minesweeper_state->cursor_x != rand_x || minesweeper_state->cursor_y != rand_y)) {
|
||||
minesweeper_state->minefield[rand_x][rand_y] = FieldMine;
|
||||
mines_left--;
|
||||
}
|
||||
@@ -206,37 +200,25 @@ static void place_flag(Minesweeper* minesweeper_state) {
|
||||
|
||||
static bool game_lost(Minesweeper* minesweeper_state) {
|
||||
// returns true if the player wants to restart, otherwise false
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
const char* header_text = "Game Over";
|
||||
const char* message_text = "You hit a mine!";
|
||||
|
||||
dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_header(message, "Game Over", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(message, "You hit a mine!", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_buttons(message, NULL, "Play again", NULL);
|
||||
|
||||
dialog_message_set_icon(message, NULL, 0, 10);
|
||||
|
||||
// Set cursor to initial position
|
||||
minesweeper_state->cursor_x = 0;
|
||||
minesweeper_state->cursor_y = 0;
|
||||
|
||||
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(notifications, &sequence_set_vibro_on);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_timer_start(minesweeper_state->timer, (uint32_t)furi_kernel_get_tick_frequency() * 0.2);
|
||||
notification_message(minesweeper_state->notifications, &sequence_single_vibro);
|
||||
|
||||
DialogMessageButton choice = dialog_message_show(dialogs, message);
|
||||
DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
return choice == DialogMessageButtonCenter;
|
||||
}
|
||||
|
||||
static bool game_won(Minesweeper* minesweeper_state) {
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
FuriString* tempStr;
|
||||
tempStr = furi_string_alloc();
|
||||
|
||||
@@ -254,12 +236,10 @@ static bool game_won(Minesweeper* minesweeper_state) {
|
||||
dialog_message_set_text(
|
||||
message, furi_string_get_cstr(tempStr), 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_buttons(message, NULL, "Play again", NULL);
|
||||
dialog_message_set_icon(message, NULL, 72, 17);
|
||||
|
||||
DialogMessageButton choice = dialog_message_show(dialogs, message);
|
||||
DialogMessageButton choice = dialog_message_show(minesweeper_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_string_free(tempStr);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
return choice == DialogMessageButtonCenter;
|
||||
}
|
||||
|
||||
@@ -370,22 +350,6 @@ static void minesweeper_state_init(Minesweeper* const minesweeper_state) {
|
||||
|
||||
int32_t minesweeper_app(void* p) {
|
||||
UNUSED(p);
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
const char* header_text = "Minesweeper";
|
||||
const char* message_text = "Hold OK pressed to toggle flags.\ngithub.com/panki27";
|
||||
|
||||
dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_buttons(message, NULL, "Play", NULL);
|
||||
|
||||
dialog_message_set_icon(message, NULL, 0, 10);
|
||||
|
||||
dialog_message_show(dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
|
||||
|
||||
Minesweeper* minesweeper_state = malloc(sizeof(Minesweeper));
|
||||
@@ -400,12 +364,28 @@ int32_t minesweeper_app(void* p) {
|
||||
}
|
||||
// BEGIN IMPLEMENTATION
|
||||
|
||||
minesweeper_state->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
minesweeper_state->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
|
||||
dialog_message_set_header(message, "Minesweeper", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Hold OK pressed to toggle flags.\ngithub.com/panki27",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
dialog_message_set_buttons(message, NULL, "Play", NULL);
|
||||
|
||||
dialog_message_show(minesweeper_state->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
|
||||
// Set system callbacks
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, render_callback, minesweeper_state);
|
||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||
minesweeper_state->timer =
|
||||
furi_timer_alloc(timer_callback, FuriTimerTypeOnce, minesweeper_state);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
@@ -414,35 +394,42 @@ int32_t minesweeper_app(void* p) {
|
||||
PluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
if(event_status == FuriStatusOk) {
|
||||
// press events
|
||||
if(event.type == EventTypeKey) {
|
||||
if(event.input.type == InputTypeShort) {
|
||||
switch(event.input.key) {
|
||||
case InputKeyUp:
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
minesweeper_state->cursor_y--;
|
||||
if(minesweeper_state->cursor_y < 0) {
|
||||
minesweeper_state->cursor_y = PLAYFIELD_HEIGHT - 1;
|
||||
}
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
minesweeper_state->cursor_y++;
|
||||
if(minesweeper_state->cursor_y >= PLAYFIELD_HEIGHT) {
|
||||
minesweeper_state->cursor_y = 0;
|
||||
}
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
minesweeper_state->cursor_x++;
|
||||
if(minesweeper_state->cursor_x >= PLAYFIELD_WIDTH) {
|
||||
minesweeper_state->cursor_x = 0;
|
||||
}
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
minesweeper_state->cursor_x--;
|
||||
if(minesweeper_state->cursor_x < 0) {
|
||||
minesweeper_state->cursor_x = PLAYFIELD_WIDTH - 1;
|
||||
}
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(!minesweeper_state->game_started) {
|
||||
@@ -492,7 +479,9 @@ int32_t minesweeper_app(void* p) {
|
||||
break;
|
||||
case InputKeyOk:
|
||||
FURI_LOG_D("Minesweeper", "Toggling flag");
|
||||
furi_mutex_acquire(minesweeper_state->mutex, FuriWaitForever);
|
||||
place_flag(minesweeper_state);
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
processing = false;
|
||||
@@ -504,15 +493,15 @@ int32_t minesweeper_app(void* p) {
|
||||
}
|
||||
}
|
||||
view_port_update(view_port);
|
||||
furi_mutex_release(minesweeper_state->mutex);
|
||||
}
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_mutex_free(minesweeper_state->mutex);
|
||||
furi_timer_free(minesweeper_state->timer);
|
||||
free(minesweeper_state);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#define MAGIC_CMD_WUPA (0x40)
|
||||
#define MAGIC_CMD_WIPE (0x41)
|
||||
#define MAGIC_CMD_READ (0x43)
|
||||
#define MAGIC_CMD_WRITE (0x43)
|
||||
#define MAGIC_CMD_ACCESS (0x43)
|
||||
|
||||
#define MAGIC_MIFARE_READ_CMD (0x30)
|
||||
#define MAGIC_MIFARE_WRITE_CMD (0xA0)
|
||||
@@ -70,7 +69,7 @@ bool magic_data_access_cmd() {
|
||||
FuriHalNfcReturn ret = 0;
|
||||
|
||||
do {
|
||||
tx_data[0] = MAGIC_CMD_WRITE;
|
||||
tx_data[0] = MAGIC_CMD_ACCESS;
|
||||
ret = furi_hal_nfc_ll_txrx_bits(
|
||||
tx_data,
|
||||
8,
|
||||
|
||||
@@ -88,15 +88,17 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) {
|
||||
card_found_notified = true;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
|
||||
if(!magic_wupa()) {
|
||||
FURI_LOG_E(TAG, "Not Magic card");
|
||||
FURI_LOG_E(TAG, "No card response to WUPA (not a magic card)");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
break;
|
||||
}
|
||||
furi_hal_nfc_sleep();
|
||||
}
|
||||
if(magic_wupa()) {
|
||||
if(!magic_data_access_cmd()) {
|
||||
FURI_LOG_E(TAG, "Not Magic card");
|
||||
FURI_LOG_E(TAG, "No card response to data access command (not a magic card)");
|
||||
nfc_magic_worker->callback(
|
||||
NfcMagicWorkerEventWrongCard, nfc_magic_worker->context);
|
||||
break;
|
||||
|
||||
4
applications/external/wav_player/README.md
vendored
4
applications/external/wav_player/README.md
vendored
@@ -1,4 +1,6 @@
|
||||
# WAV player
|
||||
A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper.
|
||||
A Flipper Zero application for playing wav files. My fork adds support for correct playback speed (for files with different sample rates) and for mono files (original wav player only plays stereo). ~~You still need to convert your file to unsigned 8-bit PCM format for it to played correctly on flipper~~. Now supports 16-bit (ordinary) wav files too, both mono and stereo!
|
||||
|
||||
Original app by https://github.com/DrZlo13.
|
||||
|
||||
Also outputs audio on `PA6` - `3(A6)` pin
|
||||
|
||||
125
applications/external/wav_player/wav_player.c
vendored
125
applications/external/wav_player/wav_player.c
vendored
@@ -127,7 +127,7 @@ static void app_free(WavPlayerApp* app) {
|
||||
|
||||
// TODO: that works only with 8-bit 2ch audio
|
||||
static bool fill_data(WavPlayerApp* app, size_t index) {
|
||||
if(app->num_channels == 1) {
|
||||
if(app->num_channels == 1 && app->bits_per_sample == 8) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count_half);
|
||||
|
||||
@@ -166,7 +166,108 @@ static bool fill_data(WavPlayerApp* app, size_t index) {
|
||||
return count != app->samples_count_half;
|
||||
}
|
||||
|
||||
if(app->num_channels == 2) {
|
||||
if(app->num_channels == 1 && app->bits_per_sample == 16) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
for(size_t i = count; i < app->samples_count; i++) {
|
||||
//app->tmp_buffer[i] = 0;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < app->samples_count; i += 2) {
|
||||
int16_t int_16 =
|
||||
(((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
|
||||
|
||||
float data = ((float)int_16 / 256.0 + 127.0);
|
||||
data -= UINT8_MAX / 2; // to signed
|
||||
data /= UINT8_MAX / 2; // scale -1..1
|
||||
|
||||
data *= app->volume; // volume
|
||||
data = tanhf(data); // hyperbolic tangent limiter
|
||||
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i / 2] = data;
|
||||
}
|
||||
|
||||
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
|
||||
|
||||
return count != app->samples_count;
|
||||
}
|
||||
|
||||
if(app->num_channels == 2 && app->bits_per_sample == 16) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
for(size_t i = 0; i < app->samples_count; i += 4) {
|
||||
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
|
||||
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
|
||||
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2
|
||||
|
||||
float data = ((float)int_16 / 256.0 + 127.0);
|
||||
data -= UINT8_MAX / 2; // to signed
|
||||
data /= UINT8_MAX / 2; // scale -1..1
|
||||
|
||||
data *= app->volume; // volume
|
||||
data = tanhf(data); // hyperbolic tangent limiter
|
||||
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i / 4] = data;
|
||||
}
|
||||
|
||||
count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
for(size_t i = 0; i < app->samples_count; i += 4) {
|
||||
int16_t L = (((int16_t)app->tmp_buffer[i + 1] << 8) + (int16_t)app->tmp_buffer[i]);
|
||||
int16_t R = (((int16_t)app->tmp_buffer[i + 3] << 8) + (int16_t)app->tmp_buffer[i + 2]);
|
||||
int32_t int_16 = L / 2 + R / 2; // (L + R) / 2
|
||||
|
||||
float data = ((float)int_16 / 256.0 + 127.0);
|
||||
data -= UINT8_MAX / 2; // to signed
|
||||
data /= UINT8_MAX / 2; // scale -1..1
|
||||
|
||||
data *= app->volume; // volume
|
||||
data = tanhf(data); // hyperbolic tangent limiter
|
||||
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i / 4 + app->samples_count / 4] = data;
|
||||
}
|
||||
|
||||
wav_player_view_set_data(app->view, sample_buffer_start, app->samples_count_half);
|
||||
|
||||
return count != app->samples_count;
|
||||
}
|
||||
|
||||
if(app->num_channels == 2 && app->bits_per_sample == 8) {
|
||||
uint16_t* sample_buffer_start = &app->sample_buffer[index];
|
||||
size_t count = stream_read(app->stream, app->tmp_buffer, app->samples_count);
|
||||
|
||||
@@ -270,6 +371,9 @@ static void app_run(WavPlayerApp* app) {
|
||||
while(1) {
|
||||
if(furi_message_queue_get(app->queue, &event, FuriWaitForever) == FuriStatusOk) {
|
||||
if(event.type == WavPlayerEventHalfTransfer) {
|
||||
wav_player_view_set_chans(app->view, app->num_channels);
|
||||
wav_player_view_set_bits(app->view, app->bits_per_sample);
|
||||
|
||||
eof = fill_data(app, 0);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
@@ -280,6 +384,9 @@ static void app_run(WavPlayerApp* app) {
|
||||
}
|
||||
|
||||
} else if(event.type == WavPlayerEventFullTransfer) {
|
||||
wav_player_view_set_chans(app->view, app->num_channels);
|
||||
wav_player_view_set_bits(app->view, app->bits_per_sample);
|
||||
|
||||
eof = fill_data(app, app->samples_count_half);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
if(eof) {
|
||||
@@ -297,14 +404,20 @@ static void app_run(WavPlayerApp* app) {
|
||||
} else if(event.type == WavPlayerEventCtrlMoveL) {
|
||||
int32_t seek =
|
||||
stream_tell(app->stream) - wav_parser_get_data_start(app->parser);
|
||||
seek =
|
||||
MIN(seek, (int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100));
|
||||
seek = MIN(
|
||||
seek,
|
||||
(int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100) % 2 ?
|
||||
((int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100) - 1) :
|
||||
(int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100));
|
||||
stream_seek(app->stream, -seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlMoveR) {
|
||||
int32_t seek = wav_parser_get_data_end(app->parser) - stream_tell(app->stream);
|
||||
seek =
|
||||
MIN(seek, (int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100));
|
||||
seek = MIN(
|
||||
seek,
|
||||
(int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100) % 2 ?
|
||||
((int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100) - 1) :
|
||||
(int32_t)(wav_parser_get_data_len(app->parser) / (size_t)100));
|
||||
stream_seek(app->stream, seek, StreamOffsetFromCurrent);
|
||||
wav_player_view_set_current(app->view, stream_tell(app->stream));
|
||||
} else if(event.type == WavPlayerEventCtrlOk) {
|
||||
|
||||
@@ -35,7 +35,7 @@ void wav_player_speaker_init(uint32_t sample_rate) {
|
||||
TIM_InitStruct.Prescaler = 0;
|
||||
//TIM_InitStruct.Autoreload = 1451; //64 000 000 / 1451 ~= 44100 Hz
|
||||
|
||||
TIM_InitStruct.Autoreload = 64000000 / sample_rate; //to support various sample rates
|
||||
TIM_InitStruct.Autoreload = 64000000 / sample_rate - 1; //to support various sample rates
|
||||
|
||||
LL_TIM_Init(SAMPLE_RATE_TIMER, &TIM_InitStruct);
|
||||
|
||||
@@ -48,16 +48,12 @@ void wav_player_speaker_init(uint32_t sample_rate) {
|
||||
//=========================================================
|
||||
//configuring PA6 pin as TIM16 output
|
||||
|
||||
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedVeryHigh, GpioAltFn14TIM16);
|
||||
//furi_hal_gpio_init_ex(&gpio_ext_pa6, (GpioMode)GpioPullNo, (GpioPull)GpioModeAltFunctionPushPull, GpioSpeedLow, GpioAltFn14TIM16);
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_ext_pa6,
|
||||
GpioModeAltFunctionPushPull,
|
||||
GpioPullNo,
|
||||
GpioSpeedVeryHigh,
|
||||
GpioAltFn14TIM16);
|
||||
//furi_hal_gpio_init_simple(&gpio_ext_pa6, GpioModeOutputPushPull);
|
||||
//furi_hal_gpio_write(&gpio_ext_pa6, false);
|
||||
}
|
||||
|
||||
void wav_player_speaker_start() {
|
||||
|
||||
@@ -12,6 +12,12 @@ static void wav_player_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
uint8_t x_pos = 0;
|
||||
uint8_t y_pos = 0;
|
||||
|
||||
/*char buffer[20];
|
||||
snprintf(buffer, sizeof(buffer), "%d", model->num_channels);
|
||||
canvas_draw_str(canvas, 0, 10, buffer);
|
||||
snprintf(buffer, sizeof(buffer), "%d", model->bits_per_sample);
|
||||
canvas_draw_str(canvas, 0, 20, buffer);*/
|
||||
|
||||
// volume
|
||||
x_pos = 123;
|
||||
y_pos = 0;
|
||||
@@ -156,6 +162,18 @@ void wav_player_view_set_play(WavPlayerView* wav_view, bool play) {
|
||||
wav_view->view, WavPlayerViewModel * model, { model->play = play; }, true);
|
||||
}
|
||||
|
||||
void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, WavPlayerViewModel * model, { model->num_channels = chn; }, true);
|
||||
}
|
||||
|
||||
void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
wav_view->view, WavPlayerViewModel * model, { model->bits_per_sample = bit; }, true);
|
||||
}
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) {
|
||||
furi_assert(wav_view);
|
||||
with_view_model(
|
||||
|
||||
@@ -43,6 +43,9 @@ typedef struct {
|
||||
size_t end;
|
||||
size_t current;
|
||||
uint8_t data[DATA_COUNT];
|
||||
|
||||
uint16_t bits_per_sample;
|
||||
uint16_t num_channels;
|
||||
} WavPlayerViewModel;
|
||||
|
||||
WavPlayerView* wav_player_view_alloc();
|
||||
@@ -63,6 +66,9 @@ void wav_player_view_set_play(WavPlayerView* wav_view, bool play);
|
||||
|
||||
void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count);
|
||||
|
||||
void wav_player_view_set_bits(WavPlayerView* wav_view, uint16_t bit);
|
||||
void wav_player_view_set_chans(WavPlayerView* wav_view, uint16_t chn);
|
||||
|
||||
void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback);
|
||||
|
||||
void wav_player_view_set_context(WavPlayerView* wav_view, void* context);
|
||||
|
||||
@@ -9,6 +9,7 @@ App(
|
||||
"nfc",
|
||||
"infrared",
|
||||
"gpio",
|
||||
"onewire",
|
||||
"ibutton",
|
||||
"bad_kb",
|
||||
"u2f",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "bad_kb_app_i.h"
|
||||
#include "bad_kb_app.h"
|
||||
#include "bad_kb_settings_filename.h"
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
@@ -72,6 +72,94 @@ static void bad_kb_save_settings(BadKbApp* app) {
|
||||
storage_file_free(settings_file);
|
||||
}
|
||||
|
||||
void bad_kb_reload_worker(BadKbApp* app) {
|
||||
bad_kb_script_close(app->bad_kb_script);
|
||||
app->bad_kb_script = bad_kb_script_open(app->file_path, app->is_bt ? app->bt : NULL);
|
||||
bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout);
|
||||
}
|
||||
|
||||
void bad_kb_config_switch_mode(BadKbApp* app) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
if(app->is_bt) {
|
||||
furi_hal_bt_start_advertising();
|
||||
} else {
|
||||
furi_hal_bt_stop_advertising();
|
||||
}
|
||||
scene_manager_next_scene(app->scene_manager, BadKbSceneConfig);
|
||||
bad_kb_reload_worker(app);
|
||||
}
|
||||
|
||||
void bad_kb_config_switch_remember_mode(BadKbApp* app) {
|
||||
if(app->bt_remember) {
|
||||
// set bouding mac
|
||||
uint8_t mac[6] = BAD_KB_BOUND_MAC_ADDRESS;
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
bt_set_profile_mac_address(app->bt, mac); // this also restart bt
|
||||
// enable keys storage
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
// set back user defined mac address
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
bt_set_profile_mac_address(app->bt, app->mac);
|
||||
// disable key storage
|
||||
bt_disable_peer_key_update(app->bt);
|
||||
}
|
||||
bad_kb_reload_worker(app);
|
||||
}
|
||||
|
||||
int32_t bad_kb_connection_init(BadKbApp* app) {
|
||||
app->usb_prev_mode = furi_hal_usb_get_config();
|
||||
furi_hal_usb_set_config(NULL, NULL);
|
||||
|
||||
bt_timeout = bt_hid_delays[LevelRssi39_0];
|
||||
bt_disconnect(app->bt);
|
||||
// furi_delay_ms(200);
|
||||
bt_keys_storage_set_storage_path(app->bt, BAD_KB_APP_PATH_BOUND_KEYS_FILE);
|
||||
app->bt_prev_mode = furi_hal_bt_get_profile_pairing_method(FuriHalBtProfileHidKeyboard);
|
||||
if(app->bt_remember) {
|
||||
uint8_t mac[6] = BAD_KB_BOUND_MAC_ADDRESS;
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, mac);
|
||||
// using GapPairingNone breaks bounding between devices
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
} else {
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
}
|
||||
|
||||
bt_set_profile(app->bt, BtProfileHidKeyboard);
|
||||
if(app->is_bt) {
|
||||
furi_hal_bt_start_advertising();
|
||||
if(app->bt_remember) {
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
bt_disable_peer_key_update(app->bt); // disable peer key adding to bt SRAM storage
|
||||
}
|
||||
} else {
|
||||
furi_hal_bt_stop_advertising();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bad_kb_connection_deinit(BadKbApp* app) {
|
||||
furi_hal_usb_set_config(app->usb_prev_mode, NULL);
|
||||
|
||||
// bt_hid_hold_while_keyboard_buffer_full(6, 3000); // release all keys
|
||||
bt_disconnect(app->bt); // stop ble
|
||||
// furi_delay_ms(200); // Wait 2nd core to update nvm storage
|
||||
bt_keys_storage_set_default_path(app->bt);
|
||||
if(app->bt_remember) {
|
||||
// hal primitives doesn't restarts ble, that's what we want cuz we are shutting down
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->mac);
|
||||
}
|
||||
bt_enable_peer_key_update(app->bt); // starts saving peer keys (bounded devices)
|
||||
// fails if ble radio stack isn't ready when switching profile
|
||||
// if it happens, maybe we should increase the delay after bt_disconnect
|
||||
bt_set_profile(app->bt, BtProfileSerial);
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, app->bt_prev_mode);
|
||||
}
|
||||
|
||||
BadKbApp* bad_kb_app_alloc(char* arg) {
|
||||
BadKbApp* app = malloc(sizeof(BadKbApp));
|
||||
|
||||
|
||||
@@ -1,11 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "bad_kb_app.h"
|
||||
#include "scenes/bad_kb_scene.h"
|
||||
#include "helpers/ducky_script.h"
|
||||
|
||||
typedef struct BadKbApp BadKbApp;
|
||||
#include <gui/gui.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include "views/bad_kb_view.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#define BAD_KB_APP_BASE_FOLDER EXT_PATH("badkb")
|
||||
#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts"
|
||||
#define BAD_KB_APP_SCRIPT_EXTENSION ".txt"
|
||||
#define BAD_KB_APP_LAYOUT_EXTENSION ".kl"
|
||||
|
||||
#define BAD_KB_MAC_ADDRESS_LEN 6 // need replace with MAC size maccro
|
||||
#define BAD_KB_ADV_NAME_MAX_LEN 18
|
||||
|
||||
// this is the MAC address used when we do not forget paired device (BOUND STATE)
|
||||
#define BAD_KB_BOUND_MAC_ADDRESS {0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4};
|
||||
|
||||
typedef enum {
|
||||
BadKbAppErrorNoFiles,
|
||||
BadKbAppErrorCloseRpc,
|
||||
} BadKbAppError;
|
||||
|
||||
typedef enum BadKbCustomEvent {
|
||||
BadKbAppCustomEventTextEditResult,
|
||||
BadKbAppCustomEventByteInputDone,
|
||||
BadKbCustomEventErrorBack
|
||||
} BadKbCustomEvent;
|
||||
|
||||
typedef struct {
|
||||
//uint8_t bounded_mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
uint8_t mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
char name[BAD_KB_ADV_NAME_MAX_LEN + 1];
|
||||
} BadKbBtConfig;
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
VariableItemList* var_item_list;
|
||||
|
||||
Bt* bt;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
uint8_t mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
char name[BAD_KB_ADV_NAME_MAX_LEN + 1];
|
||||
bool bt_remember; // weither we remember paired devices or not
|
||||
BadKbBtConfig bt_old_config;
|
||||
|
||||
BadKbAppError error;
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
BadKb* bad_kb_view;
|
||||
BadKbScript* bad_kb_script;
|
||||
|
||||
bool is_bt;
|
||||
|
||||
FuriHalUsbInterface* usb_prev_mode;
|
||||
GapPairing bt_prev_mode;
|
||||
|
||||
FuriThread* conn_init_thread;
|
||||
} BadKbApp;
|
||||
|
||||
typedef enum {
|
||||
BadKbAppViewError,
|
||||
BadKbAppViewWork,
|
||||
BadKbAppViewConfig,
|
||||
BadKbAppViewConfigMac,
|
||||
BadKbAppViewConfigName
|
||||
} BadKbAppView;
|
||||
|
||||
void bad_kb_config_switch_mode(BadKbApp* app);
|
||||
|
||||
void bad_kb_config_switch_remember_mode(BadKbApp* app);
|
||||
|
||||
int32_t bad_kb_connection_init(BadKbApp* app);
|
||||
|
||||
void bad_kb_connection_deinit(BadKbApp* app);
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "bad_kb_app.h"
|
||||
#include "scenes/bad_kb_scene.h"
|
||||
#include "bad_kb_script.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <assets_icons.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <gui/modules/byte_input.h>
|
||||
#include "views/bad_kb_view.h"
|
||||
|
||||
#define BAD_KB_APP_BASE_FOLDER EXT_PATH("badkb")
|
||||
#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts"
|
||||
#define BAD_KB_APP_PATH_BOUND_KEYS_FOLDER EXT_PATH("badkb/.bt_keys")
|
||||
#define BAD_KB_APP_PATH_BOUND_KEYS_FILE BAD_KB_APP_PATH_BOUND_KEYS_FOLDER "/.devices.keys"
|
||||
#define BAD_KB_APP_SCRIPT_EXTENSION ".txt"
|
||||
#define BAD_KB_APP_LAYOUT_EXTENSION ".kl"
|
||||
|
||||
#define BAD_KB_MAC_ADDRESS_LEN 6 // need replace with MAC size maccro
|
||||
#define BAD_KB_ADV_NAME_MAX_LEN 18
|
||||
|
||||
// this is the MAC address used when we do not forget paired device (BOUND STATE)
|
||||
#define BAD_KB_BOUND_MAC_ADDRESS {0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4};
|
||||
|
||||
typedef enum {
|
||||
BadKbAppErrorNoFiles,
|
||||
BadKbAppErrorCloseRpc,
|
||||
} BadKbAppError;
|
||||
|
||||
typedef enum BadKbCustomEvent {
|
||||
BadKbAppCustomEventTextEditResult,
|
||||
BadKbAppCustomEventByteInputDone,
|
||||
BadKbCustomEventErrorBack
|
||||
} BadKbCustomEvent;
|
||||
|
||||
typedef struct {
|
||||
//uint8_t bounded_mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
uint8_t mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
char name[BAD_KB_ADV_NAME_MAX_LEN + 1];
|
||||
} BadKbBtConfig;
|
||||
|
||||
struct BadKbApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
VariableItemList* var_item_list;
|
||||
|
||||
Bt* bt;
|
||||
TextInput* text_input;
|
||||
ByteInput* byte_input;
|
||||
uint8_t mac[BAD_KB_MAC_ADDRESS_LEN];
|
||||
char name[BAD_KB_ADV_NAME_MAX_LEN + 1];
|
||||
bool bt_remember; // weither we remember paired devices or not
|
||||
BadKbBtConfig bt_old_config;
|
||||
|
||||
BadKbAppError error;
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
BadKb* bad_kb_view;
|
||||
BadKbScript* bad_kb_script;
|
||||
|
||||
bool is_bt;
|
||||
|
||||
FuriHalUsbInterface* usb_prev_mode;
|
||||
GapPairing bt_prev_mode;
|
||||
|
||||
FuriThread* conn_init_thread;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
BadKbAppViewError,
|
||||
BadKbAppViewWork,
|
||||
BadKbAppViewConfig,
|
||||
BadKbAppViewConfigMac,
|
||||
BadKbAppViewConfigName
|
||||
} BadKbAppView;
|
||||
@@ -1,3 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define BAD_KB_SETTINGS_FILE_NAME ".badkb.settings"
|
||||
#define BAD_KB_APP_PATH_BOUND_KEYS_FOLDER EXT_PATH("badkb/.bt_keys")
|
||||
#define BAD_KB_APP_PATH_BOUND_KEYS_FILE BAD_KB_APP_PATH_BOUND_KEYS_FOLDER "/.devices.keys"
|
||||
|
||||
@@ -5,43 +5,19 @@
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include <storage/storage.h>
|
||||
#include "bad_kb_script.h"
|
||||
#include "mnemonic.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include <bt/bt_service/bt.h>
|
||||
|
||||
#include "bad_kb_app_i.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys")
|
||||
#include <storage/storage.h>
|
||||
#include "ducky_script.h"
|
||||
#include "ducky_script_i.h"
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "BadKB"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define SCRIPT_STATE_ERROR (-1)
|
||||
#define SCRIPT_STATE_END (-2)
|
||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
||||
|
||||
#define BADKB_ASCII_TO_KEY(script, x) \
|
||||
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
|
||||
|
||||
typedef enum {
|
||||
WorkerEvtToggle = (1 << 0),
|
||||
WorkerEvtEnd = (1 << 1),
|
||||
WorkerEvtConnect = (1 << 2),
|
||||
WorkerEvtDisconnect = (1 << 3),
|
||||
} WorkerEvtFlags;
|
||||
|
||||
typedef enum {
|
||||
LevelRssi122_100,
|
||||
LevelRssi99_80,
|
||||
LevelRssi79_60,
|
||||
LevelRssi59_40,
|
||||
LevelRssi39_0,
|
||||
LevelRssiNum,
|
||||
LevelRssiError = 0xFF,
|
||||
} LevelRssiRange;
|
||||
#define HID_BT_KEYS_STORAGE_PATH EXT_PATH("apps/Tools/.bt_hid.keys")
|
||||
|
||||
/**
|
||||
* Delays for waiting between HID key press and key release
|
||||
@@ -54,88 +30,6 @@ const uint8_t bt_hid_delays[LevelRssiNum] = {
|
||||
14, // LevelRssi39_0
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
uint16_t keycode;
|
||||
} DuckyKey;
|
||||
|
||||
static const DuckyKey ducky_keys[] = {
|
||||
{"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT},
|
||||
{"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI},
|
||||
{"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT},
|
||||
{"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL},
|
||||
|
||||
{"CTRL", KEY_MOD_LEFT_CTRL},
|
||||
{"CONTROL", KEY_MOD_LEFT_CTRL},
|
||||
{"SHIFT", KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT", KEY_MOD_LEFT_ALT},
|
||||
{"GUI", KEY_MOD_LEFT_GUI},
|
||||
{"WINDOWS", KEY_MOD_LEFT_GUI},
|
||||
|
||||
{"DOWNARROW", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"DOWN", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"LEFTARROW", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"LEFT", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"RIGHT", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"UPARROW", HID_KEYBOARD_UP_ARROW},
|
||||
{"UP", HID_KEYBOARD_UP_ARROW},
|
||||
|
||||
{"ENTER", HID_KEYBOARD_RETURN},
|
||||
{"BREAK", HID_KEYBOARD_PAUSE},
|
||||
{"PAUSE", HID_KEYBOARD_PAUSE},
|
||||
{"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK},
|
||||
{"DELETE", HID_KEYBOARD_DELETE},
|
||||
{"BACKSPACE", HID_KEYPAD_BACKSPACE},
|
||||
{"END", HID_KEYBOARD_END},
|
||||
{"ESC", HID_KEYBOARD_ESCAPE},
|
||||
{"ESCAPE", HID_KEYBOARD_ESCAPE},
|
||||
{"HOME", HID_KEYBOARD_HOME},
|
||||
{"INSERT", HID_KEYBOARD_INSERT},
|
||||
{"NUMLOCK", HID_KEYPAD_NUMLOCK},
|
||||
{"PAGEUP", HID_KEYBOARD_PAGE_UP},
|
||||
{"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN},
|
||||
{"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN},
|
||||
{"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK},
|
||||
{"SPACE", HID_KEYBOARD_SPACEBAR},
|
||||
{"TAB", HID_KEYBOARD_TAB},
|
||||
{"MENU", HID_KEYBOARD_APPLICATION},
|
||||
{"APP", HID_KEYBOARD_APPLICATION},
|
||||
|
||||
{"F1", HID_KEYBOARD_F1},
|
||||
{"F2", HID_KEYBOARD_F2},
|
||||
{"F3", HID_KEYBOARD_F3},
|
||||
{"F4", HID_KEYBOARD_F4},
|
||||
{"F5", HID_KEYBOARD_F5},
|
||||
{"F6", HID_KEYBOARD_F6},
|
||||
{"F7", HID_KEYBOARD_F7},
|
||||
{"F8", HID_KEYBOARD_F8},
|
||||
{"F9", HID_KEYBOARD_F9},
|
||||
{"F10", HID_KEYBOARD_F10},
|
||||
{"F11", HID_KEYBOARD_F11},
|
||||
{"F12", HID_KEYBOARD_F12},
|
||||
};
|
||||
|
||||
static const char ducky_cmd_comment[] = {"REM"};
|
||||
static const char ducky_cmd_id[] = {"ID"};
|
||||
static const char ducky_cmd_delay[] = {"DELAY "};
|
||||
static const char ducky_cmd_string[] = {"STRING "};
|
||||
static const char ducky_cmd_stringln[] = {"STRINGLN "};
|
||||
static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
|
||||
static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "};
|
||||
static const char ducky_cmd_stringdelay_1[] = {"STRINGDELAY "};
|
||||
static const char ducky_cmd_stringdelay_2[] = {"STRING_DELAY "};
|
||||
static const char ducky_cmd_repeat[] = {"REPEAT "};
|
||||
static const char ducky_cmd_sysrq[] = {"SYSRQ "};
|
||||
static const char ducky_cmd_hold[] = {"HOLD "};
|
||||
static const char ducky_cmd_release[] = {"RELEASE "};
|
||||
|
||||
static const char ducky_cmd_altchar[] = {"ALTCHAR "};
|
||||
static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
|
||||
static const char ducky_cmd_altstr_2[] = {"ALTCODE "};
|
||||
|
||||
uint8_t bt_timeout = 0;
|
||||
|
||||
static LevelRssiRange bt_remote_rssi_range(Bt* bt) {
|
||||
@@ -165,6 +59,28 @@ static inline void update_bt_timeout(Bt* bt) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
WorkerEvtToggle = (1 << 0),
|
||||
WorkerEvtEnd = (1 << 1),
|
||||
WorkerEvtConnect = (1 << 2),
|
||||
WorkerEvtDisconnect = (1 << 3),
|
||||
} WorkerEvtFlags;
|
||||
|
||||
static const char ducky_cmd_id[] = {"ID"};
|
||||
|
||||
static const uint8_t numpad_keys[10] = {
|
||||
HID_KEYPAD_0,
|
||||
HID_KEYPAD_1,
|
||||
HID_KEYPAD_2,
|
||||
HID_KEYPAD_3,
|
||||
HID_KEYPAD_4,
|
||||
HID_KEYPAD_5,
|
||||
HID_KEYPAD_6,
|
||||
HID_KEYPAD_7,
|
||||
HID_KEYPAD_8,
|
||||
HID_KEYPAD_9,
|
||||
};
|
||||
|
||||
uint32_t ducky_get_command_len(const char* line) {
|
||||
uint32_t len = strlen(line);
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
@@ -178,76 +94,197 @@ bool ducky_is_line_end(const char chr) {
|
||||
}
|
||||
|
||||
uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars) {
|
||||
for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) {
|
||||
size_t key_cmd_len = strlen(ducky_keys[i].name);
|
||||
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
|
||||
(ducky_is_line_end(param[key_cmd_len]))) {
|
||||
return ducky_keys[i].keycode;
|
||||
}
|
||||
uint16_t keycode = ducky_get_keycode_by_name(param);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
return keycode;
|
||||
}
|
||||
|
||||
if((accept_chars) && (strlen(param) > 0)) {
|
||||
return (BADKB_ASCII_TO_KEY(bad_kb, param[0]) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ducky_parse_line(BadKbScript* bad_kb, FuriString* line, char* error, size_t error_len) {
|
||||
bool ducky_get_number(const char* param, uint32_t* val) {
|
||||
uint32_t value = 0;
|
||||
if(sscanf(param, "%lu", &value) == 1) {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ducky_numlock_on(BadKbScript* bad_kb) {
|
||||
if(bad_kb->bt) {
|
||||
if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
} else {
|
||||
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ducky_numpad_press(BadKbScript* bad_kb, const char num) {
|
||||
if((num < '0') || (num > '9')) return false;
|
||||
|
||||
uint16_t key = numpad_keys[num - '0'];
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release(key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ducky_altchar(BadKbScript* bad_kb, const char* charcode) {
|
||||
uint8_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
}
|
||||
|
||||
while(!ducky_is_line_end(charcode[i])) {
|
||||
state = ducky_numpad_press(bad_kb, charcode[i]);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
} else {
|
||||
furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
bool ducky_altstring(BadKbScript* bad_kb, const char* param) {
|
||||
uint32_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
if((param[i] < ' ') || (param[i] > '~')) {
|
||||
i++;
|
||||
continue; // Skip non-printable chars
|
||||
}
|
||||
|
||||
char temp_str[4];
|
||||
snprintf(temp_str, 4, "%u", param[i]);
|
||||
|
||||
state = ducky_altchar(bad_kb, temp_str);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int32_t ducky_error(BadKbScript* bad_kb, const char* text, ...) {
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
vsnprintf(bad_kb->st.error, sizeof(bad_kb->st.error), text, args);
|
||||
|
||||
va_end(args);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
bool ducky_string(BadKbScript* bad_kb, const char* param) {
|
||||
uint32_t i = 0;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
if(param[i] != '\n') {
|
||||
uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, param[i]);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(keycode);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(keycode);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
bad_kb->stringdelay = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ducky_string_next(BadKbScript* bad_kb) {
|
||||
if(bad_kb->string_print_pos >= furi_string_size(bad_kb->string_print)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char print_char = furi_string_get_char(bad_kb->string_print, bad_kb->string_print_pos);
|
||||
|
||||
if(print_char != '\n') {
|
||||
uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, print_char);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(keycode);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(keycode);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
}
|
||||
}
|
||||
|
||||
bad_kb->string_print_pos++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int32_t ducky_parse_line(BadKbScript* bad_kb, FuriString* line) {
|
||||
uint32_t line_len = furi_string_size(line);
|
||||
const char* line_tmp = furi_string_get_cstr(line);
|
||||
const char* ducky_cmd_table[] = {
|
||||
ducky_cmd_comment,
|
||||
ducky_cmd_id,
|
||||
ducky_cmd_delay,
|
||||
ducky_cmd_string,
|
||||
ducky_cmd_defdelay_1,
|
||||
ducky_cmd_defdelay_2,
|
||||
ducky_cmd_stringdelay_1,
|
||||
ducky_cmd_stringdelay_2,
|
||||
ducky_cmd_repeat,
|
||||
ducky_cmd_sysrq,
|
||||
ducky_cmd_altchar,
|
||||
ducky_cmd_altstr_1,
|
||||
ducky_cmd_altstr_2,
|
||||
ducky_cmd_stringln,
|
||||
ducky_cmd_hold,
|
||||
ducky_cmd_release,
|
||||
NULL};
|
||||
int32_t (*fnc_ptr[])(BadKbScript*, FuriString*, const char*, char*, size_t) = {
|
||||
&ducky_fnc_noop,
|
||||
&ducky_fnc_noop,
|
||||
&ducky_fnc_delay,
|
||||
&ducky_fnc_string,
|
||||
&ducky_fnc_defdelay,
|
||||
&ducky_fnc_defdelay,
|
||||
&ducky_fnc_strdelay,
|
||||
&ducky_fnc_strdelay,
|
||||
&ducky_fnc_repeat,
|
||||
&ducky_fnc_sysrq,
|
||||
&ducky_fnc_altchar,
|
||||
&ducky_fnc_altstring,
|
||||
&ducky_fnc_altstring,
|
||||
&ducky_fnc_stringln,
|
||||
&ducky_fnc_hold,
|
||||
&ducky_fnc_release,
|
||||
NULL};
|
||||
|
||||
if(line_len == 0) {
|
||||
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
|
||||
}
|
||||
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
|
||||
|
||||
// Ducky Lang Functions
|
||||
for(size_t i = 0; ducky_cmd_table[i]; i++) {
|
||||
if(strncmp(line_tmp, ducky_cmd_table[i], strlen(ducky_cmd_table[i])) == 0)
|
||||
return ((fnc_ptr[i])(bad_kb, line, line_tmp, error, error_len));
|
||||
int32_t cmd_result = ducky_execute_cmd(bad_kb, line_tmp);
|
||||
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
|
||||
return cmd_result;
|
||||
}
|
||||
|
||||
// Special keys + modifiers
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line_tmp, false);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
return ducky_error(bad_kb, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
if((key & 0xFF00) != 0) {
|
||||
// It's a modifier key
|
||||
@@ -262,7 +299,7 @@ static int32_t
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release(key);
|
||||
}
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ducky_set_usb_id(BadKbScript* bad_kb, const char* line) {
|
||||
@@ -342,8 +379,7 @@ static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file)
|
||||
|
||||
if(bad_kb->repeat_cnt > 0) {
|
||||
bad_kb->repeat_cnt--;
|
||||
delay_val = ducky_parse_line(
|
||||
bad_kb, bad_kb->line_prev, bad_kb->st.error, sizeof(bad_kb->st.error));
|
||||
delay_val = ducky_parse_line(bad_kb, bad_kb->line_prev);
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val < 0) { // Script error
|
||||
@@ -378,20 +414,14 @@ static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file)
|
||||
bad_kb->buf_len = bad_kb->buf_len + bad_kb->buf_start - (i + 1);
|
||||
bad_kb->buf_start = i + 1;
|
||||
furi_string_trim(bad_kb->line);
|
||||
delay_val = ducky_parse_line(
|
||||
bad_kb, bad_kb->line, bad_kb->st.error, sizeof(bad_kb->st.error));
|
||||
delay_val = ducky_parse_line(bad_kb, bad_kb->line);
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
||||
return 0;
|
||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
|
||||
return delay_val;
|
||||
} else if(delay_val < 0) {
|
||||
bad_kb->st.error_line = bad_kb->st.line_cur;
|
||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) {
|
||||
snprintf(
|
||||
bad_kb->st.error, sizeof(bad_kb->st.error), "Forbidden empty line");
|
||||
FURI_LOG_E(
|
||||
WORKER_TAG, "Forbidden empty line at line %u", bad_kb->st.line_cur);
|
||||
} else {
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur);
|
||||
}
|
||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_kb->st.line_cur);
|
||||
return SCRIPT_STATE_ERROR;
|
||||
} else {
|
||||
return (delay_val + bad_kb->defdelay);
|
||||
@@ -403,11 +433,13 @@ static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file)
|
||||
bad_kb->buf_len = 0;
|
||||
if(bad_kb->file_end) return SCRIPT_STATE_END;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bad_kb_bt_hid_state_callback(BtStatus status, void* context) {
|
||||
furi_assert(context);
|
||||
BadKbScript* bad_kb = (BadKbScript*)context;
|
||||
BadKbScript* bad_kb = context;
|
||||
bool state = (status == BtStatusConnected);
|
||||
|
||||
if(state == true) {
|
||||
@@ -432,94 +464,6 @@ static void bad_kb_usb_hid_state_callback(bool state, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
void bad_kb_reload_worker(BadKbApp* app) {
|
||||
bad_kb_script_close(app->bad_kb_script);
|
||||
app->bad_kb_script = bad_kb_script_open(app->file_path, app->is_bt ? app->bt : NULL);
|
||||
bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout);
|
||||
}
|
||||
|
||||
void bad_kb_config_switch_mode(BadKbApp* app) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
if(app->is_bt) {
|
||||
furi_hal_bt_start_advertising();
|
||||
} else {
|
||||
furi_hal_bt_stop_advertising();
|
||||
}
|
||||
scene_manager_next_scene(app->scene_manager, BadKbSceneConfig);
|
||||
bad_kb_reload_worker(app);
|
||||
}
|
||||
|
||||
void bad_kb_config_switch_remember_mode(BadKbApp* app) {
|
||||
if(app->bt_remember) {
|
||||
// set bouding mac
|
||||
uint8_t mac[6] = BAD_KB_BOUND_MAC_ADDRESS;
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
bt_set_profile_mac_address(app->bt, mac); // this also restart bt
|
||||
// enable keys storage
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
// set back user defined mac address
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
bt_set_profile_mac_address(app->bt, app->mac);
|
||||
// disable key storage
|
||||
bt_disable_peer_key_update(app->bt);
|
||||
}
|
||||
bad_kb_reload_worker(app);
|
||||
}
|
||||
|
||||
int32_t bad_kb_connection_init(BadKbApp* app) {
|
||||
app->usb_prev_mode = furi_hal_usb_get_config();
|
||||
furi_hal_usb_set_config(NULL, NULL);
|
||||
|
||||
bt_timeout = bt_hid_delays[LevelRssi39_0];
|
||||
bt_disconnect(app->bt);
|
||||
// furi_delay_ms(200);
|
||||
bt_keys_storage_set_storage_path(app->bt, BAD_KB_APP_PATH_BOUND_KEYS_FILE);
|
||||
app->bt_prev_mode = furi_hal_bt_get_profile_pairing_method(FuriHalBtProfileHidKeyboard);
|
||||
if(app->bt_remember) {
|
||||
uint8_t mac[6] = BAD_KB_BOUND_MAC_ADDRESS;
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, mac);
|
||||
// using GapPairingNone breaks bounding between devices
|
||||
furi_hal_bt_set_profile_pairing_method(
|
||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
||||
} else {
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
||||
}
|
||||
|
||||
bt_set_profile(app->bt, BtProfileHidKeyboard);
|
||||
if(app->is_bt) {
|
||||
furi_hal_bt_start_advertising();
|
||||
if(app->bt_remember) {
|
||||
bt_enable_peer_key_update(app->bt);
|
||||
} else {
|
||||
bt_disable_peer_key_update(app->bt); // disable peer key adding to bt SRAM storage
|
||||
}
|
||||
} else {
|
||||
furi_hal_bt_stop_advertising();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bad_kb_connection_deinit(BadKbApp* app) {
|
||||
furi_hal_usb_set_config(app->usb_prev_mode, NULL);
|
||||
|
||||
// bt_hid_hold_while_keyboard_buffer_full(6, 3000); // release all keys
|
||||
bt_disconnect(app->bt); // stop ble
|
||||
// furi_delay_ms(200); // Wait 2nd core to update nvm storage
|
||||
bt_keys_storage_set_default_path(app->bt);
|
||||
if(app->bt_remember) {
|
||||
// hal primitives doesn't restarts ble, that's what we want cuz we are shutting down
|
||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->mac);
|
||||
}
|
||||
bt_enable_peer_key_update(app->bt); // starts saving peer keys (bounded devices)
|
||||
// fails if ble radio stack isn't ready when switching profile
|
||||
// if it happens, maybe we should increase the delay after bt_disconnect
|
||||
bt_set_profile(app->bt, BtProfileSerial);
|
||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, app->bt_prev_mode);
|
||||
}
|
||||
|
||||
static uint32_t bad_kb_flags_get(uint32_t flags_mask, uint32_t timeout) {
|
||||
uint32_t flags = furi_thread_flags_get();
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
@@ -539,17 +483,18 @@ static int32_t bad_kb_worker(void* context) {
|
||||
BadKbWorkerState worker_state = BadKbStateInit;
|
||||
int32_t delay_val = 0;
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
bad_kb->line = furi_string_alloc();
|
||||
bad_kb->line_prev = furi_string_alloc();
|
||||
bad_kb->string_print = furi_string_alloc();
|
||||
|
||||
if(bad_kb->bt) {
|
||||
bt_set_status_changed_callback(bad_kb->bt, bad_kb_bt_hid_state_callback, bad_kb);
|
||||
} else {
|
||||
furi_hal_hid_set_state_callback(bad_kb_usb_hid_state_callback, bad_kb);
|
||||
}
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "Init");
|
||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
||||
bad_kb->line = furi_string_alloc();
|
||||
bad_kb->line_prev = furi_string_alloc();
|
||||
|
||||
while(1) {
|
||||
if(worker_state == BadKbStateInit) { // State: initialization
|
||||
if(storage_file_open(
|
||||
@@ -583,6 +528,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
} else if(worker_state == BadKbStateNotConnected) { // State: Not connected
|
||||
uint32_t flags = bad_kb_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtConnect) {
|
||||
@@ -595,6 +541,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
} else if(worker_state == BadKbStateIdle) { // State: ready to start
|
||||
uint32_t flags = bad_kb_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtToggle) { // Start executing script
|
||||
@@ -605,6 +552,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
bad_kb->defdelay = 0;
|
||||
bad_kb->stringdelay = 0;
|
||||
bad_kb->repeat_cnt = 0;
|
||||
bad_kb->key_hold_nb = 0;
|
||||
bad_kb->file_end = false;
|
||||
storage_file_seek(script_file, 0, true);
|
||||
bad_kb_script_set_keyboard_layout(bad_kb, bad_kb->keyboard_layout);
|
||||
@@ -617,6 +565,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
} else if(worker_state == BadKbStateWillRun) { // State: start on connection
|
||||
uint32_t flags = bad_kb_flags_get(
|
||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtConnect) { // Start executing script
|
||||
@@ -654,6 +603,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur);
|
||||
|
||||
delay_val -= delay_cur;
|
||||
if(!(flags & FuriFlagError)) {
|
||||
if(flags & WorkerEvtEnd) {
|
||||
@@ -688,6 +638,11 @@ static int32_t bad_kb_worker(void* context) {
|
||||
delay_val = 0;
|
||||
worker_state = BadKbStateScriptError;
|
||||
bad_kb->st.state = worker_state;
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
} else {
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
} else if(delay_val == SCRIPT_STATE_END) { // End of script
|
||||
delay_val = 0;
|
||||
worker_state = BadKbStateIdle;
|
||||
@@ -698,6 +653,10 @@ static int32_t bad_kb_worker(void* context) {
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
continue;
|
||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
|
||||
delay_val = bad_kb->defdelay;
|
||||
bad_kb->string_print_pos = 0;
|
||||
worker_state = BadKbStateStringDelay;
|
||||
} else if(delay_val > 1000) {
|
||||
bad_kb->st.state = BadKbStateDelay; // Show long delays
|
||||
bad_kb->st.delay_remain = delay_val / 1000;
|
||||
@@ -705,12 +664,49 @@ static int32_t bad_kb_worker(void* context) {
|
||||
} else {
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
}
|
||||
} else if(worker_state == BadKbStateStringDelay) { // State: print string with delays
|
||||
uint32_t flags = furi_thread_flags_wait(
|
||||
WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect,
|
||||
FuriFlagWaitAny,
|
||||
bad_kb->stringdelay);
|
||||
|
||||
if(!(flags & FuriFlagError)) {
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
} else if(flags & WorkerEvtToggle) {
|
||||
worker_state = BadKbStateIdle; // Stop executing script
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
} else {
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
} else if(flags & WorkerEvtDisconnect) {
|
||||
worker_state = BadKbStateNotConnected; // USB disconnected
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release_all();
|
||||
} else {
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
}
|
||||
bad_kb->st.state = worker_state;
|
||||
continue;
|
||||
} else if(
|
||||
(flags == (unsigned)FuriFlagErrorTimeout) ||
|
||||
(flags == (unsigned)FuriFlagErrorResource)) {
|
||||
bool string_end = ducky_string_next(bad_kb);
|
||||
if(string_end) {
|
||||
bad_kb->stringdelay = 0;
|
||||
worker_state = BadKbStateRunning;
|
||||
}
|
||||
} else {
|
||||
furi_check((flags & FuriFlagError) == 0);
|
||||
}
|
||||
} else if(
|
||||
(worker_state == BadKbStateFileError) ||
|
||||
(worker_state == BadKbStateScriptError)) { // State: error
|
||||
uint32_t flags =
|
||||
bad_kb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
|
||||
|
||||
if(flags & WorkerEvtEnd) {
|
||||
break;
|
||||
}
|
||||
@@ -730,6 +726,7 @@ static int32_t bad_kb_worker(void* context) {
|
||||
storage_file_free(script_file);
|
||||
furi_string_free(bad_kb->line);
|
||||
furi_string_free(bad_kb->line_prev);
|
||||
furi_string_free(bad_kb->string_print);
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "End");
|
||||
|
||||
@@ -8,10 +8,20 @@ extern "C" {
|
||||
#include <furi_hal.h>
|
||||
#include <bt/bt_service/bt_i.h>
|
||||
|
||||
typedef struct BadKbApp BadKbApp;
|
||||
|
||||
#define FILE_BUFFER_LEN 16
|
||||
|
||||
typedef enum {
|
||||
LevelRssi122_100,
|
||||
LevelRssi99_80,
|
||||
LevelRssi79_60,
|
||||
LevelRssi59_40,
|
||||
LevelRssi39_0,
|
||||
LevelRssiNum,
|
||||
LevelRssiError = 0xFF,
|
||||
} LevelRssiRange;
|
||||
|
||||
extern const uint8_t bt_hid_delays[LevelRssiNum];
|
||||
|
||||
extern uint8_t bt_timeout;
|
||||
|
||||
typedef enum {
|
||||
@@ -21,6 +31,7 @@ typedef enum {
|
||||
BadKbStateWillRun,
|
||||
BadKbStateRunning,
|
||||
BadKbStateDelay,
|
||||
BadKbStateStringDelay,
|
||||
BadKbStateDone,
|
||||
BadKbStateScriptError,
|
||||
BadKbStateFileError,
|
||||
@@ -37,35 +48,33 @@ typedef struct {
|
||||
char error[64];
|
||||
} BadKbState;
|
||||
|
||||
typedef struct BadKbScript {
|
||||
typedef struct {
|
||||
FuriHalUsbHidConfig hid_cfg;
|
||||
FuriThread* thread;
|
||||
BadKbState st;
|
||||
|
||||
FuriString* file_path;
|
||||
FuriString* keyboard_layout;
|
||||
uint32_t defdelay;
|
||||
uint16_t layout[128];
|
||||
uint32_t stringdelay;
|
||||
FuriThread* thread;
|
||||
uint8_t file_buf[FILE_BUFFER_LEN + 1];
|
||||
uint8_t buf_start;
|
||||
uint8_t buf_len;
|
||||
bool file_end;
|
||||
FuriString* line;
|
||||
|
||||
uint32_t defdelay;
|
||||
uint32_t stringdelay;
|
||||
uint16_t layout[128];
|
||||
|
||||
FuriString* line;
|
||||
FuriString* line_prev;
|
||||
uint32_t repeat_cnt;
|
||||
uint8_t key_hold_nb;
|
||||
|
||||
FuriString* string_print;
|
||||
size_t string_print_pos;
|
||||
|
||||
Bt* bt;
|
||||
} BadKbScript;
|
||||
|
||||
void bad_kb_config_switch_mode(BadKbApp* app);
|
||||
|
||||
void bad_kb_config_switch_remember_mode(BadKbApp* app);
|
||||
|
||||
int32_t bad_kb_connection_init(BadKbApp* app);
|
||||
|
||||
void bad_kb_connection_deinit(BadKbApp* app);
|
||||
|
||||
BadKbScript* bad_kb_script_open(FuriString* file_path, Bt* bt);
|
||||
|
||||
void bad_kb_script_close(BadKbScript* bad_kb);
|
||||
@@ -80,12 +89,6 @@ void bad_kb_script_toggle(BadKbScript* bad_kb);
|
||||
|
||||
BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb);
|
||||
|
||||
uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars);
|
||||
|
||||
uint32_t ducky_get_command_len(const char* line);
|
||||
|
||||
bool ducky_is_line_end(const char chr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
194
applications/main/bad_kb/helpers/ducky_script_commands.c
Normal file
194
applications/main/bad_kb/helpers/ducky_script_commands.c
Normal file
@@ -0,0 +1,194 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "ducky_script.h"
|
||||
#include "ducky_script_i.h"
|
||||
|
||||
typedef int32_t (*DuckyCmdCallback)(BadKbScript* bad_kb, const char* line, int32_t param);
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
DuckyCmdCallback callback;
|
||||
int32_t param;
|
||||
} DuckyCmd;
|
||||
|
||||
static int32_t ducky_fnc_delay(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint32_t delay_val = 0;
|
||||
bool state = ducky_get_number(line, &delay_val);
|
||||
if((state) && (delay_val > 0)) {
|
||||
return (int32_t)delay_val;
|
||||
}
|
||||
|
||||
return ducky_error(bad_kb, "Invalid number %s", line);
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_defdelay(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_kb->defdelay);
|
||||
if(!state) {
|
||||
return ducky_error(bad_kb, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_strdelay(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_kb->stringdelay);
|
||||
if(!state) {
|
||||
return ducky_error(bad_kb, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_string(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
furi_string_set_str(bad_kb->string_print, line);
|
||||
if(param == 1) {
|
||||
furi_string_cat(bad_kb->string_print, "\n");
|
||||
}
|
||||
|
||||
if(bad_kb->stringdelay == 0) { // stringdelay not set - run command immidiately
|
||||
bool state = ducky_string(bad_kb, furi_string_get_cstr(bad_kb->string_print));
|
||||
if(!state) {
|
||||
return ducky_error(bad_kb, "Invalid string %s", line);
|
||||
}
|
||||
} else { // stringdelay is set - run command in thread to keep handling external events
|
||||
return SCRIPT_STATE_STRING_START;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_repeat(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
bool state = ducky_get_number(line, &bad_kb->repeat_cnt);
|
||||
if((!state) || (bad_kb->repeat_cnt == 0)) {
|
||||
return ducky_error(bad_kb, "Invalid number %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_sysrq(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line, true);
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_altchar(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
ducky_numlock_on(bad_kb);
|
||||
bool state = ducky_altchar(bad_kb, line);
|
||||
if(!state) {
|
||||
return ducky_error(bad_kb, "Invalid altchar %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_altstring(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
ducky_numlock_on(bad_kb);
|
||||
bool state = ducky_altstring(bad_kb, line);
|
||||
if(!state) {
|
||||
return ducky_error(bad_kb, "Invalid altstring %s", line);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_hold(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
return ducky_error(bad_kb, "No keycode defined for %s", line);
|
||||
}
|
||||
bad_kb->key_hold_nb++;
|
||||
if(bad_kb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
|
||||
return ducky_error(bad_kb, "Too many keys are hold");
|
||||
}
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t ducky_fnc_release(BadKbScript* bad_kb, const char* line, int32_t param) {
|
||||
UNUSED(param);
|
||||
|
||||
line = &line[ducky_get_command_len(line) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
return ducky_error(bad_kb, "No keycode defined for %s", line);
|
||||
}
|
||||
if(bad_kb->key_hold_nb == 0) {
|
||||
return ducky_error(bad_kb, "No keys are hold");
|
||||
}
|
||||
bad_kb->key_hold_nb--;
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_release(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const DuckyCmd ducky_commands[] = {
|
||||
{"REM ", NULL, -1},
|
||||
{"ID ", NULL, -1},
|
||||
{"DELAY ", ducky_fnc_delay, -1},
|
||||
{"STRING ", ducky_fnc_string, 0},
|
||||
{"STRINGLN ", ducky_fnc_string, 1},
|
||||
{"DEFAULT_DELAY ", ducky_fnc_defdelay, -1},
|
||||
{"DEFAULTDELAY ", ducky_fnc_defdelay, -1},
|
||||
{"STRINGDELAY ", ducky_fnc_strdelay, -1},
|
||||
{"STRING_DELAY ", ducky_fnc_strdelay, -1},
|
||||
{"REPEAT ", ducky_fnc_repeat, -1},
|
||||
{"SYSRQ ", ducky_fnc_sysrq, -1},
|
||||
{"ALTCHAR ", ducky_fnc_altchar, -1},
|
||||
{"ALTSTRING ", ducky_fnc_altstring, -1},
|
||||
{"ALTCODE ", ducky_fnc_altstring, -1},
|
||||
{"HOLD ", ducky_fnc_hold, -1},
|
||||
{"RELEASE ", ducky_fnc_release, -1},
|
||||
};
|
||||
|
||||
int32_t ducky_execute_cmd(BadKbScript* bad_kb, const char* line) {
|
||||
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
|
||||
if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) {
|
||||
if(ducky_commands[i].callback == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
return ((ducky_commands[i].callback)(bad_kb, line, ducky_commands[i].param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SCRIPT_STATE_CMD_UNKNOWN;
|
||||
}
|
||||
43
applications/main/bad_kb/helpers/ducky_script_i.h
Normal file
43
applications/main/bad_kb/helpers/ducky_script_i.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "ducky_script.h"
|
||||
|
||||
#define SCRIPT_STATE_ERROR (-1)
|
||||
#define SCRIPT_STATE_END (-2)
|
||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
||||
#define SCRIPT_STATE_CMD_UNKNOWN (-4)
|
||||
#define SCRIPT_STATE_STRING_START (-5)
|
||||
|
||||
uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars);
|
||||
|
||||
uint32_t ducky_get_command_len(const char* line);
|
||||
|
||||
bool ducky_is_line_end(const char chr);
|
||||
|
||||
uint16_t ducky_get_keycode_by_name(const char* param);
|
||||
|
||||
bool ducky_get_number(const char* param, uint32_t* val);
|
||||
|
||||
void ducky_numlock_on(BadKbScript* bad_kb);
|
||||
|
||||
bool ducky_numpad_press(BadKbScript* bad_kb, const char num);
|
||||
|
||||
bool ducky_altchar(BadKbScript* bad_kb, const char* charcode);
|
||||
|
||||
bool ducky_altstring(BadKbScript* bad_kb, const char* param);
|
||||
|
||||
bool ducky_string(BadKbScript* bad_kb, const char* param);
|
||||
|
||||
int32_t ducky_execute_cmd(BadKbScript* bad_kb, const char* line);
|
||||
|
||||
int32_t ducky_error(BadKbScript* bad_kb, const char* text, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
79
applications/main/bad_kb/helpers/ducky_script_keycodes.c
Normal file
79
applications/main/bad_kb/helpers/ducky_script_keycodes.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "ducky_script_i.h"
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
uint16_t keycode;
|
||||
} DuckyKey;
|
||||
|
||||
static const DuckyKey ducky_keys[] = {
|
||||
{"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT},
|
||||
{"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI},
|
||||
{"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT},
|
||||
{"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL},
|
||||
|
||||
{"CTRL", KEY_MOD_LEFT_CTRL},
|
||||
{"CONTROL", KEY_MOD_LEFT_CTRL},
|
||||
{"SHIFT", KEY_MOD_LEFT_SHIFT},
|
||||
{"ALT", KEY_MOD_LEFT_ALT},
|
||||
{"GUI", KEY_MOD_LEFT_GUI},
|
||||
{"WINDOWS", KEY_MOD_LEFT_GUI},
|
||||
|
||||
{"DOWNARROW", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"DOWN", HID_KEYBOARD_DOWN_ARROW},
|
||||
{"LEFTARROW", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"LEFT", HID_KEYBOARD_LEFT_ARROW},
|
||||
{"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"RIGHT", HID_KEYBOARD_RIGHT_ARROW},
|
||||
{"UPARROW", HID_KEYBOARD_UP_ARROW},
|
||||
{"UP", HID_KEYBOARD_UP_ARROW},
|
||||
|
||||
{"ENTER", HID_KEYBOARD_RETURN},
|
||||
{"BREAK", HID_KEYBOARD_PAUSE},
|
||||
{"PAUSE", HID_KEYBOARD_PAUSE},
|
||||
{"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK},
|
||||
{"DELETE", HID_KEYBOARD_DELETE_FORWARD},
|
||||
{"BACKSPACE", HID_KEYBOARD_DELETE},
|
||||
{"END", HID_KEYBOARD_END},
|
||||
{"ESC", HID_KEYBOARD_ESCAPE},
|
||||
{"ESCAPE", HID_KEYBOARD_ESCAPE},
|
||||
{"HOME", HID_KEYBOARD_HOME},
|
||||
{"INSERT", HID_KEYBOARD_INSERT},
|
||||
{"NUMLOCK", HID_KEYPAD_NUMLOCK},
|
||||
{"PAGEUP", HID_KEYBOARD_PAGE_UP},
|
||||
{"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN},
|
||||
{"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN},
|
||||
{"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK},
|
||||
{"SPACE", HID_KEYBOARD_SPACEBAR},
|
||||
{"TAB", HID_KEYBOARD_TAB},
|
||||
{"MENU", HID_KEYBOARD_APPLICATION},
|
||||
{"APP", HID_KEYBOARD_APPLICATION},
|
||||
|
||||
{"F1", HID_KEYBOARD_F1},
|
||||
{"F2", HID_KEYBOARD_F2},
|
||||
{"F3", HID_KEYBOARD_F3},
|
||||
{"F4", HID_KEYBOARD_F4},
|
||||
{"F5", HID_KEYBOARD_F5},
|
||||
{"F6", HID_KEYBOARD_F6},
|
||||
{"F7", HID_KEYBOARD_F7},
|
||||
{"F8", HID_KEYBOARD_F8},
|
||||
{"F9", HID_KEYBOARD_F9},
|
||||
{"F10", HID_KEYBOARD_F10},
|
||||
{"F11", HID_KEYBOARD_F11},
|
||||
{"F12", HID_KEYBOARD_F12},
|
||||
};
|
||||
|
||||
uint16_t ducky_get_keycode_by_name(const char* param) {
|
||||
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
|
||||
size_t key_cmd_len = strlen(ducky_keys[i].name);
|
||||
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
|
||||
(ducky_is_line_end(param[key_cmd_len]))) {
|
||||
return ducky_keys[i].keycode;
|
||||
}
|
||||
}
|
||||
|
||||
return HID_KEYBOARD_NONE;
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
#include "mnemonic.h"
|
||||
|
||||
#define TAG "BadKB"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define FILE_BUFFER_LEN 16
|
||||
#define SCRIPT_STATE_ERROR (-1)
|
||||
#define SCRIPT_STATE_END (-2)
|
||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
||||
|
||||
#define BADKB_ASCII_TO_KEY(script, x) \
|
||||
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
|
||||
|
||||
static const uint8_t numpad_keys[10] = {
|
||||
HID_KEYPAD_0,
|
||||
HID_KEYPAD_1,
|
||||
HID_KEYPAD_2,
|
||||
HID_KEYPAD_3,
|
||||
HID_KEYPAD_4,
|
||||
HID_KEYPAD_5,
|
||||
HID_KEYPAD_6,
|
||||
HID_KEYPAD_7,
|
||||
HID_KEYPAD_8,
|
||||
HID_KEYPAD_9,
|
||||
};
|
||||
|
||||
static bool ducky_get_number(const char* param, uint32_t* val) {
|
||||
uint32_t value = 0;
|
||||
if(sscanf(param, "%lu", &value) == 1) {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ducky_numlock_on(BadKbScript* bad_kb) {
|
||||
if(bad_kb->bt) {
|
||||
if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
} else {
|
||||
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ducky_numpad_press(BadKbScript* bad_kb, const char num) {
|
||||
if((num < '0') || (num > '9')) return false;
|
||||
|
||||
uint16_t key = numpad_keys[num - '0'];
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release(key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ducky_altchar(BadKbScript* bad_kb, const char* charcode) {
|
||||
uint8_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
FURI_LOG_I(WORKER_TAG, "char %s", charcode);
|
||||
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
|
||||
}
|
||||
|
||||
while(!ducky_is_line_end(charcode[i])) {
|
||||
state = ducky_numpad_press(bad_kb, charcode[i]);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
} else {
|
||||
furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool ducky_altstring(BadKbScript* bad_kb, const char* param) {
|
||||
uint32_t i = 0;
|
||||
bool state = false;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
if((param[i] < ' ') || (param[i] > '~')) {
|
||||
i++;
|
||||
continue; // Skip non-printable chars
|
||||
}
|
||||
|
||||
char temp_str[4];
|
||||
snprintf(temp_str, 4, "%u", param[i]);
|
||||
|
||||
state = ducky_altchar(bad_kb, temp_str);
|
||||
if(state == false) break;
|
||||
i++;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool ducky_string(BadKbScript* bad_kb, const char* param) {
|
||||
uint32_t i = 0;
|
||||
|
||||
while(param[i] != '\0') {
|
||||
uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, param[i]);
|
||||
if(keycode != HID_KEYBOARD_NONE) {
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(keycode);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(keycode);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(keycode);
|
||||
furi_hal_hid_kb_release(keycode);
|
||||
}
|
||||
if(bad_kb->stringdelay > 0) {
|
||||
furi_delay_ms(bad_kb->stringdelay);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
bad_kb->stringdelay = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_noop(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
(void)bad_kb;
|
||||
(void)line;
|
||||
(void)line_tmp;
|
||||
(void)error;
|
||||
(void)error_len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_delay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)bad_kb;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
uint32_t delay_val = 0;
|
||||
state = ducky_get_number(line_tmp, &delay_val);
|
||||
if((state) && (delay_val > 0)) {
|
||||
return (int32_t)delay_val;
|
||||
}
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_defdelay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_kb->defdelay);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_strdelay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_kb->stringdelay);
|
||||
if((state) && (bad_kb->stringdelay > 0)) {
|
||||
return state;
|
||||
}
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_string(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_string(bad_kb, line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid string %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_repeat(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_get_number(line_tmp, &bad_kb->repeat_cnt);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid number %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_sysrq(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
(void)error;
|
||||
(void)error_len;
|
||||
(void)line;
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line_tmp, true);
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
||||
furi_hal_hid_kb_press(key);
|
||||
furi_hal_hid_kb_release_all();
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_altchar(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)bad_kb;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on(bad_kb);
|
||||
state = ducky_altchar(bad_kb, line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid altchar %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_altstring(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)bad_kb;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
ducky_numlock_on(bad_kb);
|
||||
state = ducky_altstring(bad_kb, line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid altstring %s", line_tmp);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_stringln(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
bool state = false;
|
||||
(void)line;
|
||||
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
state = ducky_string(bad_kb, line_tmp);
|
||||
if(!state && error != NULL) {
|
||||
snprintf(error, error_len, "Invalid string %s", line_tmp);
|
||||
}
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_delay_ms(bt_timeout);
|
||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
|
||||
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
|
||||
}
|
||||
return (state) ? (0) : SCRIPT_STATE_ERROR;
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_hold(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
(void)line;
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line_tmp, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_press(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_press(key);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int32_t ducky_fnc_release(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len) {
|
||||
(void)line;
|
||||
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
|
||||
uint16_t key = ducky_get_keycode(bad_kb, line_tmp, true);
|
||||
if(key == HID_KEYBOARD_NONE) {
|
||||
if(error != NULL) {
|
||||
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
|
||||
}
|
||||
return SCRIPT_STATE_ERROR;
|
||||
}
|
||||
if(bad_kb->bt) {
|
||||
furi_hal_bt_hid_kb_release(key);
|
||||
} else {
|
||||
furi_hal_hid_kb_release(key);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "bad_kb_script.h"
|
||||
|
||||
// A no opperation function
|
||||
int32_t ducky_fnc_noop(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// DELAY
|
||||
int32_t ducky_fnc_delay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// DEFAULTDELAY
|
||||
int32_t ducky_fnc_defdelay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// STRINGDELAY
|
||||
int32_t ducky_fnc_strdelay(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// STRING
|
||||
int32_t ducky_fnc_string(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// STRINGLN
|
||||
int32_t ducky_fnc_stringln(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// REPEAT
|
||||
int32_t ducky_fnc_repeat(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// SYSRQ
|
||||
int32_t ducky_fnc_sysrq(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// ALTCHAR
|
||||
int32_t ducky_fnc_altchar(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// ALTSTRING
|
||||
int32_t ducky_fnc_altstring(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// HOLD
|
||||
int32_t ducky_fnc_hold(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
// RELEASE
|
||||
int32_t ducky_fnc_release(
|
||||
BadKbScript* bad_kb,
|
||||
FuriString* line,
|
||||
const char* line_tmp,
|
||||
char* error,
|
||||
size_t error_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include "furi_hal_usb.h"
|
||||
#include <xtreme/settings.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include "furi_hal_power.h"
|
||||
#include "furi_hal_usb.h"
|
||||
#include <storage/storage.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
|
||||
#define TAG "BadKbConfigMac"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
|
||||
static void bad_kb_scene_config_name_text_input_callback(void* context) {
|
||||
BadKbApp* bad_kb = context;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include "xtreme/assets.h"
|
||||
|
||||
static void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_usb.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../bad_kb_script.h"
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../helpers/ducky_script.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include "../views/bad_kb_view.h"
|
||||
#include <furi_hal.h>
|
||||
#include "toolbox/path.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "bad_kb_view.h"
|
||||
#include "../bad_kb_script.h"
|
||||
#include "../bad_kb_app_i.h"
|
||||
#include "../helpers/ducky_script.h"
|
||||
#include "../bad_kb_app.h"
|
||||
#include <toolbox/path.h>
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
@@ -98,7 +98,11 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error);
|
||||
furi_string_set_str(disp_str, model->state.error);
|
||||
elements_string_fit_width(canvas, disp_str, canvas_width(canvas));
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
} else if(model->state.state == BadKbStateIdle) {
|
||||
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
|
||||
canvas_set_font(canvas, FontBigNumbers);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../bad_kb_script.h"
|
||||
#include "../helpers/ducky_script.h"
|
||||
|
||||
typedef struct BadKb BadKb;
|
||||
typedef void (*BadKbButtonCallback)(InputKey key, void* context);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
|
||||
#include <assets_icons.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/modules/loading.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <flipper_application/flipper_application.h>
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include "fap_loader_app.h"
|
||||
|
||||
#define TAG "fap_loader_app"
|
||||
#define TAG "FapLoader"
|
||||
|
||||
struct FapLoader {
|
||||
FlipperApplication* app;
|
||||
@@ -22,6 +23,8 @@ struct FapLoader {
|
||||
Loading* loading;
|
||||
};
|
||||
|
||||
volatile bool fap_loader_debug_active = false;
|
||||
|
||||
bool fap_loader_load_name_and_icon(
|
||||
FuriString* path,
|
||||
Storage* storage,
|
||||
@@ -123,6 +126,14 @@ 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) {
|
||||
FURI_LOG_W(TAG, "Triggering BP for debugger");
|
||||
/* After hitting this, you can set breakpoints in your .fap's code
|
||||
* Note that you have to toggle breakpoints that were set before */
|
||||
__asm volatile("bkpt 0");
|
||||
}
|
||||
|
||||
FuriString* app_name = furi_string_alloc();
|
||||
path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name);
|
||||
furi_thread_set_appid(thread, furi_string_get_cstr(app_name));
|
||||
|
||||
@@ -4,25 +4,20 @@
|
||||
#include <cli/cli.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
#include <one_wire/ibutton/ibutton_key.h>
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/ibutton/ibutton_protocols.h>
|
||||
#include <ibutton/ibutton_key.h>
|
||||
#include <ibutton/ibutton_worker.h>
|
||||
#include <ibutton/ibutton_protocols.h>
|
||||
|
||||
static void ibutton_cli(Cli* cli, FuriString* args, void* context);
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
// app cli function
|
||||
void ibutton_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "ikey", CliCommandFlagDefault, ibutton_cli, cli);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(ibutton_cli);
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -257,56 +252,3 @@ void ibutton_cli(Cli* cli, FuriString* args, void* context) {
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
static void onewire_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("onewire search\r\n");
|
||||
};
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
printf("Search started\r\n");
|
||||
|
||||
onewire_host_start(onewire);
|
||||
furi_hal_power_enable_otg();
|
||||
|
||||
while(!done) {
|
||||
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
|
||||
printf("Search finished\r\n");
|
||||
onewire_host_reset_search(onewire);
|
||||
done = true;
|
||||
} else {
|
||||
printf("Found: ");
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
printf("%02X", address[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
furi_hal_power_disable_otg();
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
furi_string_free(cmd);
|
||||
onewire_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "search") == 0) {
|
||||
onewire_cli_search(cli);
|
||||
}
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include <one_wire/ibutton/ibutton_worker.h>
|
||||
#include <one_wire/ibutton/ibutton_protocols.h>
|
||||
#include <ibutton/ibutton_worker.h>
|
||||
#include <ibutton/ibutton_protocols.h>
|
||||
|
||||
#include <rpc/rpc_app.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
14
applications/main/onewire/application.fam
Normal file
14
applications/main/onewire/application.fam
Normal file
@@ -0,0 +1,14 @@
|
||||
App(
|
||||
appid="onewire",
|
||||
name="1-Wire",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=["onewire_start"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="onewire_start",
|
||||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="onewire_on_system_start",
|
||||
requires=["onewire"],
|
||||
order=60,
|
||||
)
|
||||
72
applications/main/onewire/onewire_cli.c
Normal file
72
applications/main/onewire/onewire_cli.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <cli/cli.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include <one_wire/one_wire_host.h>
|
||||
|
||||
static void onewire_cli(Cli* cli, FuriString* args, void* context);
|
||||
|
||||
void onewire_on_system_start() {
|
||||
#ifdef SRV_CLI
|
||||
Cli* cli = furi_record_open(RECORD_CLI);
|
||||
cli_add_command(cli, "onewire", CliCommandFlagDefault, onewire_cli, cli);
|
||||
furi_record_close(RECORD_CLI);
|
||||
#else
|
||||
UNUSED(onewire_cli);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void onewire_cli_print_usage() {
|
||||
printf("Usage:\r\n");
|
||||
printf("onewire search\r\n");
|
||||
};
|
||||
|
||||
static void onewire_cli_search(Cli* cli) {
|
||||
UNUSED(cli);
|
||||
OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio);
|
||||
uint8_t address[8];
|
||||
bool done = false;
|
||||
|
||||
printf("Search started\r\n");
|
||||
|
||||
onewire_host_start(onewire);
|
||||
furi_hal_power_enable_otg();
|
||||
|
||||
while(!done) {
|
||||
if(onewire_host_search(onewire, address, OneWireHostSearchModeNormal) != 1) {
|
||||
printf("Search finished\r\n");
|
||||
onewire_host_reset_search(onewire);
|
||||
done = true;
|
||||
} else {
|
||||
printf("Found: ");
|
||||
for(uint8_t i = 0; i < 8; i++) {
|
||||
printf("%02X", address[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
furi_delay_ms(100);
|
||||
}
|
||||
|
||||
furi_hal_power_disable_otg();
|
||||
onewire_host_free(onewire);
|
||||
}
|
||||
|
||||
void onewire_cli(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
FuriString* cmd;
|
||||
cmd = furi_string_alloc();
|
||||
|
||||
if(!args_read_string_and_trim(args, cmd)) {
|
||||
furi_string_free(cmd);
|
||||
onewire_cli_print_usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "search") == 0) {
|
||||
onewire_cli_search(cli);
|
||||
}
|
||||
|
||||
furi_string_free(cmd);
|
||||
}
|
||||
@@ -73,29 +73,34 @@ uint32_t storage_data_get_timestamp(StorageData* storage) {
|
||||
|
||||
/****************** storage glue ******************/
|
||||
|
||||
bool storage_has_file(const File* file, StorageData* storage_data) {
|
||||
bool result = false;
|
||||
static StorageFile* storage_get_file(const File* file, StorageData* storage) {
|
||||
StorageFile* storage_file_ref = NULL;
|
||||
|
||||
StorageFileList_it_t it;
|
||||
for(StorageFileList_it(it, storage_data->files); !StorageFileList_end_p(it);
|
||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||
StorageFileList_next(it)) {
|
||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
||||
StorageFile* storage_file = StorageFileList_ref(it);
|
||||
|
||||
if(storage_file->file->file_id == file->file_id) {
|
||||
result = true;
|
||||
storage_file_ref = storage_file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return storage_file_ref;
|
||||
}
|
||||
|
||||
bool storage_path_already_open(FuriString* path, StorageFileList_t array) {
|
||||
bool storage_has_file(const File* file, StorageData* storage) {
|
||||
return storage_get_file(file, storage) != NULL;
|
||||
}
|
||||
|
||||
bool storage_path_already_open(FuriString* path, StorageData* storage) {
|
||||
bool open = false;
|
||||
|
||||
StorageFileList_it_t it;
|
||||
|
||||
for(StorageFileList_it(it, array); !StorageFileList_end_p(it); StorageFileList_next(it)) {
|
||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||
StorageFileList_next(it)) {
|
||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
||||
|
||||
if(furi_string_cmp(storage_file->path, path) == 0) {
|
||||
@@ -108,43 +113,15 @@ bool storage_path_already_open(FuriString* path, StorageFileList_t array) {
|
||||
}
|
||||
|
||||
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage) {
|
||||
StorageFile* founded_file = NULL;
|
||||
|
||||
StorageFileList_it_t it;
|
||||
|
||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||
StorageFileList_next(it)) {
|
||||
StorageFile* storage_file = StorageFileList_ref(it);
|
||||
|
||||
if(storage_file->file->file_id == file->file_id) {
|
||||
founded_file = storage_file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
furi_check(founded_file != NULL);
|
||||
|
||||
founded_file->file_data = file_data;
|
||||
StorageFile* storage_file_ref = storage_get_file(file, storage);
|
||||
furi_check(storage_file_ref != NULL);
|
||||
storage_file_ref->file_data = file_data;
|
||||
}
|
||||
|
||||
void* storage_get_storage_file_data(const File* file, StorageData* storage) {
|
||||
const StorageFile* founded_file = NULL;
|
||||
|
||||
StorageFileList_it_t it;
|
||||
|
||||
for(StorageFileList_it(it, storage->files); !StorageFileList_end_p(it);
|
||||
StorageFileList_next(it)) {
|
||||
const StorageFile* storage_file = StorageFileList_cref(it);
|
||||
|
||||
if(storage_file->file->file_id == file->file_id) {
|
||||
founded_file = storage_file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
furi_check(founded_file != NULL);
|
||||
|
||||
return founded_file->file_data;
|
||||
StorageFile* storage_file_ref = storage_get_file(file, storage);
|
||||
furi_check(storage_file_ref != NULL);
|
||||
return storage_file_ref->file_data;
|
||||
}
|
||||
|
||||
void storage_push_storage_file(File* file, FuriString* path, StorageData* storage) {
|
||||
|
||||
@@ -60,7 +60,7 @@ struct StorageData {
|
||||
};
|
||||
|
||||
bool storage_has_file(const File* file, StorageData* storage_data);
|
||||
bool storage_path_already_open(FuriString* path, StorageFileList_t files);
|
||||
bool storage_path_already_open(FuriString* path, StorageData* storage_data);
|
||||
|
||||
void storage_set_storage_file_data(const File* file, void* file_data, StorageData* storage);
|
||||
void* storage_get_storage_file_data(const File* file, StorageData* storage);
|
||||
|
||||
@@ -77,7 +77,7 @@ static void storage_path_change_to_real_storage(FuriString* path, StorageType re
|
||||
}
|
||||
}
|
||||
|
||||
FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
||||
static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** storage) {
|
||||
StorageType type = storage_get_type_by_path(path);
|
||||
|
||||
if(storage_type_is_valid(type)) {
|
||||
@@ -111,7 +111,7 @@ bool storage_process_file_open(
|
||||
file->error_id = storage_get_data(app, path, &storage);
|
||||
|
||||
if(file->error_id == FSE_OK) {
|
||||
if(storage_path_already_open(path, storage->files)) {
|
||||
if(storage_path_already_open(path, storage)) {
|
||||
file->error_id = FSE_ALREADY_OPEN;
|
||||
} else {
|
||||
if(access_mode & FSAM_WRITE) {
|
||||
@@ -268,7 +268,7 @@ bool storage_process_dir_open(Storage* app, File* file, FuriString* path) {
|
||||
file->error_id = storage_get_data(app, path, &storage);
|
||||
|
||||
if(file->error_id == FSE_OK) {
|
||||
if(storage_path_already_open(path, storage->files)) {
|
||||
if(storage_path_already_open(path, storage)) {
|
||||
file->error_id = FSE_ALREADY_OPEN;
|
||||
} else {
|
||||
storage_push_storage_file(file, path, storage);
|
||||
@@ -357,7 +357,7 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) {
|
||||
FS_Error ret = storage_get_data(app, path, &storage);
|
||||
|
||||
do {
|
||||
if(storage_path_already_open(path, storage->files)) {
|
||||
if(storage_path_already_open(path, storage)) {
|
||||
ret = FSE_ALREADY_OPEN;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -618,8 +618,10 @@ static const FS_Api fs_api = {
|
||||
};
|
||||
|
||||
void storage_ext_init(StorageData* storage) {
|
||||
fatfs_init();
|
||||
|
||||
SDData* sd_data = malloc(sizeof(SDData));
|
||||
sd_data->fs = &USERFatFS;
|
||||
sd_data->fs = &fatfs_object;
|
||||
sd_data->path = "0:/";
|
||||
sd_data->sd_was_present = true;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../bt_settings_app.h"
|
||||
#include <furi_hal_bt.h>
|
||||
#include <applications/main/bad_kb/bad_kb_app_i.h>
|
||||
#include <applications/main/bad_kb/bad_kb_settings_filename.h>
|
||||
|
||||
void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
// #define SCENE_EVENT_SELECT_FAVORITE_GAME 2
|
||||
#define SCENE_EVENT_SELECT_PIN_SETUP 2
|
||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3
|
||||
#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 4
|
||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_PIN 4
|
||||
#define SCENE_EVENT_SELECT_BATTERY_DISPLAY 5
|
||||
|
||||
#define AUTO_LOCK_DELAY_COUNT 9
|
||||
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||
|
||||
@@ -2,7 +2,6 @@ from dataclasses import dataclass
|
||||
from typing import Optional, Tuple, Dict, ClassVar
|
||||
import struct
|
||||
import posixpath
|
||||
import os
|
||||
import zlib
|
||||
|
||||
import gdb
|
||||
@@ -66,9 +65,9 @@ class AppState:
|
||||
def get_gdb_unload_command(self) -> str:
|
||||
return f"remove-symbol-file -a 0x{self.text_address:08x}"
|
||||
|
||||
def is_loaded_in_gdb(self, gdb_app) -> bool:
|
||||
# Avoid constructing full app wrapper for comparison
|
||||
return self.entry_address == int(gdb_app["state"]["entry"])
|
||||
@staticmethod
|
||||
def get_gdb_app_ep(app) -> int:
|
||||
return int(app["state"]["entry"])
|
||||
|
||||
@staticmethod
|
||||
def parse_debug_link_data(section_data: bytes) -> Tuple[str, int]:
|
||||
@@ -79,10 +78,10 @@ class AppState:
|
||||
crc32 = struct.unpack("<I", section_data[-4:])[0]
|
||||
return (elf_name, crc32)
|
||||
|
||||
@staticmethod
|
||||
def from_gdb(gdb_app: "AppState") -> "AppState":
|
||||
@classmethod
|
||||
def from_gdb(cls, gdb_app: "AppState") -> "AppState":
|
||||
state = AppState(str(gdb_app["manifest"]["name"].string()))
|
||||
state.entry_address = int(gdb_app["state"]["entry"])
|
||||
state.entry_address = cls.get_gdb_app_ep(gdb_app)
|
||||
|
||||
app_state = gdb_app["state"]
|
||||
if debug_link_size := int(app_state["debug_link_info"]["debug_link_size"]):
|
||||
@@ -123,59 +122,83 @@ class SetFapDebugElfRoot(gdb.Command):
|
||||
try:
|
||||
global helper
|
||||
print(f"Set '{arg}' as debug info lookup path for Flipper external apps")
|
||||
helper.attach_fw()
|
||||
helper.attach_to_fw()
|
||||
gdb.events.stop.connect(helper.handle_stop)
|
||||
gdb.events.exited.connect(helper.handle_exit)
|
||||
except gdb.error as e:
|
||||
print(f"Support for Flipper external apps debug is not available: {e}")
|
||||
|
||||
|
||||
SetFapDebugElfRoot()
|
||||
|
||||
|
||||
class FlipperAppDebugHelper:
|
||||
class FlipperAppStateHelper:
|
||||
def __init__(self):
|
||||
self.app_ptr = None
|
||||
self.app_type_ptr = None
|
||||
self.current_app: AppState = None
|
||||
self.app_list_ptr = None
|
||||
self.app_list_entry_type = None
|
||||
self._current_apps: list[AppState] = []
|
||||
|
||||
def attach_fw(self) -> None:
|
||||
self.app_ptr = gdb.lookup_global_symbol("last_loaded_app")
|
||||
self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer()
|
||||
self._check_app_state()
|
||||
def _walk_app_list(self, list_head):
|
||||
while list_head:
|
||||
if app := list_head["data"]:
|
||||
yield app.dereference()
|
||||
list_head = list_head["next"]
|
||||
|
||||
def _check_app_state(self) -> None:
|
||||
app_ptr_value = self.app_ptr.value()
|
||||
if not app_ptr_value and self.current_app:
|
||||
# There is an ELF loaded in GDB, but nothing is running on the device
|
||||
self._unload_debug_elf()
|
||||
elif app_ptr_value:
|
||||
# There is an app running on the device
|
||||
loaded_app = app_ptr_value.cast(self.app_type_ptr).dereference()
|
||||
|
||||
if self.current_app and not self.current_app.is_loaded_in_gdb(loaded_app):
|
||||
# Currently loaded ELF is not the one running on the device
|
||||
self._unload_debug_elf()
|
||||
|
||||
if not self.current_app:
|
||||
# Load ELF for the app running on the device
|
||||
self._load_debug_elf(loaded_app)
|
||||
|
||||
def _unload_debug_elf(self) -> None:
|
||||
def _exec_gdb_command(self, command: str) -> bool:
|
||||
try:
|
||||
gdb.execute(self.current_app.get_gdb_unload_command())
|
||||
gdb.execute(command)
|
||||
return True
|
||||
except gdb.error as e:
|
||||
print(f"Failed to unload debug ELF: {e} (might not be an error)")
|
||||
self.current_app = None
|
||||
print(f"Failed to execute GDB command '{command}': {e}")
|
||||
return False
|
||||
|
||||
def _load_debug_elf(self, app_object) -> None:
|
||||
self.current_app = AppState.from_gdb(app_object)
|
||||
def _sync_apps(self) -> None:
|
||||
self.set_debug_mode(True)
|
||||
if not (app_list := self.app_list_ptr.value()):
|
||||
print("Reset app loader state")
|
||||
for app in self._current_apps:
|
||||
self._exec_gdb_command(app.get_gdb_unload_command())
|
||||
self._current_apps = []
|
||||
return
|
||||
|
||||
if self.current_app.is_debug_available():
|
||||
gdb.execute(self.current_app.get_gdb_load_command())
|
||||
loaded_apps: dict[int, gdb.Value] = dict(
|
||||
(AppState.get_gdb_app_ep(app), app)
|
||||
for app in self._walk_app_list(app_list[0])
|
||||
)
|
||||
|
||||
for app in self._current_apps.copy():
|
||||
if app.entry_address not in loaded_apps:
|
||||
print(f"Application {app.name} is no longer loaded")
|
||||
if not self._exec_gdb_command(app.get_gdb_unload_command()):
|
||||
print(f"Failed to unload debug info for {app.name}")
|
||||
self._current_apps.remove(app)
|
||||
|
||||
for entry_point, app in loaded_apps.items():
|
||||
if entry_point not in set(app.entry_address for app in self._current_apps):
|
||||
new_app_state = AppState.from_gdb(app)
|
||||
print(f"New application loaded. Adding debug info")
|
||||
if self._exec_gdb_command(new_app_state.get_gdb_load_command()):
|
||||
self._current_apps.append(new_app_state)
|
||||
else:
|
||||
print(f"Failed to load debug info for {new_app_state}")
|
||||
|
||||
def attach_to_fw(self) -> None:
|
||||
print("Attaching to Flipper firmware")
|
||||
self.app_list_ptr = gdb.lookup_global_symbol(
|
||||
"flipper_application_loaded_app_list"
|
||||
)
|
||||
self.app_type_ptr = gdb.lookup_type("FlipperApplication").pointer()
|
||||
self.app_list_entry_type = gdb.lookup_type("struct FlipperApplicationList_s")
|
||||
|
||||
def handle_stop(self, event) -> None:
|
||||
self._check_app_state()
|
||||
self._sync_apps()
|
||||
|
||||
def handle_exit(self, event) -> None:
|
||||
self.set_debug_mode(False)
|
||||
|
||||
def set_debug_mode(self, mode: bool) -> None:
|
||||
gdb.execute(f"set variable fap_loader_debug_active = {int(mode)}")
|
||||
|
||||
|
||||
helper = FlipperAppDebugHelper()
|
||||
# Init additional 'fap-set-debug-elf-root' command and set up hooks
|
||||
SetFapDebugElfRoot()
|
||||
helper = FlipperAppStateHelper()
|
||||
print("Support for Flipper external apps debug is loaded")
|
||||
|
||||
@@ -151,6 +151,10 @@ Header,+,lib/mlib/m-list.h,,
|
||||
Header,+,lib/mlib/m-rbtree.h,,
|
||||
Header,+,lib/mlib/m-tuple.h,,
|
||||
Header,+,lib/mlib/m-variant.h,,
|
||||
Header,+,lib/one_wire/maxim_crc.h,,
|
||||
Header,+,lib/one_wire/one_wire_host.h,,
|
||||
Header,+,lib/one_wire/one_wire_host_timing.h,,
|
||||
Header,+,lib/one_wire/one_wire_slave.h,,
|
||||
Header,+,lib/print/wrappers.h,,
|
||||
Header,+,lib/toolbox/args.h,,
|
||||
Header,+,lib/toolbox/crc32_calc.h,,
|
||||
@@ -1394,6 +1398,7 @@ Function,+,manchester_advance,_Bool,"ManchesterState, ManchesterEvent, Mancheste
|
||||
Function,+,manchester_encoder_advance,_Bool,"ManchesterEncoderState*, const _Bool, ManchesterEncoderResult*"
|
||||
Function,+,manchester_encoder_finish,ManchesterEncoderResult,ManchesterEncoderState*
|
||||
Function,+,manchester_encoder_reset,void,ManchesterEncoderState*
|
||||
Function,+,maxim_crc8,uint8_t,"const uint8_t*, const uint8_t, const uint8_t"
|
||||
Function,-,mbedtls_des3_crypt_cbc,int,"mbedtls_des3_context*, int, size_t, unsigned char[8], const unsigned char*, unsigned char*"
|
||||
Function,-,mbedtls_des3_crypt_ecb,int,"mbedtls_des3_context*, const unsigned char[8], unsigned char[8]"
|
||||
Function,-,mbedtls_des3_free,void,mbedtls_des3_context*
|
||||
@@ -1472,6 +1477,32 @@ Function,+,notification_message,void,"NotificationApp*, const NotificationSequen
|
||||
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||
Function,-,nrand48,long,unsigned short[3]
|
||||
Function,-,on_exit,int,"void (*)(int, void*), void*"
|
||||
Function,+,onewire_host_alloc,OneWireHost*,const GpioPin*
|
||||
Function,+,onewire_host_free,void,OneWireHost*
|
||||
Function,+,onewire_host_read,uint8_t,OneWireHost*
|
||||
Function,+,onewire_host_read_bit,_Bool,OneWireHost*
|
||||
Function,+,onewire_host_read_bytes,void,"OneWireHost*, uint8_t*, uint16_t"
|
||||
Function,+,onewire_host_reset,_Bool,OneWireHost*
|
||||
Function,+,onewire_host_reset_search,void,OneWireHost*
|
||||
Function,+,onewire_host_search,uint8_t,"OneWireHost*, uint8_t*, OneWireHostSearchMode"
|
||||
Function,+,onewire_host_skip,void,OneWireHost*
|
||||
Function,+,onewire_host_start,void,OneWireHost*
|
||||
Function,+,onewire_host_stop,void,OneWireHost*
|
||||
Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t"
|
||||
Function,+,onewire_host_write,void,"OneWireHost*, uint8_t"
|
||||
Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool"
|
||||
Function,+,onewire_host_write_bytes,void,"OneWireHost*, const uint8_t*, uint16_t"
|
||||
Function,+,onewire_slave_alloc,OneWireSlave*,const GpioPin*
|
||||
Function,+,onewire_slave_free,void,OneWireSlave*
|
||||
Function,+,onewire_slave_receive,_Bool,"OneWireSlave*, uint8_t*, size_t"
|
||||
Function,+,onewire_slave_receive_bit,_Bool,OneWireSlave*
|
||||
Function,+,onewire_slave_send,_Bool,"OneWireSlave*, const uint8_t*, size_t"
|
||||
Function,+,onewire_slave_send_bit,_Bool,"OneWireSlave*, _Bool"
|
||||
Function,+,onewire_slave_set_command_callback,void,"OneWireSlave*, OneWireSlaveCommandCallback, void*"
|
||||
Function,+,onewire_slave_set_reset_callback,void,"OneWireSlave*, OneWireSlaveResetCallback, void*"
|
||||
Function,+,onewire_slave_set_result_callback,void,"OneWireSlave*, OneWireSlaveResultCallback, void*"
|
||||
Function,+,onewire_slave_start,void,OneWireSlave*
|
||||
Function,+,onewire_slave_stop,void,OneWireSlave*
|
||||
Function,-,open_memstream,FILE*,"char**, size_t*"
|
||||
Function,+,path_append,void,"FuriString*, const char*"
|
||||
Function,+,path_concat,void,"const char*, const char*, FuriString*"
|
||||
|
||||
|
@@ -3,8 +3,6 @@
|
||||
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <fatfs.h>
|
||||
|
||||
#define TAG "FuriHal"
|
||||
|
||||
void furi_hal_init_early() {
|
||||
@@ -74,10 +72,6 @@ void furi_hal_init() {
|
||||
#endif
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FatFS driver initialization
|
||||
MX_FATFS_Init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
}
|
||||
|
||||
void furi_hal_switch(void* address) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"usb_stm32",
|
||||
"appframe",
|
||||
"assets",
|
||||
"one_wire",
|
||||
"misc",
|
||||
"flipper_application",
|
||||
"flipperformat",
|
||||
@@ -45,11 +46,11 @@
|
||||
"furi_hal_subghz_configs.h"
|
||||
],
|
||||
"excluded_modules": [
|
||||
"one_wire",
|
||||
"nfc",
|
||||
"lfrfid",
|
||||
"subghz",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"st25rfal002"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,9 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
|
||||
Header,+,lib/flipper_application/plugins/plugin_manager.h,,
|
||||
Header,+,lib/flipper_format/flipper_format.h,,
|
||||
Header,+,lib/flipper_format/flipper_format_i.h,,
|
||||
Header,+,lib/ibutton/ibutton_key.h,,
|
||||
Header,+,lib/ibutton/ibutton_protocols.h,,
|
||||
Header,+,lib/ibutton/ibutton_worker.h,,
|
||||
Header,+,lib/infrared/encoder_decoder/infrared.h,,
|
||||
Header,+,lib/infrared/worker/infrared_transmit.h,,
|
||||
Header,+,lib/infrared/worker/infrared_worker.h,,
|
||||
@@ -175,9 +178,6 @@ Header,+,lib/mlib/m-rbtree.h,,
|
||||
Header,+,lib/mlib/m-tuple.h,,
|
||||
Header,+,lib/mlib/m-variant.h,,
|
||||
Header,+,lib/nfc/nfc_device.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_key.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_protocols.h,,
|
||||
Header,+,lib/one_wire/ibutton/ibutton_worker.h,,
|
||||
Header,+,lib/one_wire/maxim_crc.h,,
|
||||
Header,+,lib/one_wire/one_wire_host.h,,
|
||||
Header,+,lib/one_wire/one_wire_host_timing.h,,
|
||||
|
||||
|
@@ -18,22 +18,13 @@
|
||||
|
||||
#include "fatfs.h"
|
||||
|
||||
uint8_t retUSER; /* Return value for USER */
|
||||
char USERPath[4]; /* USER logical drive path */
|
||||
FATFS USERFatFS; /* File system object for USER logical drive */
|
||||
FIL USERFile; /* File object for USER */
|
||||
/** logical drive path */
|
||||
char fatfs_path[4];
|
||||
/** File system object */
|
||||
FATFS fatfs_object;
|
||||
|
||||
/* USER CODE BEGIN Variables */
|
||||
|
||||
/* USER CODE END Variables */
|
||||
|
||||
void MX_FATFS_Init(void) {
|
||||
/*## FatFS: Link the USER driver ###########################*/
|
||||
retUSER = FATFS_LinkDriver(&USER_Driver, USERPath);
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
/* additional user code for init */
|
||||
/* USER CODE END Init */
|
||||
void fatfs_init(void) {
|
||||
FATFS_LinkDriver(&sd_fatfs_driver, fatfs_path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,13 +33,7 @@ void MX_FATFS_Init(void) {
|
||||
* @retval Time in DWORD
|
||||
*/
|
||||
DWORD get_fattime(void) {
|
||||
/* USER CODE BEGIN get_fattime */
|
||||
return 0;
|
||||
/* USER CODE END get_fattime */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Application */
|
||||
|
||||
/* USER CODE END Application */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -16,34 +16,24 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __fatfs_H
|
||||
#define __fatfs_H
|
||||
#pragma once
|
||||
|
||||
#include "fatfs/ff.h"
|
||||
#include "fatfs/ff_gen_drv.h"
|
||||
#include "user_diskio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "fatfs/ff.h"
|
||||
#include "fatfs/ff_gen_drv.h"
|
||||
#include "user_diskio.h" /* defines USER_Driver as external */
|
||||
/** File system object */
|
||||
extern FATFS fatfs_object;
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
/** Init file system driver */
|
||||
void fatfs_init(void);
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern uint8_t retUSER; /* Return value for USER */
|
||||
extern char USERPath[4]; /* USER logical drive path */
|
||||
extern FATFS USERFatFS; /* File system object for USER logical drive */
|
||||
extern FIL USERFile; /* File object for USER */
|
||||
|
||||
void MX_FATFS_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__fatfs_H */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
|
||||
/* USER CODE BEGIN Volumes */
|
||||
#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
|
||||
#define _VOLUME_STRS "RAM", "NAND", "CF", "SD1", "SD2", "USB1", "USB2", "USB3"
|
||||
#define _VOLUME_STRS "SD"
|
||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample code of OS dependent controls for FatFs */
|
||||
/* (C)ChaN, 2014 */
|
||||
/* Portions COPYRIGHT 2017 STMicroelectronics */
|
||||
/* Portions Copyright (C) 2014, ChaN, all right reserved */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics. All rights reserved.
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
**/
|
||||
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#if _FS_REENTRANT
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_cre_syncobj(/* 1:Function succeeded, 0:Could not create the sync object */
|
||||
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||
_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||
) {
|
||||
int ret;
|
||||
|
||||
//osSemaphoreDef(SEM);
|
||||
//*sobj = osSemaphoreCreate(osSemaphore(SEM), 1);
|
||||
*sobj = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
ret = (*sobj != NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj(/* 1:Function succeeded, 0:Could not delete due to any error */
|
||||
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
) {
|
||||
furi_mutex_free(sobj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant(/* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
_SYNC_t sobj /* Sync object to wait */
|
||||
) {
|
||||
int ret = 0;
|
||||
|
||||
if(furi_mutex_acquire(sobj, _FS_TIMEOUT) == FuriStatusOk) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant(_SYNC_t sobj /* Sync object to be signaled */
|
||||
) {
|
||||
furi_mutex_release(sobj);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
|
||||
*/
|
||||
|
||||
void* ff_memalloc(/* Returns pointer to the allocated memory block */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
) {
|
||||
return ff_malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree(void* mblock /* Pointer to the memory block to free */
|
||||
) {
|
||||
ff_free(mblock); /* Discard the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -18,33 +18,13 @@
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
|
||||
/*
|
||||
* Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)
|
||||
* To be suppressed in the future.
|
||||
* Kept to ensure backward compatibility with previous CubeMx versions when
|
||||
* migrating projects.
|
||||
* User code previously added there should be copied in the new user sections before
|
||||
* the section contents can be deleted.
|
||||
*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
/* USER CODE END 0 */
|
||||
#endif
|
||||
|
||||
/* USER CODE BEGIN DECL */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "user_diskio.h"
|
||||
#include <furi_hal.h>
|
||||
#include "sector_cache.h"
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Disk status */
|
||||
static volatile DSTATUS Stat = STA_NOINIT;
|
||||
|
||||
static DSTATUS User_CheckStatus(BYTE lun) {
|
||||
static DSTATUS driver_check_status(BYTE lun) {
|
||||
UNUSED(lun);
|
||||
Stat = STA_NOINIT;
|
||||
if(sd_get_card_state() == SdSpiStatusOK) {
|
||||
@@ -54,32 +34,20 @@ static DSTATUS User_CheckStatus(BYTE lun) {
|
||||
return Stat;
|
||||
}
|
||||
|
||||
/* USER CODE END DECL */
|
||||
static DSTATUS driver_initialize(BYTE pdrv);
|
||||
static DSTATUS driver_status(BYTE pdrv);
|
||||
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
DSTATUS USER_initialize(BYTE pdrv);
|
||||
DSTATUS USER_status(BYTE pdrv);
|
||||
DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
#if _USE_WRITE == 1
|
||||
DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
#endif /* _USE_WRITE == 1 */
|
||||
#if _USE_IOCTL == 1
|
||||
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff);
|
||||
#endif /* _USE_IOCTL == 1 */
|
||||
|
||||
Diskio_drvTypeDef USER_Driver = {
|
||||
USER_initialize,
|
||||
USER_status,
|
||||
USER_read,
|
||||
#if _USE_WRITE
|
||||
USER_write,
|
||||
#endif /* _USE_WRITE == 1 */
|
||||
#if _USE_IOCTL == 1
|
||||
USER_ioctl,
|
||||
#endif /* _USE_IOCTL == 1 */
|
||||
Diskio_drvTypeDef sd_fatfs_driver = {
|
||||
driver_initialize,
|
||||
driver_status,
|
||||
driver_read,
|
||||
driver_write,
|
||||
driver_ioctl,
|
||||
};
|
||||
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
static inline bool sd_cache_get(uint32_t address, uint32_t* data) {
|
||||
uint8_t* cached_data = sector_cache_get(address);
|
||||
if(cached_data) {
|
||||
@@ -101,24 +69,73 @@ static inline void sd_cache_invalidate_all() {
|
||||
sector_cache_init();
|
||||
}
|
||||
|
||||
static bool sd_device_read(uint32_t* buff, uint32_t sector, uint32_t count) {
|
||||
bool result = false;
|
||||
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||
|
||||
if(sd_read_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||
|
||||
/* wait until the read operation is finished */
|
||||
result = true;
|
||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_sd_spi_handle = NULL;
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool sd_device_write(uint32_t* buff, uint32_t sector, uint32_t count) {
|
||||
bool result = false;
|
||||
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||
|
||||
if(sd_write_blocks(buff, sector, count, SD_TIMEOUT_MS) == SdSpiStatusOK) {
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||
|
||||
/* wait until the Write operation is finished */
|
||||
result = true;
|
||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
sd_cache_invalidate_all();
|
||||
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_sd_spi_handle = NULL;
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a Drive
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @retval DSTATUS: Operation status
|
||||
*/
|
||||
DSTATUS USER_initialize(BYTE pdrv) {
|
||||
/* USER CODE BEGIN INIT */
|
||||
|
||||
static DSTATUS driver_initialize(BYTE pdrv) {
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||
|
||||
DSTATUS status = User_CheckStatus(pdrv);
|
||||
DSTATUS status = driver_check_status(pdrv);
|
||||
|
||||
furi_hal_sd_spi_handle = NULL;
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
return status;
|
||||
/* USER CODE END INIT */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,11 +143,9 @@ DSTATUS USER_initialize(BYTE pdrv) {
|
||||
* @param pdrv: Physical drive number (0..)
|
||||
* @retval DSTATUS: Operation status
|
||||
*/
|
||||
DSTATUS USER_status(BYTE pdrv) {
|
||||
/* USER CODE BEGIN STATUS */
|
||||
static DSTATUS driver_status(BYTE pdrv) {
|
||||
UNUSED(pdrv);
|
||||
return Stat;
|
||||
/* USER CODE END STATUS */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,11 +156,10 @@ DSTATUS USER_status(BYTE pdrv) {
|
||||
* @param count: Number of sectors to read (1..128)
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
||||
/* USER CODE BEGIN READ */
|
||||
static DRESULT driver_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
||||
UNUSED(pdrv);
|
||||
DRESULT res = RES_ERROR;
|
||||
|
||||
bool result;
|
||||
bool single_sector = count == 1;
|
||||
|
||||
if(single_sector) {
|
||||
@@ -154,32 +168,33 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
|
||||
|
||||
if(sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
|
||||
SdSpiStatusOK) {
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||
if(!result) {
|
||||
uint8_t counter = sd_max_mount_retry_count();
|
||||
|
||||
/* wait until the read operation is finished */
|
||||
res = RES_OK;
|
||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
res = RES_ERROR;
|
||||
break;
|
||||
while(result == false && counter > 0 && hal_sd_detect()) {
|
||||
SdSpiStatus status;
|
||||
|
||||
if((counter % 2) == 0) {
|
||||
// power reset sd card
|
||||
status = sd_init(true);
|
||||
} else {
|
||||
status = sd_init(false);
|
||||
}
|
||||
|
||||
if(status == SdSpiStatusOK) {
|
||||
result = sd_device_read((uint32_t*)buff, (uint32_t)(sector), count);
|
||||
}
|
||||
counter--;
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_sd_spi_handle = NULL;
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
if(single_sector && res == RES_OK) {
|
||||
if(single_sector && result == true) {
|
||||
sd_cache_put(sector, (uint32_t*)buff);
|
||||
}
|
||||
|
||||
return res;
|
||||
/* USER CODE END READ */
|
||||
return result ? RES_OK : RES_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,41 +205,36 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
|
||||
* @param count: Number of sectors to write (1..128)
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
#if _USE_WRITE == 1
|
||||
DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
||||
/* USER CODE BEGIN WRITE */
|
||||
/* USER CODE HERE */
|
||||
static DRESULT driver_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
||||
UNUSED(pdrv);
|
||||
DRESULT res = RES_ERROR;
|
||||
bool result;
|
||||
|
||||
sd_cache_invalidate_range(sector, sector + count);
|
||||
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast);
|
||||
furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast;
|
||||
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
|
||||
|
||||
if(sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) ==
|
||||
SdSpiStatusOK) {
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000);
|
||||
if(!result) {
|
||||
uint8_t counter = sd_max_mount_retry_count();
|
||||
|
||||
/* wait until the Write operation is finished */
|
||||
res = RES_OK;
|
||||
while(sd_get_card_state() != SdSpiStatusOK) {
|
||||
if(furi_hal_cortex_timer_is_expired(timer)) {
|
||||
sd_cache_invalidate_all();
|
||||
while(result == false && counter > 0 && hal_sd_detect()) {
|
||||
SdSpiStatus status;
|
||||
|
||||
res = RES_ERROR;
|
||||
break;
|
||||
if((counter % 2) == 0) {
|
||||
// power reset sd card
|
||||
status = sd_init(true);
|
||||
} else {
|
||||
status = sd_init(false);
|
||||
}
|
||||
|
||||
if(status == SdSpiStatusOK) {
|
||||
result = sd_device_write((uint32_t*)buff, (uint32_t)(sector), count);
|
||||
}
|
||||
counter--;
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_sd_spi_handle = NULL;
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
return res;
|
||||
/* USER CODE END WRITE */
|
||||
return result ? RES_OK : RES_ERROR;
|
||||
}
|
||||
#endif /* _USE_WRITE == 1 */
|
||||
|
||||
/**
|
||||
* @brief I/O control operation
|
||||
@@ -233,9 +243,7 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
|
||||
* @param *buff: Buffer to send/receive control data
|
||||
* @retval DRESULT: Operation result
|
||||
*/
|
||||
#if _USE_IOCTL == 1
|
||||
DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
||||
/* USER CODE BEGIN IOCTL */
|
||||
static DRESULT driver_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
||||
UNUSED(pdrv);
|
||||
DRESULT res = RES_ERROR;
|
||||
SD_CardInfo CardInfo;
|
||||
@@ -280,8 +288,6 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast);
|
||||
|
||||
return res;
|
||||
/* USER CODE END IOCTL */
|
||||
}
|
||||
#endif /* _USE_IOCTL == 1 */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -19,30 +19,19 @@
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USER_DISKIO_H
|
||||
#define __USER_DISKIO_H
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "sd_spi_io.h"
|
||||
#include "fatfs/ff_gen_drv.h"
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
extern Diskio_drvTypeDef USER_Driver;
|
||||
|
||||
/* USER CODE END 0 */
|
||||
extern Diskio_drvTypeDef sd_fatfs_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USER_DISKIO_H */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
|
||||
#include <fatfs.h>
|
||||
|
||||
#define TAG "FuriHal"
|
||||
|
||||
void furi_hal_init_early() {
|
||||
@@ -80,10 +78,6 @@ void furi_hal_init() {
|
||||
furi_hal_nfc_init();
|
||||
furi_hal_rfid_init();
|
||||
#endif
|
||||
|
||||
// FatFS driver initialization
|
||||
MX_FATFS_Init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
}
|
||||
|
||||
void furi_hal_switch(void* address) {
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#define HID_EP_OUT 0x01
|
||||
#define HID_EP_SZ 0x10
|
||||
|
||||
#define HID_KB_MAX_KEYS 6
|
||||
#define HID_CONSUMER_MAX_KEYS 2
|
||||
|
||||
#define HID_INTERVAL 2
|
||||
|
||||
#define HID_VID_DEFAULT 0x046D
|
||||
|
||||
@@ -44,7 +44,7 @@ static bool flipper_update_init() {
|
||||
|
||||
furi_hal_spi_config_init();
|
||||
|
||||
MX_FATFS_Init();
|
||||
fatfs_init();
|
||||
if(!hal_sd_detect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"appframe",
|
||||
"assets",
|
||||
"one_wire",
|
||||
"ibutton",
|
||||
"misc",
|
||||
"mbedtls",
|
||||
"lfrfid",
|
||||
@@ -42,4 +43,4 @@
|
||||
"flipperformat",
|
||||
"toolbox"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Max number of simultaneously pressed keys (keyboard) */
|
||||
#define HID_KB_MAX_KEYS 6
|
||||
/** Max number of simultaneously pressed keys (consumer control) */
|
||||
#define HID_CONSUMER_MAX_KEYS 2
|
||||
|
||||
#define HID_KEYBOARD_NONE 0x00
|
||||
|
||||
/** HID keyboard modifier keys */
|
||||
|
||||
@@ -89,6 +89,7 @@ libs = env.BuildModules(
|
||||
"fatfs",
|
||||
"flipper_format",
|
||||
"one_wire",
|
||||
"ibutton",
|
||||
"infrared",
|
||||
"littlefs",
|
||||
"mbedtls",
|
||||
|
||||
@@ -830,8 +830,9 @@ void elf_file_init_debug_info(ELFFile* elf, ELFDebugInfo* debug_info) {
|
||||
|
||||
const void* data_ptr = itref->value.data;
|
||||
if(data_ptr) {
|
||||
debug_info->mmap_entries[mmap_entry_idx].address = (uint32_t)data_ptr;
|
||||
debug_info->mmap_entries[mmap_entry_idx].name = itref->key;
|
||||
ELFMemoryMapEntry* entry = &debug_info->mmap_entries[mmap_entry_idx];
|
||||
entry->address = (uint32_t)data_ptr;
|
||||
entry->name = itref->key;
|
||||
mmap_entry_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <notification/notification_messages.h>
|
||||
#include "application_assets.h"
|
||||
|
||||
#define TAG "fapp"
|
||||
#include <m-list.h>
|
||||
|
||||
#define TAG "Fap"
|
||||
|
||||
struct FlipperApplication {
|
||||
ELFDebugInfo state;
|
||||
@@ -13,8 +15,39 @@ struct FlipperApplication {
|
||||
void* ep_thread_args;
|
||||
};
|
||||
|
||||
/* For debugger access to app state */
|
||||
FlipperApplication* last_loaded_app = NULL;
|
||||
/********************** Debugger access to loader state **********************/
|
||||
|
||||
LIST_DEF(FlipperApplicationList, const FlipperApplication*, M_POD_OPLIST);
|
||||
|
||||
FlipperApplicationList_t flipper_application_loaded_app_list = {0};
|
||||
static bool flipper_application_loaded_app_list_initialized = false;
|
||||
|
||||
static void flipper_application_list_add_app(const FlipperApplication* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(!flipper_application_loaded_app_list_initialized) {
|
||||
FlipperApplicationList_init(flipper_application_loaded_app_list);
|
||||
flipper_application_loaded_app_list_initialized = true;
|
||||
}
|
||||
FlipperApplicationList_push_back(flipper_application_loaded_app_list, app);
|
||||
}
|
||||
|
||||
static void flipper_application_list_remove_app(const FlipperApplication* app) {
|
||||
furi_assert(flipper_application_loaded_app_list_initialized);
|
||||
furi_assert(app);
|
||||
|
||||
FlipperApplicationList_it_t it;
|
||||
for(FlipperApplicationList_it(it, flipper_application_loaded_app_list);
|
||||
!FlipperApplicationList_end_p(it);
|
||||
FlipperApplicationList_next(it)) {
|
||||
if(*FlipperApplicationList_ref(it) == app) {
|
||||
FlipperApplicationList_remove(flipper_application_loaded_app_list, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
FlipperApplication*
|
||||
flipper_application_alloc(Storage* storage, const ElfApiInterface* api_interface) {
|
||||
@@ -37,8 +70,8 @@ void flipper_application_free(FlipperApplication* app) {
|
||||
furi_thread_free(app->thread);
|
||||
}
|
||||
|
||||
if(!flipper_application_is_plugin(app)) {
|
||||
last_loaded_app = NULL;
|
||||
if(app->state.entry) {
|
||||
flipper_application_list_remove_app(app);
|
||||
}
|
||||
|
||||
elf_file_clear_debug_info(&app->state);
|
||||
@@ -153,14 +186,12 @@ const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplic
|
||||
}
|
||||
|
||||
FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app) {
|
||||
if(!flipper_application_is_plugin(app)) {
|
||||
last_loaded_app = app;
|
||||
}
|
||||
ELFFileLoadStatus status = elf_file_load_sections(app->elf);
|
||||
|
||||
switch(status) {
|
||||
case ELFFileLoadStatusSuccess:
|
||||
elf_file_init_debug_info(app->elf, &app->state);
|
||||
flipper_application_list_add_app(app);
|
||||
return FlipperApplicationLoadStatusSuccess;
|
||||
case ELFFileLoadStatusNoFreeMemory:
|
||||
return FlipperApplicationLoadStatusNoFreeMemory;
|
||||
|
||||
24
lib/ibutton/SConscript
Normal file
24
lib/ibutton/SConscript
Normal file
@@ -0,0 +1,24 @@
|
||||
Import("env")
|
||||
|
||||
env.Append(
|
||||
LINT_SOURCES=[
|
||||
Dir("."),
|
||||
],
|
||||
CPPPATH=[
|
||||
"#/lib/ibutton",
|
||||
],
|
||||
SDK_HEADERS=[
|
||||
File("ibutton_key.h"),
|
||||
File("ibutton_worker.h"),
|
||||
File("ibutton_protocols.h"),
|
||||
],
|
||||
)
|
||||
|
||||
libenv = env.Clone(FW_LIB_NAME="ibutton")
|
||||
libenv.ApplyLibFlags()
|
||||
|
||||
sources = libenv.GlobRecursive("*.c*")
|
||||
|
||||
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
|
||||
libenv.Install("${LIB_DIST_DIR}", lib)
|
||||
Return("lib")
|
||||
@@ -85,7 +85,7 @@ bool dallas_common_read_mem(OneWireHost* host, uint16_t address, uint8_t* data,
|
||||
onewire_host_write(host, DALLAS_COMMON_CMD_READ_MEM);
|
||||
|
||||
onewire_host_write(host, (uint8_t)address);
|
||||
onewire_host_write(host, (uint8_t)(address > BITS_IN_BYTE));
|
||||
onewire_host_write(host, (uint8_t)(address >> BITS_IN_BYTE));
|
||||
|
||||
onewire_host_read_bytes(host, data, (uint16_t)data_size);
|
||||
|
||||
144
lib/ibutton/protocols/dallas/protocol_ds1420.c
Normal file
144
lib/ibutton/protocols/dallas/protocol_ds1420.c
Normal file
@@ -0,0 +1,144 @@
|
||||
#include "protocol_ds1420.h"
|
||||
|
||||
#include <core/string.h>
|
||||
#include <core/core_defines.h>
|
||||
|
||||
#include "dallas_common.h"
|
||||
|
||||
#include "../blanks/rw1990.h"
|
||||
#include "../blanks/tm2004.h"
|
||||
|
||||
#define DS1420_FAMILY_CODE 0x81U
|
||||
#define DS1420_FAMILY_NAME "DS1420"
|
||||
|
||||
#define DS1420_CMD_READ_ROM 0x0FU
|
||||
|
||||
typedef struct {
|
||||
OneWireSlave* bus;
|
||||
} DS1420ProtocolState;
|
||||
|
||||
typedef struct {
|
||||
DallasCommonRomData rom_data;
|
||||
DS1420ProtocolState state;
|
||||
} DS1420ProtocolData;
|
||||
|
||||
static bool dallas_ds1420_read(OneWireHost*, iButtonProtocolData*);
|
||||
static bool dallas_ds1420_write_blank(OneWireHost*, iButtonProtocolData*);
|
||||
static void dallas_ds1420_emulate(OneWireSlave*, iButtonProtocolData*);
|
||||
static bool dallas_ds1420_load(FlipperFormat*, uint32_t, iButtonProtocolData*);
|
||||
static bool dallas_ds1420_save(FlipperFormat*, const iButtonProtocolData*);
|
||||
static void dallas_ds1420_render_brief_data(FuriString*, const iButtonProtocolData*);
|
||||
static void dallas_ds1420_render_error(FuriString*, const iButtonProtocolData*);
|
||||
static bool dallas_ds1420_is_data_valid(const iButtonProtocolData*);
|
||||
static void dallas_ds1420_get_editable_data(iButtonEditableData*, iButtonProtocolData*);
|
||||
static void dallas_ds1420_apply_edits(iButtonProtocolData*);
|
||||
|
||||
const iButtonProtocolDallasBase ibutton_protocol_ds1420 = {
|
||||
.family_code = DS1420_FAMILY_CODE,
|
||||
.features = iButtonProtocolFeatureWriteBlank,
|
||||
.data_size = sizeof(DS1420ProtocolData),
|
||||
.manufacturer = DALLAS_COMMON_MANUFACTURER_NAME,
|
||||
.name = DS1420_FAMILY_NAME,
|
||||
|
||||
.read = dallas_ds1420_read,
|
||||
.write_blank = dallas_ds1420_write_blank,
|
||||
.write_copy = NULL, /* No data to write a copy */
|
||||
.emulate = dallas_ds1420_emulate,
|
||||
.save = dallas_ds1420_save,
|
||||
.load = dallas_ds1420_load,
|
||||
.render_data = NULL, /* No data to render */
|
||||
.render_brief_data = dallas_ds1420_render_brief_data,
|
||||
.render_error = dallas_ds1420_render_error,
|
||||
.is_valid = dallas_ds1420_is_data_valid,
|
||||
.get_editable_data = dallas_ds1420_get_editable_data,
|
||||
.apply_edits = dallas_ds1420_apply_edits,
|
||||
};
|
||||
|
||||
bool dallas_ds1420_read(OneWireHost* host, iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
return onewire_host_reset(host) && dallas_common_read_rom(host, &data->rom_data);
|
||||
}
|
||||
|
||||
bool dallas_ds1420_write_blank(OneWireHost* host, iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
|
||||
return rw1990_write_v1(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) ||
|
||||
rw1990_write_v2(host, data->rom_data.bytes, sizeof(DallasCommonRomData)) ||
|
||||
tm2004_write(host, data->rom_data.bytes, sizeof(DallasCommonRomData));
|
||||
}
|
||||
|
||||
static bool dallas_ds1420_command_callback(uint8_t command, void* context) {
|
||||
furi_assert(context);
|
||||
DS1420ProtocolData* data = context;
|
||||
OneWireSlave* bus = data->state.bus;
|
||||
|
||||
switch(command) {
|
||||
case DALLAS_COMMON_CMD_SEARCH_ROM:
|
||||
dallas_common_emulate_search_rom(bus, &data->rom_data);
|
||||
break;
|
||||
case DALLAS_COMMON_CMD_READ_ROM:
|
||||
case DS1420_CMD_READ_ROM:
|
||||
dallas_common_emulate_read_rom(bus, &data->rom_data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// No support for multiple consecutive commands
|
||||
return false;
|
||||
}
|
||||
|
||||
void dallas_ds1420_emulate(OneWireSlave* bus, iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
data->state.bus = bus;
|
||||
|
||||
onewire_slave_set_reset_callback(bus, NULL, NULL);
|
||||
onewire_slave_set_command_callback(bus, dallas_ds1420_command_callback, protocol_data);
|
||||
}
|
||||
|
||||
bool dallas_ds1420_save(FlipperFormat* ff, const iButtonProtocolData* protocol_data) {
|
||||
const DS1420ProtocolData* data = protocol_data;
|
||||
return dallas_common_save_rom_data(ff, &data->rom_data);
|
||||
}
|
||||
|
||||
bool dallas_ds1420_load(
|
||||
FlipperFormat* ff,
|
||||
uint32_t format_version,
|
||||
iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
return dallas_common_load_rom_data(ff, format_version, &data->rom_data);
|
||||
}
|
||||
|
||||
void dallas_ds1420_render_brief_data(FuriString* result, const iButtonProtocolData* protocol_data) {
|
||||
const DS1420ProtocolData* data = protocol_data;
|
||||
|
||||
for(size_t i = 0; i < sizeof(DallasCommonRomData); ++i) {
|
||||
furi_string_cat_printf(result, "%02X ", data->rom_data.bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void dallas_ds1420_render_error(FuriString* result, const iButtonProtocolData* protocol_data) {
|
||||
const DS1420ProtocolData* data = protocol_data;
|
||||
|
||||
if(!dallas_common_is_valid_crc(&data->rom_data)) {
|
||||
dallas_common_render_crc_error(result, &data->rom_data);
|
||||
}
|
||||
}
|
||||
|
||||
bool dallas_ds1420_is_data_valid(const iButtonProtocolData* protocol_data) {
|
||||
const DS1420ProtocolData* data = protocol_data;
|
||||
return dallas_common_is_valid_crc(&data->rom_data);
|
||||
}
|
||||
|
||||
void dallas_ds1420_get_editable_data(
|
||||
iButtonEditableData* editable_data,
|
||||
iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
editable_data->ptr = data->rom_data.bytes;
|
||||
editable_data->size = sizeof(DallasCommonRomData);
|
||||
}
|
||||
|
||||
void dallas_ds1420_apply_edits(iButtonProtocolData* protocol_data) {
|
||||
DS1420ProtocolData* data = protocol_data;
|
||||
dallas_common_apply_edits(&data->rom_data, DS1420_FAMILY_CODE);
|
||||
}
|
||||
5
lib/ibutton/protocols/dallas/protocol_ds1420.h
Normal file
5
lib/ibutton/protocols/dallas/protocol_ds1420.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "protocol_dallas_base.h"
|
||||
|
||||
extern const iButtonProtocolDallasBase ibutton_protocol_ds1420;
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "protocol_ds1992.h"
|
||||
#include "protocol_ds1996.h"
|
||||
#include "protocol_ds1971.h"
|
||||
#include "protocol_ds1420.h"
|
||||
#include "protocol_ds_generic.h"
|
||||
|
||||
const iButtonProtocolDallasBase* ibutton_protocols_dallas[] = {
|
||||
@@ -11,6 +12,7 @@ const iButtonProtocolDallasBase* ibutton_protocols_dallas[] = {
|
||||
[iButtonProtocolDS1992] = &ibutton_protocol_ds1992,
|
||||
[iButtonProtocolDS1996] = &ibutton_protocol_ds1996,
|
||||
[iButtonProtocolDS1971] = &ibutton_protocol_ds1971,
|
||||
[iButtonProtocolDS1420] = &ibutton_protocol_ds1420,
|
||||
/* Add new 1-Wire protocols here */
|
||||
|
||||
/* Default catch-all 1-Wire protocol */
|
||||
@@ -7,6 +7,7 @@ typedef enum {
|
||||
iButtonProtocolDS1992,
|
||||
iButtonProtocolDS1996,
|
||||
iButtonProtocolDS1971,
|
||||
iButtonProtocolDS1420,
|
||||
/* Add new 1-Wire protocols here */
|
||||
|
||||
/* Default catch-all 1-Wire protocol */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user