mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-07-18 14:36:14 +00:00
Compare commits
3
Commits
dev-d4d8b0e6
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90e1c2b850 | ||
|
|
b6d8d67c6e | ||
|
|
ac8909904e |
@@ -17,45 +17,46 @@ static const char* const button_default_labels[SUBGHZ_BUTTON_LABEL_COUNT] = {
|
||||
|
||||
typedef struct {
|
||||
const char* protocol;
|
||||
uint8_t max_custom_btn;
|
||||
const char* labels[SUBGHZ_BUTTON_LABEL_COUNT];
|
||||
} SubGhzProtocolButtonLabels;
|
||||
|
||||
static const SubGhzProtocolButtonLabels protocol_button_labels[] = {
|
||||
{"VAG GROUP", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Porsche AG", {"Original", "Lock", "Unlock", "Trunk", "Open"}},
|
||||
{"FORD V0", {"Original", "Lock", "Unlock", "Trunk"}},
|
||||
{"Ford V2", {"Unlock", "Lock", "Trunk", "Panic", "Remote Start"}},
|
||||
{"PSA GROUP", {"Original", "Lock", "Unlock", "Trunk", "Trunk"}},
|
||||
{"PSA OLD", {"Original", "Lock", "Unlock", "Trunk", "Trunk"}},
|
||||
{"KIA/HYU V0", {"Original", "Lock", "Unlock", "Trunk", "Horn"}},
|
||||
{"KIA/HYU V1", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"KIA/HYU V2", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"KIA/HYU V3", {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V4", {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V3/V4", {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V5", {"Original", "Unlock", "Lock", "Trunk", "Horn"}},
|
||||
{"KIA/HYU V6", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"SUBARU", {"Original", "Lock", "Unlock", "Trunk", "Panic", "Extra"}},
|
||||
{"SUZUKI", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Star Line", {"Original", "Lock", "Unlock", "Trunk", "Start"}},
|
||||
{"Scher-Khan", {"Original", "Lock", "Unlock", "Trunk", "Start"}},
|
||||
{"Sheriff CFM", {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Nice FloR-S", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"CAME Atomo", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Alutech AT-4N", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"KeeLoq", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Phoenix_V2", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Beninca ARC", {"Original", "Btn 1", "Btn 2"}},
|
||||
{"GangQi", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Hay21", {"Original", "Btn 1", "Btn 2"}},
|
||||
{"Hollarm", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Jarolift", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"KingGates Stylo4k", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Princeton", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Roger", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Security+ 2.0", {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Somfy Telis", {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Faac SLH", {"Original", "Btn 1"}},
|
||||
{"VAG GROUP", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Porsche AG", 4, {"Original", "Lock", "Unlock", "Trunk", "Open"}},
|
||||
{"FORD V0", 3, {"Original", "Lock", "Unlock", "Trunk"}},
|
||||
{"Ford V2", 4, {"Unlock", "Lock", "Trunk", "Panic", "Remote Start"}},
|
||||
{"PSA GROUP", 4, {"Original", "Lock", "Unlock", "Trunk", "Trunk"}},
|
||||
{"PSA OLD", 4, {"Original", "Lock", "Unlock", "Trunk", "Trunk"}},
|
||||
{"KIA/HYU V0", 4, {"Original", "Lock", "Unlock", "Trunk", "Horn"}},
|
||||
{"KIA/HYU V1", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"KIA/HYU V2", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"KIA/HYU V3", 5, {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V4", 5, {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V3/V4", 5, {"Original", "Lock", "Unlock", "Trunk", "Panic", "Horn"}},
|
||||
{"KIA/HYU V5", 4, {"Original", "Unlock", "Lock", "Trunk", "Horn"}},
|
||||
{"KIA/HYU V6", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"SUBARU", 5, {"Original", "Lock", "Unlock", "Trunk", "Panic", "Extra"}},
|
||||
{"SUZUKI", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Star Line", 4, {"Original", "Lock", "Unlock", "Trunk", "Start"}},
|
||||
{"Scher-Khan", 4, {"Original", "Lock", "Unlock", "Trunk", "Start"}},
|
||||
{"Sheriff CFM", 4, {"Original", "Lock", "Unlock", "Trunk", "Panic"}},
|
||||
{"Nice FloR-S", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"CAME Atomo", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Alutech AT-4N", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"KeeLoq", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Phoenix_V2", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Beninca ARC", 2, {"Original", "Btn 1", "Btn 2"}},
|
||||
{"GangQi", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Hay21", 2, {"Original", "Btn 1", "Btn 2"}},
|
||||
{"Hollarm", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Jarolift", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"KingGates Stylo4k", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Princeton", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Roger", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Security+ 2.0", 4, {"Original", "Btn 1", "Btn 2", "Btn 3", "Btn 4"}},
|
||||
{"Somfy Telis", 3, {"Original", "Btn 1", "Btn 2", "Btn 3"}},
|
||||
{"Faac SLH", 1, {"Original", "Btn 1"}},
|
||||
};
|
||||
|
||||
void subghz_button_labels_reset(const char* labels[SUBGHZ_BUTTON_LABEL_COUNT]) {
|
||||
@@ -98,3 +99,15 @@ const char* subghz_button_labels_get(
|
||||
|
||||
return "Button";
|
||||
}
|
||||
|
||||
uint8_t subghz_button_labels_get_max_custom_btn(const char* protocol) {
|
||||
if(!protocol) return 0;
|
||||
|
||||
for(uint8_t i = 0; i < COUNT_OF(protocol_button_labels); i++) {
|
||||
if(strcmp(protocol, protocol_button_labels[i].protocol) == 0) {
|
||||
return protocol_button_labels[i].max_custom_btn;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ const char* subghz_button_labels_get(
|
||||
uint8_t custom_btn_id,
|
||||
uint8_t original_custom_btn);
|
||||
|
||||
uint8_t subghz_button_labels_get_max_custom_btn(const char* protocol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <notification/notification_messages.h>
|
||||
#include "../helpers/subghz_txrx_i.h"
|
||||
#include <lib/subghz/blocks/custom_btn_i.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TAG "SubGhzSceneCarEmulate"
|
||||
#define MIN_TX_TICKS 66U /* ~666 ms at 100 ms tick */
|
||||
@@ -30,6 +31,9 @@ typedef struct {
|
||||
uint32_t freq;
|
||||
char preset_short[12]; /* "AM650", "FM476", … */
|
||||
|
||||
bool has_serial;
|
||||
bool has_counter;
|
||||
|
||||
/* TX state */
|
||||
bool is_transmitting;
|
||||
bool stop_pending; /* stop requested before MIN_TX_TICKS elapsed */
|
||||
@@ -203,6 +207,99 @@ static void car_emulate_read_freq_preset(SubGhz* subghz, CarEmulateState* st) {
|
||||
furi_string_free(preset_str);
|
||||
}
|
||||
|
||||
static bool car_emulate_hex_digit(char c, uint8_t* value) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
*value = c - '0';
|
||||
return true;
|
||||
} else if(c >= 'a' && c <= 'f') {
|
||||
*value = c - 'a' + 10;
|
||||
return true;
|
||||
} else if(c >= 'A' && c <= 'F') {
|
||||
*value = c - 'A' + 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool car_emulate_parse_hex_after(
|
||||
const char* text,
|
||||
const char* marker,
|
||||
uint32_t* value) {
|
||||
const char* field = strstr(text, marker);
|
||||
if(!field) return false;
|
||||
|
||||
field += strlen(marker);
|
||||
while(*field == ' ' || *field == '\t' || *field == '[') {
|
||||
field++;
|
||||
}
|
||||
if(field[0] == '0' && (field[1] == 'x' || field[1] == 'X')) {
|
||||
field += 2;
|
||||
}
|
||||
|
||||
uint32_t parsed = 0;
|
||||
uint8_t digits = 0;
|
||||
uint8_t digit_value = 0;
|
||||
while((digits < 8) && car_emulate_hex_digit(*field, &digit_value)) {
|
||||
parsed = (parsed << 4) | digit_value;
|
||||
digits++;
|
||||
field++;
|
||||
}
|
||||
|
||||
if(digits == 0) return false;
|
||||
*value = parsed;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool car_emulate_serial_is_placeholder(void) {
|
||||
return !s_state->has_serial || (s_state->serial <= 1);
|
||||
}
|
||||
|
||||
static bool car_emulate_counter_is_placeholder(void) {
|
||||
return !s_state->has_counter || (s_state->current_counter == 0);
|
||||
}
|
||||
|
||||
static void car_emulate_set_counter(uint32_t value) {
|
||||
s_state->original_counter = value;
|
||||
s_state->current_counter = value;
|
||||
s_state->has_counter = true;
|
||||
}
|
||||
|
||||
static void car_emulate_apply_global_metadata(void) {
|
||||
furi_assert(s_state);
|
||||
|
||||
if(subghz_block_generic_global.cnt_is_available) {
|
||||
car_emulate_set_counter(subghz_block_generic_global.current_cnt);
|
||||
}
|
||||
}
|
||||
|
||||
static void car_emulate_apply_decoded_metadata(FuriString* decoded_text) {
|
||||
furi_assert(s_state);
|
||||
if(!decoded_text) return;
|
||||
|
||||
const char* text = furi_string_get_cstr(decoded_text);
|
||||
uint32_t value = 0;
|
||||
|
||||
if((car_emulate_parse_hex_after(text, "Sn:", &value) ||
|
||||
car_emulate_parse_hex_after(text, "SN:", &value) ||
|
||||
car_emulate_parse_hex_after(text, "Ser:", &value) ||
|
||||
car_emulate_parse_hex_after(text, "Serial:", &value)) &&
|
||||
(value != 0)) {
|
||||
s_state->serial = value;
|
||||
s_state->has_serial = true;
|
||||
} else if(
|
||||
car_emulate_serial_is_placeholder() &&
|
||||
car_emulate_parse_hex_after(text, "Fix:", &value) &&
|
||||
(value != 0)) {
|
||||
s_state->serial = value;
|
||||
s_state->has_serial = true;
|
||||
}
|
||||
|
||||
if(car_emulate_parse_hex_after(text, "Cnt:", &value) &&
|
||||
((value != 0) || car_emulate_counter_is_placeholder())) {
|
||||
car_emulate_set_counter(value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Update Btn and Cnt fields in fff_data so the transmitter re-serialises them. */
|
||||
static bool car_emulate_apply_button(SubGhz* subghz, InputKey key) {
|
||||
UNUSED(subghz);
|
||||
@@ -337,7 +434,8 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
flipper_format_read_uint32(fff, "Serial", &s_state->serial, 1);
|
||||
s_state->has_serial =
|
||||
flipper_format_read_uint32(fff, "Serial", &s_state->serial, 1);
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
uint32_t btn_tmp = 0;
|
||||
@@ -346,7 +444,8 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
}
|
||||
|
||||
flipper_format_rewind(fff);
|
||||
flipper_format_read_uint32(fff, "Cnt", &s_state->original_counter, 1);
|
||||
s_state->has_counter =
|
||||
flipper_format_read_uint32(fff, "Cnt", &s_state->original_counter, 1);
|
||||
s_state->current_counter = s_state->original_counter;
|
||||
|
||||
furi_string_free(tmp);
|
||||
@@ -362,6 +461,7 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
* - subghz_custom_btn_get_original() → the button that was in the file
|
||||
* - subghz_custom_btn_is_allowed() → true if protocol supports it
|
||||
* - subghz_custom_btn_get_max() → number of buttons available */
|
||||
subghz_block_generic_global_reset(NULL);
|
||||
subghz_custom_btns_reset();
|
||||
|
||||
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
||||
@@ -370,6 +470,8 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
if(subghz_protocol_decoder_base_deserialize(decoder, fff) == SubGhzProtocolStatusOk) {
|
||||
FuriString* decoded_text = furi_string_alloc();
|
||||
subghz_protocol_decoder_base_get_string(decoder, decoded_text);
|
||||
car_emulate_apply_global_metadata();
|
||||
car_emulate_apply_decoded_metadata(decoded_text);
|
||||
furi_string_free(decoded_text);
|
||||
}
|
||||
/* Rewind again so subsequent reads in car_emulate_read_freq_preset()
|
||||
@@ -379,6 +481,13 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
|
||||
s_state->max_custom_button =
|
||||
subghz_custom_btn_is_allowed() ? subghz_custom_btn_get_max() : SUBGHZ_CUSTOM_BTN_OK;
|
||||
if(s_state->max_custom_button == SUBGHZ_CUSTOM_BTN_OK) {
|
||||
s_state->max_custom_button =
|
||||
subghz_button_labels_get_max_custom_btn(s_state->protocol_name);
|
||||
if(s_state->max_custom_button != SUBGHZ_CUSTOM_BTN_OK) {
|
||||
subghz_custom_btn_set_max(s_state->max_custom_button);
|
||||
}
|
||||
}
|
||||
|
||||
const char* button_labels[SUBGHZ_BUTTON_LABEL_COUNT];
|
||||
subghz_button_labels_reset(button_labels);
|
||||
|
||||
Reference in New Issue
Block a user