Merge remote-tracking branch 'mntm/dev' into mntm-pr-322

This commit is contained in:
Willy-JL
2025-01-17 00:08:35 +00:00
969 changed files with 2228 additions and 440 deletions
+38 -5
View File
@@ -1,22 +1,42 @@
### Breaking Changes:
- Lockscreen: Separate 'Allow RPC While Locked' settings for USB/BLE (#343 by @956MB)
- Both default to OFF like before
- If you had enabled this option before, you will need to re-enable
### Added:
- Apps:
- Games: Pinball0 (by @rdefeo)
- NFC: Metroflip (by @luu176)
- CLI: Add `clear` and `cls` commands, add `did you mean ...?` command suggestion (#342 by @dexvleads)
- Main Menu: Add coverflow menu style (#314 by @CodyTolene)
- BadKB: Added german Mac keyboard Layout (#325 by @Cloudy261)
- UL: Sub-GHz: Jolly Motors support with add manually (by @pkooiman & @xMasterX)
- OFW: Desktop: Add winter animations (by @Astrrra)
- API:
- Added `canvas_draw_icon_animation_ex()` to draw animated icons resized (#314 by @CodyTolene)
- OFW: Added `flipper_format_write_empty_line()` (by @janwiesemann)
- OFW: Furi: Pipe support (by @portasynthinca3)
- OFW: Furi: Thread stdin support (by @portasynthinca3)
- OFW: RPC: Command to send a signal once (by @Astrrra)
- OFW: Add VCP break support (by @gsurkov)
### Updated:
- Apps:
- BT/USB Remote: Add PTT support for Gather (by @SapphicCode)
- Chess: Fix illegal move bug (by @956MB)
- Color Guess: Simplify app code (by @leedave)
- Countdown Timer: Default to 60 seconds on open (by @andrejka27)
- Cross Remote: Fix Sub-GHz actions rolling code support, animations for transmit, allow interrupting chain (by @leedave), loop transmit feature (by @miccayo)
- ESP Flasher: Add c3 and c6 to s3 option (by @jaylikesbunda), update Marauder bins to 1.1.0 (by @justcallmekoko)
- FlipBIP: Refactor to make adding coins easier (by @xtruan)
- FlipLibrary: Wikipedia, dog facts, random quotes, weather, asset price, predictions, trivia, advice, uuid and many more, bug fixes (by @jblanked), holidays, improvements to connectivity and progress (by @jamisonderek)
- FlipSocial: Improved authentication, loading screens, memory fixes, bio and friend counts, search contacts (by @jblanked), RPC_KEYBOAARD support (by @jamisonderek)
- FlipStore: Many bugfixes, support ESP32 firmware downloads, allow deleting apps, memory fixes, update Marauder (by @jblanked), more improvements (by @jamisonderek)
- FlipSocial: Improved authentication, loading screens, memory fixes, bio and friend counts, new feed screen with posted time, search users and contacts, home announcements and notifications, private feed option, endless feed (by @jblanked), RPC_KEYBOARD support (by @jamisonderek)
- FlipStore: Many bugfixes, support downloading ESP32 and VGM firmwares and Github repos, allow deleting apps, memory fixes, update Marauder, use Flipper catalog API (by @jblanked), more improvements (by @jamisonderek)
- FlipTrader: Improved progress display, added connectivity check on startup (by @jamisonderek)
- FlipWeather: Stability improvements (by @jblanked), improved progress display, added connectivity check on startup (by @jamisonderek)
- FlipWiFi: Improve error handling, update scan loading and parsing, fix crash when saving networks manually (by @jblanked), add connectivity check on startup (by @jamisonderek)
- FlipWiFi: Improve error handling, update scan loading and parsing, fix crash when saving networks manually, max 100 network scan, add some fast commands (by @jblanked), add connectivity check on startup (by @jamisonderek)
- Oscilloscope: Add simple spectrum analyser and basic software scaling support (by @anfractuosity)
- Picopass: Handle write key retry when a different card is presented (by @bettse)
- Pokemon Trade Tool: Update to gblink v0.63 which includes saving/loading of pin configurations for the EXT link interface (by @kbembedded)
- Snake 2.0: Progress saving, endless mode, game timer, fruit positioning bugfixes (by @Willzvul)
- uPython: Enabled extra functions for the `random` module (by @ofabel)
@@ -25,6 +45,7 @@
- UL: NFC Magic: Added possibility to write 7b MFC to Gen1 tags (by @mishamyte)
- UL: Unitemp: Fixed handling of hPa units (by @shininghero)
- UL: Fixed apps for firmware USB CDC callback changes (by @xMasterX)
- Infrared: Update universal bluray remote (#348 by @jaylikesbunda)
- NFC:
- OFW: Replace mf_classic_dict.nfc with Proxmark3 version (by @onovy)
- OFW: More station IDs for Clipper plugin (by @ted-logan)
@@ -32,10 +53,22 @@
### Fixed:
- Desktop: Fixed Wardriving animation design (by @Davim09)
- Main Menu: Fix MNTM style battery percent off by 1 (#339 by @956MB)
- OFW: Fix lost BadBLE keystrokes (by @Astrrra)
- OFW: GPIO: Fix USB UART Bridge Crash by increasing system stack size (by @Astrrra)
- OFW: Loader: Fix BusFault in handling of OOM (by @Willy-JL)
- NFC:
- XERO: Fix issue with MFC key recovery state machine performing key reuse early (by @noproto)
- OFW: Plantain parser Last payment amount fix (by @mxcdoam)
- OFW: Fix typo for mf_classic_key_cahce_get_next_key() function (by @luu176)
- OFW: Fix skylander ID reading (by @bettse)
- OFW: Fix MIFARE Plus detection (by @GMMan)
- OFW: Fix ISO15693 stuck in wrong mode (by @RebornedBrain)
- OFW: Fix MFUL PWD_AUTH command creation when 0x00 in password (by @GMMan)
- OFW: Fix typo for `mf_classic_key_cahce_get_next_key()` function (by @luu176)
- OFW: U2F: Fix message digest memory leak (by @GMMan)
- OFW: JS: SDK workaround incorrect serial port handling by OS (by @portasynthinca3)
- OFW: FBT: Fix invalid path errors on Windows with UTF8 paths (by @Alex4386)
### Removed:
- Nothing
- NFC: Previous fix for ISO15693 stuck in wrong mode (#225)
- Removes APIs `nfc_iso15693_detect_mode()`, `nfc_iso15693_force_1outof4()`, `nfc_iso15693_force_1outof256()`
@@ -236,3 +236,11 @@ App(
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_pipe",
sources=["tests/common/*.c", "tests/pipe/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
@@ -265,6 +265,7 @@ static bool test_write(const char* file_name) {
if(!flipper_format_file_open_always(file, file_name)) break;
if(!flipper_format_write_header_cstr(file, test_filetype, test_version)) break;
if(!flipper_format_write_comment_cstr(file, "This is comment")) break;
if(!flipper_format_write_empty_line(file)) break;
if(!flipper_format_write_string_cstr(file, test_string_key, test_string_data)) break;
if(!flipper_format_write_int32(file, test_int_key, test_int_data, COUNT_OF(test_int_data)))
break;
@@ -0,0 +1,108 @@
#include <furi.h>
#include <errno.h>
#include <stdio.h>
#include "../test.h" // IWYU pragma: keep
#define TAG "StdioTest"
#define CONTEXT_MAGIC ((void*)0xDEADBEEF)
// stdin
static char mock_in[256];
static size_t mock_in_len, mock_in_pos;
static void set_mock_in(const char* str) {
size_t len = strlen(str);
strcpy(mock_in, str);
mock_in_len = len;
mock_in_pos = 0;
}
static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context) {
UNUSED(wait);
furi_check(context == CONTEXT_MAGIC);
size_t remaining = mock_in_len - mock_in_pos;
size = MIN(remaining, size);
memcpy(buffer, mock_in + mock_in_pos, size);
mock_in_pos += size;
return size;
}
void test_stdin(void) {
FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback();
furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC);
char buf[256];
// plain in
set_mock_in("Hello, World!\n");
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq("Hello, World!\n", buf);
mu_assert_int_eq(EOF, getchar());
// ungetc
ungetc('i', stdin);
ungetc('H', stdin);
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq("Hi", buf);
mu_assert_int_eq(EOF, getchar());
// ungetc + plain in
set_mock_in(" World");
ungetc('i', stdin);
ungetc('H', stdin);
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq("Hi World", buf);
mu_assert_int_eq(EOF, getchar());
// partial plain in
set_mock_in("Hello, World!\n");
fgets(buf, strlen("Hello") + 1, stdin);
mu_assert_string_eq("Hello", buf);
mu_assert_int_eq(',', getchar());
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq(" World!\n", buf);
furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC);
}
// stdout
static FuriString* mock_out;
FuriThreadStdoutWriteCallback original_out_cb;
static void mock_out_cb(const char* data, size_t size, void* context) {
furi_check(context == CONTEXT_MAGIC);
// there's no furi_string_cat_strn :(
for(size_t i = 0; i < size; i++) {
furi_string_push_back(mock_out, data[i]);
}
}
static void assert_and_clear_mock_out(const char* expected) {
// return the original stdout callback for the duration of the check
// if the check fails, we don't want the error to end up in our buffer,
// we want to be able to see it!
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
mu_assert_string_eq(expected, furi_string_get_cstr(mock_out));
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
furi_string_reset(mock_out);
}
void test_stdout(void) {
original_out_cb = furi_thread_get_stdout_callback();
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
mock_out = furi_string_alloc();
puts("Hello, World!");
assert_and_clear_mock_out("Hello, World!\n");
printf("He");
printf("llo!");
fflush(stdout);
assert_and_clear_mock_out("Hello!");
furi_string_free(mock_out);
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
}
@@ -10,6 +10,8 @@ void test_furi_memmgr(void);
void test_furi_event_loop(void);
void test_errno_saving(void);
void test_furi_primitives(void);
void test_stdin(void);
void test_stdout(void);
static int foo = 0;
@@ -52,6 +54,11 @@ MU_TEST(mu_test_furi_primitives) {
test_furi_primitives();
}
MU_TEST(mu_test_stdio) {
test_stdin();
test_stdout();
}
MU_TEST_SUITE(test_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
MU_RUN_TEST(test_check);
@@ -61,6 +68,7 @@ MU_TEST_SUITE(test_suite) {
MU_RUN_TEST(mu_test_furi_pubsub);
MU_RUN_TEST(mu_test_furi_memmgr);
MU_RUN_TEST(mu_test_furi_event_loop);
MU_RUN_TEST(mu_test_stdio);
MU_RUN_TEST(mu_test_errno_saving);
MU_RUN_TEST(mu_test_furi_primitives);
}
@@ -0,0 +1,153 @@
#include "../test.h" // IWYU pragma: keep
#include <furi.h>
#include <lib/toolbox/pipe.h>
#define PIPE_SIZE 128U
#define PIPE_TRG_LEVEL 1U
MU_TEST(pipe_test_trivial) {
PipeSideBundle bundle = pipe_alloc(PIPE_SIZE, PIPE_TRG_LEVEL);
PipeSide* alice = bundle.alices_side;
PipeSide* bob = bundle.bobs_side;
mu_assert_int_eq(PipeRoleAlice, pipe_role(alice));
mu_assert_int_eq(PipeRoleBob, pipe_role(bob));
mu_assert_int_eq(PipeStateOpen, pipe_state(alice));
mu_assert_int_eq(PipeStateOpen, pipe_state(bob));
mu_assert_int_eq(PIPE_SIZE, pipe_spaces_available(alice));
mu_assert_int_eq(PIPE_SIZE, pipe_spaces_available(bob));
mu_assert_int_eq(0, pipe_bytes_available(alice));
mu_assert_int_eq(0, pipe_bytes_available(bob));
for(uint8_t i = 0;; ++i) {
mu_assert_int_eq(PIPE_SIZE - i, pipe_spaces_available(alice));
mu_assert_int_eq(i, pipe_bytes_available(bob));
if(pipe_send(alice, &i, sizeof(uint8_t), 0) != sizeof(uint8_t)) {
break;
}
mu_assert_int_eq(PIPE_SIZE - i, pipe_spaces_available(bob));
mu_assert_int_eq(i, pipe_bytes_available(alice));
if(pipe_send(bob, &i, sizeof(uint8_t), 0) != sizeof(uint8_t)) {
break;
}
}
pipe_free(alice);
mu_assert_int_eq(PipeStateBroken, pipe_state(bob));
for(uint8_t i = 0;; ++i) {
mu_assert_int_eq(PIPE_SIZE - i, pipe_bytes_available(bob));
uint8_t value;
if(pipe_receive(bob, &value, sizeof(uint8_t), 0) != sizeof(uint8_t)) {
break;
}
mu_assert_int_eq(i, value);
}
pipe_free(bob);
}
typedef enum {
TestFlagDataArrived = 1 << 0,
TestFlagSpaceFreed = 1 << 1,
TestFlagBecameBroken = 1 << 2,
} TestFlag;
typedef struct {
TestFlag flag;
FuriEventLoop* event_loop;
} AncillaryThreadContext;
static void on_data_arrived(PipeSide* pipe, void* context) {
AncillaryThreadContext* ctx = context;
ctx->flag |= TestFlagDataArrived;
uint8_t buffer[PIPE_SIZE];
size_t size = pipe_receive(pipe, buffer, sizeof(buffer), 0);
pipe_send(pipe, buffer, size, 0);
}
static void on_space_freed(PipeSide* pipe, void* context) {
AncillaryThreadContext* ctx = context;
ctx->flag |= TestFlagSpaceFreed;
const char* message = "Hi!";
pipe_send(pipe, message, strlen(message), 0);
}
static void on_became_broken(PipeSide* pipe, void* context) {
UNUSED(pipe);
AncillaryThreadContext* ctx = context;
ctx->flag |= TestFlagBecameBroken;
furi_event_loop_stop(ctx->event_loop);
}
static int32_t ancillary_thread(void* context) {
PipeSide* pipe = context;
AncillaryThreadContext thread_ctx = {
.flag = 0,
.event_loop = furi_event_loop_alloc(),
};
pipe_attach_to_event_loop(pipe, thread_ctx.event_loop);
pipe_set_callback_context(pipe, &thread_ctx);
pipe_set_data_arrived_callback(pipe, on_data_arrived, 0);
pipe_set_space_freed_callback(pipe, on_space_freed, FuriEventLoopEventFlagEdge);
pipe_set_broken_callback(pipe, on_became_broken, 0);
furi_event_loop_run(thread_ctx.event_loop);
pipe_detach_from_event_loop(pipe);
pipe_free(pipe);
furi_event_loop_free(thread_ctx.event_loop);
return thread_ctx.flag;
}
MU_TEST(pipe_test_event_loop) {
PipeSideBundle bundle = pipe_alloc(PIPE_SIZE, PIPE_TRG_LEVEL);
PipeSide* alice = bundle.alices_side;
PipeSide* bob = bundle.bobs_side;
FuriThread* thread = furi_thread_alloc_ex("PipeTestAnc", 2048, ancillary_thread, bob);
furi_thread_start(thread);
const char* message = "Hello!";
pipe_send(alice, message, strlen(message), FuriWaitForever);
char buffer_1[16];
size_t size = pipe_receive(alice, buffer_1, sizeof(buffer_1), FuriWaitForever);
buffer_1[size] = 0;
char buffer_2[16];
const char* expected_reply = "Hi!";
size = pipe_receive(alice, buffer_2, sizeof(buffer_2), FuriWaitForever);
buffer_2[size] = 0;
pipe_free(alice);
furi_thread_join(thread);
mu_assert_string_eq(message, buffer_1);
mu_assert_string_eq(expected_reply, buffer_2);
mu_assert_int_eq(
TestFlagDataArrived | TestFlagSpaceFreed | TestFlagBecameBroken,
furi_thread_get_return_code(thread));
furi_thread_free(thread);
}
MU_TEST_SUITE(test_pipe) {
MU_RUN_TEST(pipe_test_trivial);
MU_RUN_TEST(pipe_test_event_loop);
}
int run_minunit_test_pipe(void) {
MU_RUN_SUITE(test_pipe);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_pipe)
@@ -157,6 +157,7 @@ static BleEventAckStatus ble_svc_hid_event_handler(void* event, void* context) {
hci_event_pckt* event_pckt = (hci_event_pckt*)(((hci_uart_pckt*)event)->data);
evt_blecore_aci* blecore_evt = (evt_blecore_aci*)event_pckt->data;
// aci_gatt_attribute_modified_event_rp0* attribute_modified;
if(event_pckt->evt == HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE) {
if(blecore_evt->ecode == ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE) {
// Process modification events
@@ -274,6 +275,7 @@ bool ble_svc_hid_update_input_report(
.data_ptr = data,
.data_len = len,
};
return ble_gatt_characteristic_update(
hid_svc->svc_handle, &hid_svc->input_report_chars[input_report_num], &report_data);
}
+33
View File
@@ -79,6 +79,19 @@ static void infrared_rpc_command_callback(const RpcAppSystemEvent* event, void*
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressIndex);
}
} else if(event->type == RpcAppEventTypeButtonPressRelease) {
furi_assert(
event->data.type == RpcAppSystemEventDataTypeString ||
event->data.type == RpcAppSystemEventDataTypeInt32);
if(event->data.type == RpcAppSystemEventDataTypeString) {
furi_string_set(infrared->button_name, event->data.string);
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseName);
} else {
infrared->app_state.current_button_index = event->data.i32;
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressReleaseIndex);
}
} else if(event->type == RpcAppEventTypeButtonRelease) {
view_dispatcher_send_custom_event(
infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease);
@@ -402,6 +415,26 @@ void infrared_tx_stop(InfraredApp* infrared) {
infrared->app_state.last_transmit_time = furi_get_tick();
}
void infrared_tx_send_once(InfraredApp* infrared) {
if(infrared->app_state.is_transmitting) {
return;
}
dolphin_deed(DolphinDeedIrSend);
infrared_signal_transmit(infrared->current_signal);
}
InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index) {
furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote));
InfraredErrorCode error = infrared_remote_load_signal(
infrared->remote, infrared->current_signal, infrared->app_state.current_button_index);
if(!INFRARED_ERROR_PRESENT(error)) {
infrared_tx_send_once(infrared);
}
return error;
}
void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback) {
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewLoading);
furi_thread_set_callback(infrared->task_thread, callback);
@@ -218,6 +218,20 @@ InfraredErrorCode infrared_tx_start_button_index(InfraredApp* infrared, size_t b
*/
void infrared_tx_stop(InfraredApp* infrared);
/**
* @brief Transmit the currently loaded signal once.
*
* @param[in,out] infrared pointer to the application instance.
*/
void infrared_tx_send_once(InfraredApp* infrared);
/**
* @brief Load the signal under the given index and transmit it once.
*
* @param[in,out] infrared pointer to the application instance.
*/
InfraredErrorCode infrared_tx_send_once_button_index(InfraredApp* infrared, size_t button_index);
/**
* @brief Start a blocking task in a separate thread.
*
@@ -21,6 +21,8 @@ enum InfraredCustomEventType {
InfraredCustomEventTypeRpcButtonPressName,
InfraredCustomEventTypeRpcButtonPressIndex,
InfraredCustomEventTypeRpcButtonRelease,
InfraredCustomEventTypeRpcButtonPressReleaseName,
InfraredCustomEventTypeRpcButtonPressReleaseIndex,
InfraredCustomEventTypeRpcSessionClose,
InfraredCustomEventTypeGpioTxPinChanged,
@@ -28,7 +28,6 @@ address: 2D 00 00 00
command: 50 00 00 00
#
# Model: LG AKB73775801
#
name: Power
type: parsed
protocol: Samsung32
@@ -84,7 +83,6 @@ address: 2D 00 00 00
command: 36 00 00 00
#
# Model: OPPO BDP103
#
name: Power
type: parsed
protocol: NEC
@@ -134,7 +132,6 @@ address: 49 00 00 00
command: 4B 00 00 00
#
# Model: Panasonic DMPBDT167
#
name: Power
type: parsed
protocol: Kaseikyo
@@ -190,7 +187,6 @@ address: B0 02 20 02
command: 30 01 00 00
#
# Model: Philips BDP2501/F7
#
name: Power
type: parsed
protocol: RC6
@@ -234,7 +230,6 @@ address: 46 00 00 00
command: 2C 00 00 00
#
# Model: Philips BDP2700
#
name: Power
type: parsed
protocol: RC6
@@ -266,7 +261,6 @@ address: 46 00 00 00
command: 31 00 00 00
#
# Model: Pioneer BDP150
#
name: Power
type: parsed
protocol: Pioneer
@@ -328,7 +322,6 @@ address: AF 00 00 00
command: 39 00 00 00
#
# Model: Samsung AK59_00149A
#
name: Power
type: raw
frequency: 38000
@@ -360,7 +353,6 @@ duty_cycle: 0.330000
data: 4539 4519 488 516 489 489 516 515 490 514 491 514 491 1491 520 485 520 511 494 511 484 520 485 520 485 493 512 519 486 518 487 491 514 504 491 4491 516 1492 519 1490 521 1488 513 519 486 518 487 1495 516 1493 518 487 518 513 492 1517 494 484 511 520 485 1498 513 491 514 517 488 1495 516 1493 518 486 519 1491 510 1499 512 57491 4537 4495 512 492 513 519 486 493 512 520 485 521 494 1491 520 486 519 513 492 514 491 515 490 516 489 517 488 517 488 518 487 519 486 506 489 4502 516 1523 488 1498 513 1500 521 511 494 512 493 1519 492 1520 491 515 490 516 489 1522 489 491 514 518 487 1498 513 520 485 521 484 1528 493 1492 519 514 491 1521 490 1523 488
#
# Model: Samsung B59-01301A
#
name: Power
type: parsed
protocol: Samsung32
@@ -380,7 +372,6 @@ address: 07 00 00 00
command: 4A 00 00 00
#
# Model: Samsung BD-D5300
#
name: Power
type: raw
frequency: 38000
@@ -412,7 +403,6 @@ duty_cycle: 0.330000
data: 4510 4508 537 470 535 467 538 470 535 468 537 471 534 1475 534 467 538 470 535 467 538 469 536 467 538 470 535 467 538 470 535 468 537 469 536 4472 537 1472 537 1472 537 1472 537 470 535 467 538 470 535 1475 534 1475 534 1474 535 467 538 470 535 468 537 1472 537 1473 536 469 536 468 537 469 536 1474 535 1473 536 1473 536
#
# Model: Samsung BDD7500
#
name: Power
type: raw
frequency: 38000
@@ -462,7 +452,6 @@ duty_cycle: 0.330000
data: 4489 4495 514 428 571 485 514 486 513 486 513 486 513 1482 512 487 512 488 511 486 488 510 489 512 487 511 488 511 488 512 487 506 493 512 487 4507 487 1507 487 1507 487 1508 486 510 489 513 486 1506 488 1507 487 513 486 458 541 1507 487 512 487 512 487 1507 487 512 487 512 487 1507 487 1506 488 512 487 1426 568 1506 488
#
# Model: Samsung BDE5300
#
name: Power
type: raw
frequency: 38000
@@ -512,7 +501,6 @@ duty_cycle: 0.330000
data: 4489 4478 516 481 517 483 515 483 515 482 516 484 514 1456 515 481 517 484 514 482 516 484 514 483 515 483 515 481 517 482 516 367 632 482 516 4451 515 1457 514 1457 514 1455 516 483 515 483 515 1456 515 1412 559 483 515 484 514 1456 515 483 515 486 512 1458 513 483 515 482 516 1456 515 1455 516 484 514 1457 514 1457 514 57918 4486 4476 514 484 514 483 515 484 514 484 514 484 514 1458 513 483 515 483 515 484 514 484 514 483 515 484 514 483 515 483 515 484 514 483 515 4452 514 1457 514 1457 514 1456 515 482 516 484 514 1457 514 1457 514 484 514 486 512 1456 515 483 515 484 514 1456 515 485 513 484 514 1457 514 1457 514 483 515 1457 514 1456 515
#
# Model: Sanyo Bluray_NC088
#
name: Power
type: parsed
protocol: NECext
@@ -550,7 +538,6 @@ address: 87 22 00 00
command: 7A 85 00 00
#
# Model: Sharp BD-HP20
#
name: Power
type: raw
frequency: 38000
@@ -600,7 +587,6 @@ duty_cycle: 0.330000
data: 3341 1723 380 454 380 1298 381 454 380 1298 381 454 380 1298 381 455 379 1298 381 454 380 1299 380 453 381 1299 380 1299 380 453 381 1298 381 453 381 1298 381 1299 380 1272 407 1214 465 453 381 452 382 453 381 1299 380 453 381 454 380 453 381 453 381 1298 381 1232 447 453 381 454 380 1298 381 1299 380 453 381 1301 378 1299 380 1299 380 454 380 452 382 1298 381 453 381 453 381 453 381 454 380 1202 477 453 381 453 381 20534 3341 1723 380 453 381 1298 381 453 381 1299 380 453 381 1298 381 453 381 1298 381 453 381 1298 381 453 381 1298 381 1299 380 453 381 1299 380 453 381 1299 405 1274 380 1298 381 1299 380 453 381 454 380 452 382 1298 381 453 381 453 381 454 380 453 381 1298 381 1298 381 453 381 453 381 1298 381 1298 381 453 381 1299 380 1299 380 1299 380 453 381 453 381 1298 381 453 381 453 381 453 381 454 380 1298 381 454 380 453 381 20535 3340 1723 380 454 380 1299 380 454 380 1299 380 454 380 1263 416 454 380 1299 380 454 380 1299 380 454 380 1300 379 1299 380 454 380 1299 380 454 380 1299 380 1299 380 1299 380 1300 379 454 380 455 379 455 379 1300 379 455 379 454 380 455 379 454 380 1299 380 1218 462 454 379 455 379 1300 379 1301 378 455 379 1301 378 1301 378 1300 500 332 381 455 402 1277 402 433 401 432 402 432 402 432 402 1277 402 431 403 431 403
#
# Model: RMT VB201U
#
name: Power
type: parsed
protocol: SIRC20
@@ -650,7 +636,6 @@ address: 5A 1C 00 00
command: 1B 00 00 00
#
# Model: Toshiba SE-R0398
#
name: Power
type: parsed
protocol: NECext
@@ -682,7 +667,6 @@ address: 45 B5 00 00
command: 28 D7 00 00
#
# Model: Vizio VBR220
#
name: Power
type: parsed
protocol: NEC
@@ -738,7 +722,6 @@ address: 00 00 00 00
command: 33 00 00 00
#
# Model: Bose 3-2-1_Series_1
#
name: Power
type: parsed
protocol: NECext
@@ -758,7 +741,6 @@ address: BA 4B 00 00
command: 55 AA 00 00
#
# Model: Brandt DVDP-7R
#
name: Ok
type: parsed
protocol: NEC
@@ -766,7 +748,6 @@ address: 00 00 00 00
command: 07 00 00 00
#
# Model: GPX D2816
#
name: Power
type: parsed
protocol: NEC
@@ -798,7 +779,6 @@ address: 00 00 00 00
command: 03 00 00 00
#
# Model: LG DKS-6100Q
#
name: Power
type: parsed
protocol: Samsung32
@@ -824,7 +804,6 @@ address: B0 02 20 02
command: 10 01 00 00
#
# Model: Philips RC_5610
#
name: Power
type: parsed
protocol: RC6
@@ -850,7 +829,6 @@ address: 04 00 00 00
command: 4B 00 00 00
#
# Model: PIONEER-DVD PLAYER-VXX2702
#
name: Power
type: parsed
protocol: NEC
@@ -870,7 +848,6 @@ address: AF 00 00 00
command: 9E 00 00 00
#
# Model: Prinz DVD_Player_T182
#
name: Power
type: raw
frequency: 38000
@@ -884,7 +861,6 @@ duty_cycle: 0.330000
data: 8362 4520 567 599 540 547 603 564 544 595 544 543 596 544 575 592 547 566 573 1680 568 1685 574 1681 598 1709 550 1704 544 1710 569 1712 546 1708 540 1714 576 1705 543 544 595 1711 547 540 599 541 567 573 566 1687 571 569 570 544 595 1711 547 540 599 1681 567 1686 573 1682 597 570 549 40168 8377 2261 567
#
# Model: Sony DVD_RMT-D197A
#
name: Power
type: parsed
protocol: SIRC20
@@ -910,7 +886,6 @@ address: 3A 09 00 00
command: 39 00 00 00
#
# Model: Strato DVD507
#
name: Power
type: parsed
protocol: NEC
@@ -924,7 +899,6 @@ address: 00 00 00 00
command: 1E 00 00 00
#
# Model: Toshiba SE_R0108
#
name: Power
type: parsed
protocol: NEC
@@ -950,7 +924,6 @@ address: 45 00 00 00
command: 15 00 00 00
#
# Model: TOSHIBA SE_R0420
#
name: Power
type: raw
frequency: 38000
@@ -958,7 +931,6 @@ duty_cycle: 0.330000
data: 9072 4364 664 1566 664 451 663 1567 663 453 661 454 660 478 636 1594 636 479 635 1595 635 480 635 1596 634 481 634 1597 633 1597 634 482 633 1598 632 482 633 482 633 482 633 482 633 482 633 482 633 1597 633 1598 632 1598 632 1598 632 1598 632 1598 632 1598 632 1598 632 482 633 482 633 39968 9043 2203 634 95675 9067 2203 634 95675 9067 2203 634
#
# Model: Dvd tv_player
#
name: Power
type: parsed
protocol: NEC
@@ -966,7 +938,6 @@ address: 00 00 00 00
command: 03 00 00 00
#
# Model: Dvd tv_player_2
#
name: Subtitle
type: parsed
protocol: NEC
@@ -986,7 +957,6 @@ address: 00 00 00 00
command: 53 00 00 00
#
# Model: APEX RM_3800
#
name: Power
type: parsed
protocol: NEC
@@ -1000,7 +970,6 @@ address: 01 00 00 00
command: 19 00 00 00
#
# Model: RVR-4000
#
name: Power
type: parsed
protocol: NEC
@@ -1020,7 +989,6 @@ address: 35 00 00 00
command: 1B 00 00 00
#
# Model: JVC HR-A591U
#
name: Power
type: raw
frequency: 38000
@@ -1040,7 +1008,6 @@ duty_cycle: 0.330000
data: 8414 4228 507 1601 506 1600 507 547 506 548 505 546 507 547 506 1601 506 547 506 547 506 546 507 1600 507 1599 508 547 506 547 506 546 507 546 507 23151 505 1600 507 1601 506 547 506 547 506 547 506 547 506 1600 507 546 507 547 506 547 506 1600 507 1600 507 546 507 548 505 547 506 546 507 23150 506 1600 507 1601 506 545 508 547 506 547 506 545 508 1601 506 548 505 547 506 546 507 1599 508 1600 507 547 506 547 506 546 507 547 506
#
# Model: JVC HR-J700E
#
name: Power
type: raw
frequency: 38000
@@ -1066,7 +1033,6 @@ duty_cycle: 0.330000
data: 8422 4235 547 1565 547 1564 548 507 548 507 549 507 549 508 548 1565 547 510 545 507 549 509 547 1563 549 1563 549 1567 545 1564 548 507 549 506 550 20891 546 1566 545 1564 548 508 548 507 548 509 547 506 549 1565 547 509 547 507 548 509 547 1563 549 1562 550 1563 549 1564 548 508 548 508 548 21245 548 1565 547 1565 547 507 549 509 547 509 546 508 548 1566 546 508 548 508 547 507 549 1566 546 1564 548 1564 548 1562 549 508 548 508 548 21246 547 1563 549 1563 549 509 547 509 547 508 547 508 547 1565 547 508 548 507 548 507 549 1564 548 1565 547 1564 548 1565 546 507 549 507 549 21246 547 1564 548 1566 546 506 549 511 545 508 547 508 548 1564 548 508 548 508 548 507 549 1563 549 1564 548 1564 548 1563 548 509 547 508 547 21246 547 1564 548 1564 548 509 547 509 547 508 548 508 548 1564 548 507 549 507 548 508 548 1564 548 1566 546 1564 548 1564 548 508 548 509 547 21245 548 1565 547 1563 549 509 547 508 547 508 548 506 550 1566 546 511 545 507 549 508 547 1565 547 1563 549 1564 548 1566 546 508 548 508 548
#
# Model: JVC HR-S2902U
#
name: Power
type: raw
frequency: 38000
@@ -1092,7 +1058,6 @@ duty_cycle: 0.330000
data: 8376 4181 504 1565 505 1592 504 543 505 570 504 570 504 544 504 1592 505 571 503 544 504 570 504 1566 504 1591 505 1591 505 1566 504 570 504 570 504 21772 505 1592 504 1565 505 570 504 569 505 543 505 570 504 1566 504 571 503 569 505 544 504 1592 504 1592 504 1565 505 1591 505 544 504 570 504 21773 504 1591 505 1565 505 570 504 570 504 543 505 569 505 1565 505 572 502 570 504 542 506 1591 505 1591 505 1565 505 1592 504 544 504 568 506 21773 505 1592 504 1567 503 570 504 568 506 543 505 569 505 1566 504 570 504 570 504 543 505 1591 505 1591 505 1565 505 1591 506 543 505 569 505
#
# Model: LG GC260W
#
name: Power
type: parsed
protocol: NEC
@@ -1112,7 +1077,6 @@ address: 6E 00 00 00
command: 08 00 00 00
#
# Model: Magnavox N9377
#
name: Power
type: raw
frequency: 38000
@@ -1138,7 +1102,6 @@ duty_cycle: 0.330000
data: 3489 3523 881 865 876 886 882 888 880 2607 875 885 883 2628 881 2607 875 2627 882 887 881 2607 875 888 880 886 882 2607 875 2628 881 2627 882 864 877 2627 882 887 881 865 876 886 881 2628 881 867 874 2629 880 2628 881 33917 3494 3502 874 888 880 887 881 865 876 2628 881 888 880 2606 876 2629 880 2629 880 864 876 2629 880 889 879 867 873 2629 880 2629 880 2606 876 888 880 2630 879 865 876 889 879 890 878 2607 875 889 879 2631 878 2608 874
#
# Model: Panasonic Light_Tower_LSSQ0342
#
name: Play
type: parsed
protocol: Kaseikyo
@@ -1164,7 +1127,6 @@ address: 90 02 20 00
command: 60 00 00 00
#
# Model: Panasonic NV-FJ606
#
name: Power
type: raw
frequency: 38000
@@ -1172,7 +1134,6 @@ duty_cycle: 0.330000
data: 3538 1702 463 407 461 1273 463 406 462 405 463 405 463 405 463 405 487 382 487 407 460 408 459 410 457 411 457 411 457 1280 457 411 457 411 457 411 457 411 457 411 457 411 457 1280 457 411 457 412 456 1280 457 412 457 412 456 411 457 411 457 412 456 412 456 412 456 412 456 1280 457 412 456 1281 456 1281 456 1281 456 1281 456 412 456 412 456 1281 456 413 455 1281 456 1282 455 413 455 1282 455 413 455 1282 455 74229 3532 1709 457 411 457 1280 457 411 457 412 456 412 456 412 457 411 457 412 456 412 456 412 456 412 456 412 456 412 456 1281 456 412 457 412 456 412 456 412 456 412 456 412 456 1281 456 412 456 412 456 1281 456 413 455 413 455 413 455 413 455 413 455 413 455 413 455 413 455 1282 455 413 455 1282 455 1282 455 1282 455 1282 455 414 454 414 454 1283 454 414 454 1283 454 1283 454 414 454 1283 454 414 454 1283 454
#
# Model: Panasonic VCR_PV9662
#
name: Power
type: raw
frequency: 38000
@@ -1198,7 +1159,6 @@ duty_cycle: 0.330000
data: 3510 1694 450 416 454 1280 450 417 453 414 445 422 448 418 452 415 455 412 447 420 450 416 454 413 446 420 450 417 453 1282 448 419 451 416 454 412 447 420 450 417 453 414 445 1288 452 415 444 422 448 1286 454 413 446 420 450 417 453 414 445 422 448 418 452 415 455 412 447 419 451 1284 446 1288 452 414 445 422 448 419 451 416 454 413 446 420 450 1284 446 1288 452 415 444 1290 450 416 454 413 446 1288 452 74520 3511 1688 446 422 448 1286 454 412 447 420 450 416 454 413 446 421 449 418 452 415 444 422 448 419 451 415 455 412 447 1287 453 414 445 421 449 418 452 415 444 422 448 419 451 1283 447 420 450 417 453 1281 449 418 452 415 444 422 448 419 451 416 454 413 446 420 450 417 453 414 445 1289 451 1283 447 420 450 417 453 414 445 421 449 418 452 415 455 1279 451 1284 446 421 449 1285 445 422 448 419 451 1283 447
#
# Model: Philips-RC2K16
#
name: Power
type: parsed
protocol: RC6
@@ -1212,7 +1172,6 @@ address: 04 00 00 00
command: 2C 00 00 00
#
# Model: Sony RM-Y126
#
name: Power
type: parsed
protocol: SIRC
@@ -1238,7 +1197,6 @@ address: 0B 00 00 00
command: 1A 00 00 00
#
# Model: Sony SLV-SE610B
#
name: Power
type: parsed
protocol: SIRC
@@ -1246,7 +1204,6 @@ address: 0B 00 00 00
command: 15 00 00 00
#
# Model: Unknown1
#
name: Power
type: parsed
protocol: NEC
@@ -1308,7 +1265,6 @@ address: BA 4B 00 00
command: E0 1F 00 00
#
# Model: Brandt DVDP-7R
#
name: Subtitle
type: parsed
protocol: NEC
@@ -1346,7 +1302,6 @@ duty_cycle: 0.330000
data: 3484 3464 907 829 908 830 907 804 906 2596 906 804 933 2569 878 858 879 832 878 2622 880 831 879 858 879 860 877 2596 878 2623 879 2597 877 858 879 2597 877 857 880 2595 879 2594 880 857 880 2595 907 2595 879 2595 880 33544 3485 3437 907 831 906 831 906 830 907 2568 906 830 907 2567 907 831 906 830 907 2567 907 830 907 805 932 802 908 2594 908 2568 907 2567 907 832 905 2568 906 831 906 2568 879 2622 879 831 906 2596 878 2596 879 2596 906
#
# Model: Prinz DVD_Player_T182
#
name: Eject
type: raw
frequency: 38000
@@ -1366,7 +1321,6 @@ duty_cycle: 0.330000
data: 8328 4524 563 592 527 569 550 545 553 596 533 565 554 568 530 595 534 566 553 1683 565 1684 564 1684 647 1624 562 1685 563 1685 646 1625 561 1687 561 598 531 567 552 571 527 1687 592 567 531 596 533 567 552 1687 572 1678 570 1680 589 1685 563 572 557 1681 619 1630 566 1684 595 565 533 40169 8337 2267 572
#
# Model: Sony DVD_RMT-D197A
#
name: Eject
type: parsed
protocol: SIRC20
@@ -1554,7 +1508,6 @@ address: 2D 00 00 00
command: 33 00 00 00
#
# Model: NAD T557
#
name: Power
type: parsed
protocol: NECext
@@ -1604,7 +1557,6 @@ address: 86 0F 00 00
command: CD 32 00 00
#
# Model: Samsung UBDK8500
#
name: Power
type: raw
frequency: 38000
@@ -1648,7 +1600,6 @@ duty_cycle: 0.330000
data: 4486 4499 483 516 483 515 484 515 484 514 485 515 484 1510 484 514 485 516 483 516 483 515 484 515 484 516 483 516 483 515 484 516 483 516 483 4450 544 1511 461 1533 461 1534 482 516 461 539 460 539 460 1534 460 539 460 1534 460 539 460 538 461 539 460 1533 461 1534 460 538 461 1534 460 538 461 1534 460 1534 460 1533 461
#
# Model: Sylvania SDVD1111
#
name: Power
type: parsed
protocol: NEC
@@ -1710,7 +1661,6 @@ address: 07 00 00 00
command: 45 00 00 00
#
# Model: Marantz BD8002
#
name: Power
type: raw
frequency: 38000
@@ -1754,7 +1704,6 @@ duty_cycle: 0.330000
data: 874 930 1764 942 874 931 873 1833 873 931 873 931 873 4448 873 930 1764 1846 1762 1846 1763 943 873 931 873 931 873 931 873 931 873 75040 873 931 1763 944 872 931 873 1833 873 931 873 931 873 4449 872 931 1763 1846 1762 1845 1764 943 873 931 873 931 873 931 873 931 873 75040 873 931 1763 944 872 931 873 1834 872 931 873 931 873 4449 872 931 1763 1846 1763 1846 1763 943 873 931 873 931 873 931 873 931 873
#
# Model: Yamaha BDS667
#
name: Power
type: parsed
protocol: NEC
@@ -1791,12 +1740,12 @@ protocol: NEC
address: 7C 00 00 00
command: 83 00 00 00
#
# Model: JVC XVBP1
name: Play
type: parsed
protocol: NEC
address: 7C 00 00 00
command: 82 00 00 00
# Model: JVC XVBP1
#
name: Power
type: parsed
@@ -1847,7 +1796,6 @@ address: 2A 03 01 02
command: E1 01 00 00
#
# Model: Soniq B100
#
name: Power
type: parsed
protocol: NECext
@@ -1890,8 +1838,224 @@ protocol: NECext
address: 00 DF 00 00
command: 1E E1 00 00
#
# Model: Bose 3-2-1_Series_1
name: Subtitle
type: parsed
protocol: NECext
address: 00 DF 00 00
command: 5A A5 00 00
#
# Model: Pioneer GGF1381
name: Fast_fo
type: parsed
protocol: NEC
address: A8 00 00 00
command: 10 00 00 00
#
name: Fast_ba
type: parsed
protocol: NEC
address: A8 00 00 00
command: 11 00 00 00
#
name: Pause
type: parsed
protocol: NEC
address: A8 00 00 00
command: 18 00 00 00
#
name: Play
type: parsed
protocol: NEC
address: A8 00 00 00
command: 17 00 00 00
#
# Model: JVC HRS7900U
#
name: Power
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8382 4224 460 1643 461 1643 461 543 461 541 463 543 461 543 461 1642 462 543 461 1643 461 1643 461 543 461 1643 461 543 461 543 461 470 534 543 485 21919 487 1618 486 1617 487 517 487 517 487 517 487 518 486 1617 487 517 487 1617 487 1617 487 516 488 1617 487 516 488 517 487 517 487 517 487 21917 487 1617 487 1617 488 517 486 517 487 518 486 516 488 1618 486 518 486 1618 486 1618 461 543 485 1619 461 543 461 543 461 543 461 543 461
#
name: Eject
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8381 4223 460 1644 460 1645 459 544 460 544 460 544 460 544 460 1644 460 544 460 1644 460 1644 460 1644 460 544 460 544 460 544 460 544 460 1644 460 20846 459 1645 459 1644 460 545 459 544 460 545 459 545 459 1645 459 545 459 1645 459 1645 459 1644 460 545 459 544 460 544 460 545 459 1645 459 20845 460 1645 459 1645 459 544 460 544 460 544 460 544 460 1644 460 544 460 1644 460 1644 460 1644 460 544 460 544 460 544 460 544 460 1587 517
#
name: Fast_fo
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8382 4220 511 1592 512 1593 511 493 511 488 516 492 512 492 512 1594 510 492 512 492 512 1592 512 1593 511 493 511 492 512 492 512 493 511 465 538 22994 487 1618 486 1618 486 518 486 517 487 518 486 518 486 1618 486 518 486 517 487 1618 486 1618 486 517 487 518 486 518 486 518 486 518 486 23019 486 1618 486 1618 486 518 486 518 486 518 486 518 486 1618 486 519 485 518 486 1618 486 1617 487 518 486 517 487 518 486 518 486 518 486
#
name: Fast_ba
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8383 4223 511 1592 512 1592 512 492 512 493 511 493 511 492 512 1593 511 493 511 1593 487 1619 485 1617 487 518 486 516 488 518 486 517 487 518 486 21918 512 1592 512 1592 512 492 512 493 511 493 511 492 512 1592 512 492 512 1591 513 1592 512 1592 512 493 511 491 564 440 513 492 512 492 564 21870 535 1541 563 1540 564 440 564 439 513 491 513 492 512 1591 513 492 512 1593 511 1592 512 1592 512 492 512 493 511 492 512 490 514 493 511
#
name: Pause
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8380 4158 526 1644 460 1645 459 544 460 544 460 544 460 543 461 1645 459 545 459 1599 505 545 459 1645 459 1645 459 545 459 545 459 544 460 545 459 21944 483 1621 483 1621 483 520 484 521 483 520 484 521 483 1620 484 520 484 1619 485 522 482 1619 485 1620 484 519 485 519 485 520 484 519 485 21920 485 1618 486 1618 486 548 456 518 486 519 485 518 486 1618 486 519 485 1619 485 518 486 1618 486 1619 485 518 486 477 527 519 485 519 485
#
name: Play
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8380 4223 461 1644 460 1644 460 544 460 544 460 544 460 453 551 1644 460 544 460 544 460 489 515 1644 460 1644 460 545 459 544 460 544 460 544 460 23044 461 1644 460 1644 460 543 486 519 460 544 460 544 460 1644 460 544 460 544 460 544 460 1644 460 1645 459 544 460 544 460 544 460 544 460 23045 460 1645 459 1644 460 544 460 545 459 545 459 544 460 1645 459 544 460 545 459 544 460 1645 459 1645 459 544 460 544 460 493 511 544 460
#
name: Ok
type: raw
frequency: 38000
duty_cycle: 0.330000
data: 8381 4221 460 1643 461 1643 461 543 461 543 486 518 461 543 461 1643 485 520 460 543 485 519 485 1619 485 1619 485 1597 507 1619 486 518 486 518 486 20819 486 1617 487 1617 487 517 487 517 487 517 487 517 487 1617 487 517 487 517 487 517 487 1617 487 1617 487 1617 487 1617 487 516 488 517 487 20817 488 1617 487 1616 488 516 488 516 488 516 488 516 488 1616 488 517 487 516 488 517 487 1616 488 1617 487 1618 486 1617 487 517 487 516 488
#
# Model: Memorex MVR4040A
name: Power
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 13 EC 00 00
#
name: Eject
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 4E B1 00 00
#
name: Ok
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 45 BA 00 00
#
name: Fast_fo
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 18 E7 00 00
#
name: Fast_ba
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 19 E6 00 00
#
name: Pause
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 1A E5 00 00
#
name: Play
type: parsed
protocol: NECext
address: 80 7B 00 00
command: 16 E9 00 00
#
name: Ok
type: parsed
protocol: SIRC
address: 0B 00 00 00
command: 51 00 00 00
#
name: Fast_fo
type: parsed
protocol: SIRC
address: 0B 00 00 00
command: 1C 00 00 00
#
name: Ok
type: parsed
protocol: SIRC
address: 0B 00 00 00
command: 1A 00 00 00
#
name: Fast_fo
type: parsed
protocol: SIRC15
address: BA 00 00 00
command: 11 00 00 00
#
name: Fast_ba
type: parsed
protocol: SIRC15
address: BA 00 00 00
command: 10 00 00 00
#
name: Pause
type: parsed
protocol: SIRC15
address: BA 00 00 00
command: 0E 00 00 00
#
# Model: Sony SLVD201P
name: Power
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 15 00 00 00
#
name: Eject
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 16 00 00 00
#
name: Ok
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 0B 00 00 00
#
name: Fast_fo
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 1C 00 00 00
#
name: Fast_ba
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 1B 00 00 00
#
name: Pause
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 19 00 00 00
#
name: Play
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 1A 00 00 00
#
name: Subtitle
type: parsed
protocol: SIRC20
address: 7A 0A 00 00
command: 60 00 00 00
#
name: Ok
type: parsed
protocol: SIRC15
address: BA 00 00 00
command: 18 00 00 00
#
name: Pause
type: parsed
protocol: NEC
address: 45 00 00 00
command: 00 00 00 00
#
name: Play
type: parsed
protocol: NEC
address: A8 00 00 00
command: 17 00 00 00
@@ -124,6 +124,49 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
rpc_system_app_confirm(infrared->rpc_ctx, result);
} else if(
event.event == InfraredCustomEventTypeRpcButtonPressReleaseName ||
event.event == InfraredCustomEventTypeRpcButtonPressReleaseIndex) {
bool result = false;
// Send the signal once and stop
if(rpc_state == InfraredRpcStateLoaded) {
if(event.event == InfraredCustomEventTypeRpcButtonPressReleaseName) {
const char* button_name = furi_string_get_cstr(infrared->button_name);
size_t index;
const bool index_found =
infrared_remote_get_signal_index(infrared->remote, button_name, &index);
app_state->current_button_index = index_found ? (signed)index :
InfraredButtonIndexNone;
FURI_LOG_D(TAG, "Sending signal with name \"%s\"", button_name);
} else {
FURI_LOG_D(
TAG, "Sending signal with index \"%ld\"", app_state->current_button_index);
}
if(infrared->app_state.current_button_index != InfraredButtonIndexNone) {
InfraredErrorCode error = infrared_tx_send_once_button_index(
infrared, app_state->current_button_index);
if(!INFRARED_ERROR_PRESENT(error)) {
const char* remote_name = infrared_remote_get_name(infrared->remote);
infrared_text_store_set(infrared, 0, "emulating\n%s", remote_name);
infrared_scene_rpc_show(infrared);
result = true;
} else {
rpc_system_app_set_error_code(
infrared->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
rpc_system_app_set_error_text(
infrared->rpc_ctx, "Cannot load button data");
result = false;
}
}
}
if(result) {
scene_manager_set_scene_state(
infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded);
}
rpc_system_app_confirm(infrared->rpc_ctx, result);
} else if(
event.event == InfraredCustomEventTypeRpcExit ||
event.event == InfraredCustomEventTypeRpcSessionClose ||
@@ -33,11 +33,20 @@ static void momentum_app_scene_interface_lockscreen_bad_pins_format_changed(Vari
}
static void
momentum_app_scene_interface_lockscreen_allow_locked_rpc_commands_changed(VariableItem* item) {
momentum_app_scene_interface_lockscreen_allow_locked_rpc_usb_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
bool value = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, value ? "ON" : "OFF");
momentum_settings.allow_locked_rpc_commands = value;
momentum_settings.allow_locked_rpc_usb = value;
app->save_settings = true;
}
static void
momentum_app_scene_interface_lockscreen_allow_locked_rpc_ble_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
bool value = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, value ? "ON" : "OFF");
momentum_settings.allow_locked_rpc_ble = value;
app->save_settings = true;
}
@@ -126,13 +135,23 @@ void momentum_app_scene_interface_lockscreen_on_enter(void* context) {
item = variable_item_list_add(
var_item_list,
"Allow RPC While Locked",
"Allow USB RPC While Locked",
2,
momentum_app_scene_interface_lockscreen_allow_locked_rpc_commands_changed,
momentum_app_scene_interface_lockscreen_allow_locked_rpc_usb_changed,
app);
variable_item_set_current_value_index(item, momentum_settings.allow_locked_rpc_commands);
variable_item_set_current_value_index(item, momentum_settings.allow_locked_rpc_usb);
variable_item_set_current_value_text(
item, momentum_settings.allow_locked_rpc_commands ? "ON" : "OFF");
item, momentum_settings.allow_locked_rpc_usb ? "ON" : "OFF");
item = variable_item_list_add(
var_item_list,
"Allow BLE RPC While Locked",
2,
momentum_app_scene_interface_lockscreen_allow_locked_rpc_ble_changed,
app);
variable_item_set_current_value_index(item, momentum_settings.allow_locked_rpc_ble);
variable_item_set_current_value_text(
item, momentum_settings.allow_locked_rpc_ble ? "ON" : "OFF");
item = variable_item_list_add(
var_item_list,
@@ -23,6 +23,7 @@ const char* const menu_style_names[MenuStyleCount] = {
"C64",
"Compact",
"MNTM",
"CoverFlow",
};
static void momentum_app_scene_interface_mainmenu_menu_style_changed(VariableItem* item) {
MomentumApp* app = variable_item_get_context(item);
@@ -7,13 +7,36 @@
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#include <flipper_format/flipper_format.h>
#define TAG "Skylanders"
#define TAG "Skylanders"
#define POLY UINT64_C(0x42f0e1eba9ea3693)
#define TOP UINT64_C(0x800000000000)
#define UID_LEN 4
#define KEY_MASK 0xFFFFFFFFFFFF
static const uint64_t skylanders_key = 0x4b0b20107ccb;
static const char* nfc_resources_header = "Flipper NFC resources";
static const uint32_t nfc_resources_file_version = 1;
uint64_t crc64_like(uint64_t result, uint8_t sector) {
result ^= (uint64_t)sector << 40;
for(int i = 0; i < 8; i++) {
result = (result & TOP) ? (result << 1) ^ POLY : result << 1;
}
return result;
}
uint64_t taghash(uint32_t uid) {
uint64_t result = 0x9AE903260CC4;
uint8_t uidBytes[UID_LEN] = {0};
memcpy(uidBytes, &uid, UID_LEN);
for(int i = 0; i < UID_LEN; i++) {
result = crc64_like(result, uidBytes[i]);
}
return result;
}
static bool skylanders_search_data(
Storage* storage,
const char* file_name,
@@ -88,6 +111,12 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) {
MfClassicData* data = mf_classic_alloc();
nfc_device_copy_data(device, NfcProtocolMfClassic, data);
size_t* uid_len = 0;
const uint8_t* uid_bytes = mf_classic_get_uid(data, uid_len);
uint32_t uid = 0;
memcpy(&uid, uid_bytes, sizeof(uid));
uint64_t hash = taghash(uid);
do {
MfClassicType type = MfClassicType1k;
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
@@ -96,10 +125,18 @@ static bool skylanders_read(Nfc* nfc, NfcDevice* device) {
data->type = type;
MfClassicDeviceKeys keys = {};
for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) {
bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data);
FURI_BIT_SET(keys.key_a_mask, i);
bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_b[i].data);
FURI_BIT_SET(keys.key_b_mask, i);
if(i == 0) {
bit_lib_num_to_bytes_be(skylanders_key, sizeof(MfClassicKey), keys.key_a[i].data);
FURI_BIT_SET(keys.key_a_mask, i);
} else {
uint64_t sectorhash = crc64_like(hash, i);
uint64_t key = sectorhash & KEY_MASK;
uint8_t* keyBytes = (uint8_t*)&key;
memcpy(keys.key_a[i].data, keyBytes, sizeof(MfClassicKey));
FURI_BIT_SET(keys.key_a_mask, i);
memset(keys.key_b[i].data, 0, sizeof(MfClassicKey));
FURI_BIT_SET(keys.key_b_mask, i);
}
}
error = mf_classic_poller_sync_read(nfc, &keys, data);
@@ -134,7 +171,7 @@ static bool skylanders_parse(const NfcDevice* device, FuriString* parsed_data) {
uint64_t key = bit_lib_bytes_to_num_be(sec_tr->key_a.data, 6);
if(key != skylanders_key) break;
const uint16_t id = (uint16_t)*data->block[1].data;
const uint16_t id = data->block[1].data[1] << 8 | data->block[1].data[0];
if(id == 0) break;
Storage* storage = furi_record_open(RECORD_STORAGE);
@@ -35,6 +35,7 @@ typedef enum {
SubGhzCustomEventSceneRpcLoad,
SubGhzCustomEventSceneRpcButtonPress,
SubGhzCustomEventSceneRpcButtonRelease,
SubGhzCustomEventSceneRpcButtonPressRelease,
SubGhzCustomEventSceneRpcSessionClose,
SubGhzCustomEventViewReceiverOK,
@@ -87,6 +87,43 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
rpc_system_app_confirm(subghz->rpc_ctx, result);
} else if(event.event == SubGhzCustomEventSceneRpcButtonPressRelease) {
bool result = false;
if(state == SubGhzRpcStateLoaded) {
switch(
subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) {
case SubGhzTxRxStartTxStateErrorOnlyRx:
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeRegionLock);
rpc_system_app_set_error_text(
subghz->rpc_ctx,
"Transmission on this frequency is restricted in your region");
break;
case SubGhzTxRxStartTxStateErrorParserOthers:
rpc_system_app_set_error_code(
subghz->rpc_ctx, RpcAppSystemErrorCodeInternalParse);
rpc_system_app_set_error_text(
subghz->rpc_ctx, "Error in protocol parameters description");
break;
default: //if(SubGhzTxRxStartTxStateOk)
result = true;
subghz_blink_start(subghz);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateTx);
break;
}
}
// Stop transmission
if(state == SubGhzRpcStateTx) {
subghz_txrx_stop(subghz->txrx);
subghz_blink_stop(subghz);
result = true;
}
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateIdle);
rpc_system_app_confirm(subghz->rpc_ctx, result);
} else if(event.event == SubGhzCustomEventSceneRpcLoad) {
bool result = false;
if(state == SubGhzRpcStateIdle) {
+3
View File
@@ -53,6 +53,9 @@ static void subghz_rpc_command_callback(const RpcAppSystemEvent* event, void* co
} else if(event->type == RpcAppEventTypeButtonRelease) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonRelease);
} else if(event->type == RpcAppEventTypeButtonPressRelease) {
view_dispatcher_send_custom_event(
subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonPressRelease);
} else {
rpc_system_app_confirm(subghz->rpc_ctx, false);
}
+4
View File
@@ -280,6 +280,8 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private)));
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash));
mbedtls_md_free(&hmac_ctx);
}
// Generate public key
@@ -387,6 +389,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key)));
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control));
mbedtls_md_free(&hmac_ctx);
}
if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) {
+51 -8
View File
@@ -8,6 +8,7 @@
#include <flipper_application/plugins/plugin_manager.h>
#include <loader/firmware_api/firmware_api.h>
#include <inttypes.h>
#include <stdlib.h>
#define TAG "CliSrv"
@@ -208,6 +209,36 @@ static void cli_execute_command(Cli* cli, CliCommand* command, FuriString* args)
}
}
static size_t cli_string_distance(const char* s1, const char* s2) {
size_t distance = 0;
while(*s1 && *s2) {
if(*s1++ != *s2++) distance++;
}
while(*s1++)
distance++;
while(*s2++)
distance++;
return distance;
}
static void cli_find_similar_command(Cli* cli, const char* input, FuriString* suggestion) {
size_t min_distance = (size_t)-1;
size_t max_allowed = (strlen(input) + 1) / 2;
furi_string_reset(suggestion);
CliCommandTree_it_t it;
for(CliCommandTree_it(it, cli->commands); !CliCommandTree_end_p(it); CliCommandTree_next(it)) {
const char* cmd_name = furi_string_get_cstr(*CliCommandTree_ref(it)->key_ptr);
size_t distance = cli_string_distance(input, cmd_name);
if(distance < min_distance && distance <= max_allowed) {
min_distance = distance;
furi_string_set(suggestion, cmd_name);
}
}
}
static void cli_handle_enter(Cli* cli) {
cli_normalize_line(cli);
@@ -245,9 +276,21 @@ static void cli_handle_enter(Cli* cli) {
} else {
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
cli_nl(cli);
printf(
"`%s` command not found, use `help` or `?` to list all available commands",
furi_string_get_cstr(command));
FuriString* suggestion = furi_string_alloc();
cli_find_similar_command(cli, furi_string_get_cstr(command), suggestion);
if(furi_string_empty(suggestion)) {
printf(
"`%s` command not found, use `help` or `?` to list all available commands",
furi_string_get_cstr(command));
} else {
printf(
"`%s` command not found, did you mean `%s`? Use `help` or `?` to list all available commands",
furi_string_get_cstr(command),
furi_string_get_cstr(suggestion));
}
furi_string_free(suggestion);
cli_putc(cli, CliKeyBell);
}
@@ -533,9 +576,9 @@ void cli_session_open(Cli* cli, void* session) {
cli->session = session;
if(cli->session != NULL) {
cli->session->init();
furi_thread_set_stdout_callback(cli->session->tx_stdout);
furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL);
} else {
furi_thread_set_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL, NULL);
}
furi_semaphore_release(cli->idle_sem);
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
@@ -549,7 +592,7 @@ void cli_session_close(Cli* cli) {
cli->session->deinit();
}
cli->session = NULL;
furi_thread_set_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL, NULL);
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
}
@@ -563,9 +606,9 @@ int32_t cli_srv(void* p) {
furi_record_create(RECORD_CLI, cli);
if(cli->session != NULL) {
furi_thread_set_stdout_callback(cli->session->tx_stdout);
furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL);
} else {
furi_thread_set_stdout_callback(NULL);
furi_thread_set_stdout_callback(NULL, NULL);
}
if(furi_hal_is_normal_boot()) {
+11
View File
@@ -682,6 +682,13 @@ void cli_command_i2c(Cli* cli, FuriString* args, void* context) {
furi_hal_i2c_release(&furi_hal_i2c_handle_external);
}
void cli_command_clear(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(args);
UNUSED(context);
printf("\e[2J\e[H");
}
CLI_PLUGIN_WRAPPER("info", cli_command_info)
CLI_PLUGIN_WRAPPER("src", cli_command_src)
CLI_PLUGIN_WRAPPER("neofetch", cli_command_neofetch)
@@ -693,6 +700,7 @@ CLI_PLUGIN_WRAPPER("vibro", cli_command_vibro)
CLI_PLUGIN_WRAPPER("led", cli_command_led)
CLI_PLUGIN_WRAPPER("gpio", cli_command_gpio)
CLI_PLUGIN_WRAPPER("i2c", cli_command_i2c)
CLI_PLUGIN_WRAPPER("clear", cli_command_clear)
void cli_commands_init(Cli* cli) {
cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info_wrapper, (void*)true);
@@ -724,4 +732,7 @@ void cli_commands_init(Cli* cli) {
cli_add_command(cli, "led", CliCommandFlagDefault, cli_command_led_wrapper, NULL);
cli_add_command(cli, "gpio", CliCommandFlagDefault, cli_command_gpio_wrapper, NULL);
cli_add_command(cli, "i2c", CliCommandFlagDefault, cli_command_i2c_wrapper, NULL);
cli_add_command(cli, "clear", CliCommandFlagParallelSafe, cli_command_clear, NULL);
cli_add_command(cli, "cls", CliCommandFlagParallelSafe, cli_command_clear, NULL);
}
+2 -1
View File
@@ -28,8 +28,9 @@ struct CliSession {
void (*init)(void);
void (*deinit)(void);
size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
size_t (*rx_stdin)(uint8_t* buffer, size_t size, uint32_t timeout, void* context);
void (*tx)(const uint8_t* buffer, size_t size);
void (*tx_stdout)(const char* data, size_t size);
void (*tx_stdout)(const char* data, size_t size, void* context);
bool (*is_connected)(void);
};
+8 -1
View File
@@ -243,6 +243,11 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
return rx_cnt;
}
static size_t cli_vcp_rx_stdin(uint8_t* data, size_t size, uint32_t timeout, void* context) {
UNUSED(context);
return cli_vcp_rx(data, size, timeout);
}
static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
furi_assert(vcp);
furi_assert(buffer);
@@ -268,7 +273,8 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
VCP_DEBUG("tx %u end", size);
}
static void cli_vcp_tx_stdout(const char* data, size_t size) {
static void cli_vcp_tx_stdout(const char* data, size_t size, void* context) {
UNUSED(context);
cli_vcp_tx((const uint8_t*)data, size);
}
@@ -311,6 +317,7 @@ CliSession cli_vcp = {
cli_vcp_init,
cli_vcp_deinit,
cli_vcp_rx,
cli_vcp_rx_stdin,
cli_vcp_tx,
cli_vcp_tx_stdout,
cli_vcp_is_connected,
+23 -15
View File
@@ -193,11 +193,11 @@ static void desktop_stop_auto_lock_timer(Desktop* desktop) {
static void desktop_auto_lock_arm(Desktop* desktop) {
if(desktop->settings.auto_lock_delay_ms) {
if(desktop->input_events_subscription == NULL) {
if(!desktop->input_events_subscription) {
desktop->input_events_subscription = furi_pubsub_subscribe(
desktop->input_events_pubsub, desktop_auto_lock_callback, desktop);
}
if(desktop->ascii_events_subscription == NULL) {
if(!desktop->ascii_events_subscription) {
desktop->ascii_events_subscription = furi_pubsub_subscribe(
desktop->ascii_events_pubsub, desktop_auto_lock_callback, desktop);
}
@@ -391,13 +391,17 @@ void desktop_lock(Desktop* desktop, bool with_pin) {
furi_hal_rtc_set_pin_fails(0);
}
if(with_pin && !momentum_settings.allow_locked_rpc_commands) {
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_close(cli);
furi_record_close(RECORD_CLI);
Bt* bt = furi_record_open(RECORD_BT);
bt_close_rpc_connection(bt);
furi_record_close(RECORD_BT);
if(with_pin) {
if(!momentum_settings.allow_locked_rpc_usb) {
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_close(cli);
furi_record_close(RECORD_CLI);
}
if(!momentum_settings.allow_locked_rpc_ble) {
Bt* bt = furi_record_open(RECORD_BT);
bt_close_rpc_connection(bt);
furi_record_close(RECORD_BT);
}
}
desktop_auto_lock_inhibit(desktop);
@@ -426,12 +430,16 @@ void desktop_unlock(Desktop* desktop) {
furi_hal_rtc_set_pin_fails(0);
if(with_pin) {
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_open(cli, &cli_vcp);
furi_record_close(RECORD_CLI);
Bt* bt = furi_record_open(RECORD_BT);
bt_open_rpc_connection(bt);
furi_record_close(RECORD_BT);
if(!momentum_settings.allow_locked_rpc_usb) {
Cli* cli = furi_record_open(RECORD_CLI);
cli_session_open(cli, &cli_vcp);
furi_record_close(RECORD_CLI);
}
if(!momentum_settings.allow_locked_rpc_ble) {
Bt* bt = furi_record_open(RECORD_BT);
bt_open_rpc_connection(bt);
furi_record_close(RECORD_BT);
}
}
DesktopStatus status = {.locked = false};
+41 -15
View File
@@ -294,27 +294,53 @@ void canvas_draw_bitmap(
canvas_draw_u8g2_bitmap(&canvas->fb, x, y, width, height, bitmap_data, IconRotation0);
}
static void _canvas_draw_icon_animation(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
IconAnimation* icon_animation) {
furi_check(canvas);
furi_check(icon_animation);
// Ensure scale % is > 0
furi_assert(width_scale > 0 && height_scale > 0);
// Ensure scale % is <= 100: animated icons > 100% are buggy
// TODO: Future, allow scaling > 100
furi_assert(width_scale <= 100 && height_scale <= 100);
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(
canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data);
int32_t width = icon_animation_get_width(icon_animation);
int32_t height = icon_animation_get_height(icon_animation);
int32_t width_scaled = (width * width_scale) / 100;
int32_t height_scaled = (height * height_scale) / 100;
canvas_draw_u8g2_bitmap(
&canvas->fb, x, y, width_scaled, height_scaled, icon_data, IconRotation0);
}
void canvas_draw_icon_animation(
Canvas* canvas,
int32_t x,
int32_t y,
IconAnimation* icon_animation) {
furi_check(canvas);
furi_check(icon_animation);
_canvas_draw_icon_animation(canvas, x, y, 100, 100, icon_animation);
}
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(
canvas->compress_icon, icon_animation_get_data(icon_animation), &icon_data);
canvas_draw_u8g2_bitmap(
&canvas->fb,
x,
y,
icon_animation_get_width(icon_animation),
icon_animation_get_height(icon_animation),
icon_data,
IconRotation0);
void canvas_draw_icon_animation_ex(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
IconAnimation* icon_animation) {
_canvas_draw_icon_animation(canvas, x, y, width_scale, height_scale, icon_animation);
}
static void canvas_draw_u8g2_bitmap_int(
+23
View File
@@ -258,6 +258,9 @@ void canvas_draw_icon_ex(
IconRotation rotation);
/** Draw animation at position defined by x,y.
*
* This function is retained for backward compatibility and draws the animation
* at the specified position without scaling.
*
* @param canvas Canvas instance
* @param x x coordinate
@@ -270,6 +273,26 @@ void canvas_draw_icon_animation(
int32_t y,
IconAnimation* icon_animation);
/** Draw animation at position defined by x,y with scaling.
*
* This extended version allows scaling of the animation dimensions by percentage.
* The width and height are scaled independently.
*
* @param canvas Canvas instance
* @param x x coordinate
* @param y y coordinate
* @param width_scale Scaled (%) width of the icon (1100%)
* @param height_scale Scaled (%) height of the icon (1100%)
* @param icon_animation IconAnimation instance
*/
void canvas_draw_icon_animation_ex(
Canvas* canvas,
int32_t x,
int32_t y,
int32_t width_scale,
int32_t height_scale,
IconAnimation* icon_animation);
/** Draw icon at position defined by x,y.
*
* @param canvas Canvas instance
+127 -3
View File
@@ -81,6 +81,24 @@ static void menu_centered_icon(
item->icon);
}
static void menu_centered_icon_scaled(
Canvas* canvas,
MenuItem* item,
size_t x,
size_t y,
size_t width,
size_t height,
size_t width_scale,
size_t height_scale) {
canvas_draw_icon_animation_ex(
canvas,
x + (width - item->icon->icon->width) / 2,
y + (height - item->icon->icon->height) / 2,
width_scale,
height_scale,
item->icon);
}
static size_t menu_scroll_counter(MenuModel* model, bool selected) {
if(!selected) return 0;
size_t scroll_counter = model->scroll_counter;
@@ -391,10 +409,8 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
snprintf(clk, sizeof(clk), "%02u:%02u", hour, min);
canvas_draw_str(canvas, 5, 34, clk);
uint32_t battery_capacity = furi_hal_power_get_battery_full_capacity();
uint32_t battery_remaining = furi_hal_power_get_battery_remaining_capacity();
bool ext5v = furi_hal_power_is_otg_enabled();
uint16_t battery_percent = (battery_remaining * 100) / battery_capacity;
uint8_t battery_percent = furi_hal_power_get_pct();
bool charge_state = false;
// Determine charge state
@@ -442,6 +458,112 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
}
break;
}
case MenuStyleCoverFlow: {
canvas_set_font(canvas, FontPrimary);
// Draw frames
canvas_set_bitmap_mode(canvas, true);
canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_draw_frame(canvas, 44, 2, 40, 40);
// Draw left side albums
canvas_draw_line(canvas, 6, 40, 17, 35);
canvas_draw_line(canvas, 19, 40, 30, 35);
canvas_draw_line(canvas, 32, 40, 43, 35);
canvas_draw_line(canvas, 6, 3, 17, 8);
canvas_draw_line(canvas, 19, 3, 30, 8);
canvas_draw_line(canvas, 32, 3, 43, 8);
canvas_draw_line(canvas, 18, 2, 18, 41);
canvas_draw_line(canvas, 31, 2, 31, 41);
canvas_draw_line(canvas, 5, 2, 5, 41);
canvas_draw_line(canvas, 4, 8, 1, 7);
canvas_draw_line(canvas, 5, 35, 1, 36);
// Draw right side albums
canvas_draw_line(canvas, 95, 40, 84, 35);
canvas_draw_line(canvas, 108, 40, 97, 35);
canvas_draw_line(canvas, 121, 40, 110, 35);
canvas_draw_line(canvas, 84, 8, 95, 3);
canvas_draw_line(canvas, 97, 8, 108, 3);
canvas_draw_line(canvas, 110, 8, 121, 3);
canvas_draw_line(canvas, 96, 2, 96, 41);
canvas_draw_line(canvas, 109, 2, 109, 41);
canvas_draw_line(canvas, 122, 2, 122, 41);
canvas_draw_line(canvas, 123, 8, 126, 7);
canvas_draw_line(canvas, 123, 35, 126, 36);
const int32_t pos_x_center = 128 / 2;
const int32_t pos_y_center = 64 / 2;
const int32_t pos_y_offset = 10;
const int32_t icon_size = 20;
const int32_t side_icon_width = icon_size / 2;
const int32_t padding_center_icon = 14;
const int32_t spacing_between_icons = 3;
const int32_t scale_base = 100;
MenuItem* center_item = NULL;
// Draw 7 icons, where index 0 is the center icon
// [-3, -2, -1, 0, 1, 2, 3]
for(int8_t i = -3; i <= 3; i++) {
shift_position = (position + items_count + i) % items_count;
item = MenuItemArray_get(model->items, shift_position);
int32_t pos_x = pos_x_center;
int32_t pos_y = pos_y_center;
int32_t scale_width = scale_base;
int32_t scale_height = scale_base;
if(i < 0) {
// Left sided icons
pos_x -= padding_center_icon;
pos_x -= ((-i) * (side_icon_width + spacing_between_icons));
pos_x -= (side_icon_width / 2) / 2;
pos_y = (pos_y_center - icon_size / 2) - pos_y_offset;
scale_width = 50;
} else if(i > 0) {
// Right sided icons
pos_x += padding_center_icon;
pos_x += (i * (side_icon_width + spacing_between_icons));
pos_x -= side_icon_width;
pos_y = (pos_y_center - icon_size / 2) - pos_y_offset;
scale_width = 50;
} else if(i == 0) {
// Center icon
pos_x -= icon_size / 2;
pos_y = (pos_y_center - (icon_size / 2)) - pos_y_offset;
// Scaling > 100% doesn't look good, keep 100% for now
scale_width = scale_base; // TODO: 200%
scale_height = scale_base; // TODO: 200%
// Save center item pointer for later
center_item = item;
}
// Draw the icon
menu_centered_icon_scaled(
canvas, item, pos_x, pos_y, icon_size, icon_size, scale_width, scale_height);
}
// Draw label for center item
if(center_item) {
menu_get_name(center_item, name, false);
elements_scrollable_text_line_centered(
canvas,
pos_x_center,
(pos_y_center + icon_size / 2) + pos_y_offset,
126,
name,
0,
false,
true);
}
// Add scrollbar element
elements_scrollbar_horizontal(canvas, 0, 60, 128, position, items_count);
break;
}
default:
break;
}
@@ -792,6 +914,7 @@ static void menu_process_left(Menu* menu) {
case MenuStyleDsi:
case MenuStylePs4:
case MenuStyleVertical:
case MenuStyleCoverFlow:
size_t vertical_offset = model->vertical_offset;
if(position > 0) {
position--;
@@ -856,6 +979,7 @@ static void menu_process_right(Menu* menu) {
case MenuStyleDsi:
case MenuStylePs4:
case MenuStyleVertical:
case MenuStyleCoverFlow:
size_t vertical_offset = model->vertical_offset;
if(position < count - 1) {
position++;
+4 -3
View File
@@ -385,9 +385,10 @@ static void
}
RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) {
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock) &&
!momentum_settings.allow_locked_rpc_commands)
return NULL;
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
if(owner == RpcOwnerUsb && !momentum_settings.allow_locked_rpc_usb) return NULL;
if(owner == RpcOwnerBle && !momentum_settings.allow_locked_rpc_ble) return NULL;
}
furi_check(rpc);
+39
View File
@@ -258,6 +258,41 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context)
}
}
static void rpc_system_app_button_press_release(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(request->which_content == PB_Main_app_button_press_release_request_tag);
RpcAppSystem* rpc_app = context;
furi_assert(rpc_app);
if(rpc_app->callback) {
FURI_LOG_D(TAG, "ButtonPressRelease");
RpcAppSystemEvent event;
event.type = RpcAppEventTypeButtonPressRelease;
if(strlen(request->content.app_button_press_release_request.args) != 0) {
event.data.type = RpcAppSystemEventDataTypeString;
event.data.string = request->content.app_button_press_release_request.args;
} else {
event.data.type = RpcAppSystemEventDataTypeInt32;
event.data.i32 = request->content.app_button_press_release_request.index;
}
rpc_system_app_error_reset(rpc_app);
rpc_system_app_set_last_command(rpc_app, request->command_id, &event);
rpc_app->callback(&event, rpc_app->callback_context);
} else {
rpc_system_app_send_error_response(
rpc_app,
request->command_id,
PB_CommandStatus_ERROR_APP_NOT_RUNNING,
"ButtonPressRelease");
}
}
static void rpc_system_app_get_error_process(const PB_Main* request, void* context) {
furi_assert(request);
furi_assert(request->which_content == PB_Main_app_get_error_request_tag);
@@ -332,6 +367,7 @@ void rpc_system_app_confirm(RpcAppSystem* rpc_app, bool result) {
rpc_app->last_event_type == RpcAppEventTypeLoadFile ||
rpc_app->last_event_type == RpcAppEventTypeButtonPress ||
rpc_app->last_event_type == RpcAppEventTypeButtonRelease ||
rpc_app->last_event_type == RpcAppEventTypeButtonPressRelease ||
rpc_app->last_event_type == RpcAppEventTypeDataExchange);
const uint32_t last_command_id = rpc_app->last_command_id;
@@ -432,6 +468,9 @@ void* rpc_system_app_alloc(RpcSession* session) {
rpc_handler.message_handler = rpc_system_app_button_release;
rpc_add_handler(session, PB_Main_app_button_release_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_app_button_press_release;
rpc_add_handler(session, PB_Main_app_button_press_release_request_tag, &rpc_handler);
rpc_handler.message_handler = rpc_system_app_get_error_process;
rpc_add_handler(session, PB_Main_app_get_error_request_tag, &rpc_handler);
+8
View File
@@ -90,6 +90,13 @@ typedef enum {
* all activities to be conducted while a button is being pressed.
*/
RpcAppEventTypeButtonRelease,
/**
* @brief The client has informed the application that a button has been pressed and released.
*
* This command's meaning is application-specific, e.g. to perform an action
* once without repeating it.
*/
RpcAppEventTypeButtonPressRelease,
/**
* @brief The client has sent a byte array of arbitrary size.
*
@@ -162,6 +169,7 @@ void rpc_system_app_send_exited(RpcAppSystem* rpc_app);
* - RpcAppEventTypeLoadFile
* - RpcAppEventTypeButtonPress
* - RpcAppEventTypeButtonRelease
* - RpcAppEventTypeButtonPressRelease
* - RpcAppEventTypeDataExchange
*
* Not confirming these events will result in a client-side timeout.
@@ -62,8 +62,8 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
eastasianwidth@0.2.0:
@@ -240,7 +240,7 @@ snapshots:
color-name@1.1.4: {}
cross-spawn@7.0.3:
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
@@ -256,7 +256,7 @@ snapshots:
foreground-child@3.3.0:
dependencies:
cross-spawn: 7.0.3
cross-spawn: 7.0.6
signal-exit: 4.1.0
get-caller-file@2.0.5: {}
@@ -1,6 +1,6 @@
{
"name": "@next-flip/fz-sdk-mntm",
"version": "0.1.3",
"version": "0.1.4",
"description": "Type declarations and documentation for native JS modules available on Momentum Custom Firmware for Flipper Zero",
"keywords": [
"momentum",
+6 -7
View File
@@ -8,13 +8,6 @@ importers:
.:
dependencies:
prompts:
specifier: ^2.4.2
version: 2.4.2
serialport:
specifier: ^12.0.0
version: 12.0.0
devDependencies:
esbuild:
specifier: ^0.24.0
version: 0.24.0
@@ -24,6 +17,12 @@ importers:
json5:
specifier: ^2.2.3
version: 2.2.3
prompts:
specifier: ^2.4.2
version: 2.4.2
serialport:
specifier: ^12.0.0
version: 12.0.0
typedoc:
specifier: ^0.26.10
version: 0.26.10(typescript@5.6.3)
@@ -91,9 +91,21 @@ async function build(config) {
async function upload(config) {
const appFile = fs.readFileSync(config.input, "utf8");
const flippers = (await SerialPort.list()).filter(x => x.serialNumber?.startsWith("flip_"));
const serialPorts = await SerialPort.list();
if (!flippers) {
let flippers = serialPorts
.filter(x => x.serialNumber?.startsWith("flip_"))
.map(x => ({ path: x.path, name: x.serialNumber.replace("flip_", "") }));
if (!flippers.length) {
// some Windows installations don't report the serial number correctly;
// filter by STM VCP VID:PID instead
flippers = serialPorts
.filter(x => x?.vendorId === "0483" && x?.productId === "5740")
.map(x => ({ path: x.path, name: x.path }));
}
if (!flippers.length) {
console.error("No Flippers found");
process.exit(1);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 414 B

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 486 B

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 B

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 B

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 B

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 500 B

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 483 B

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 B

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 748 B

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 776 B

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 890 B

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 909 B

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 546 B

Some files were not shown because too many files have changed in this diff Show More