mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-07-14 01:08:49 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b34a73b08a | |||
| 069a42d697 | |||
| 2a182a2f5c | |||
| b13f42f8bc |
@@ -34,7 +34,7 @@ typedef struct {
|
||||
bool stop_pending; /* stop requested before MIN_TX_TICKS elapsed */
|
||||
uint32_t tx_start_tick;
|
||||
|
||||
/* Pending button key (InputKey) decoded from the packed custom event */
|
||||
/* Resolved custom button repeated while the physical key is held */
|
||||
uint8_t pending_button;
|
||||
} CarEmulateState;
|
||||
|
||||
@@ -252,12 +252,34 @@ static bool car_emulate_start_tx(SubGhz* subghz, uint8_t custom_btn_id) {
|
||||
|
||||
/** Stop an active transmission. */
|
||||
static void car_emulate_stop_tx(SubGhz* subghz) {
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
subghz_txrx_stop(subghz->txrx);
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
FURI_LOG_I(TAG, "TX stopped");
|
||||
}
|
||||
|
||||
static bool car_emulate_restart_tx(SubGhz* subghz) {
|
||||
furi_assert(s_state);
|
||||
|
||||
car_emulate_update_fff(subghz, s_state->current_counter);
|
||||
subghz_block_generic_global.endless_tx = true;
|
||||
|
||||
if(car_emulate_start_tx(subghz, s_state->pending_button)) {
|
||||
s_state->is_transmitting = true;
|
||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||
notification_message(subghz->notifications, &sequence_blink_magenta_10);
|
||||
FURI_LOG_D(TAG, "TX restarted while button is held");
|
||||
return true;
|
||||
}
|
||||
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
notification_message(subghz->notifications, &sequence_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════════════
|
||||
* View callback (fired from the View's input handler)
|
||||
* ═════════════════════════════════════════════════════════════════════════*/
|
||||
@@ -293,6 +315,7 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
||||
s_state = malloc(sizeof(CarEmulateState));
|
||||
furi_check(s_state);
|
||||
memset(s_state, 0, sizeof(CarEmulateState));
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
|
||||
/* ── Read metadata from the loaded fff_data ── */
|
||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||
@@ -401,8 +424,11 @@ bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
s_state->tx_start_tick = (uint32_t)furi_get_tick();
|
||||
|
||||
uint8_t cur_btn = subghz_custom_btn_get();
|
||||
s_state->pending_button = cur_btn;
|
||||
subghz_block_generic_global.endless_tx = true;
|
||||
if(!car_emulate_start_tx(subghz, cur_btn)) {
|
||||
s_state->is_transmitting = false;
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
notification_message(subghz->notifications, &sequence_error);
|
||||
}
|
||||
|
||||
@@ -411,11 +437,13 @@ bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
/* ── Stop ── */
|
||||
} else if(event.event == SubGhzCustomEventCarEmulateStop) {
|
||||
if(s_state->is_transmitting &&
|
||||
subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
if(s_state->is_transmitting) {
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
|
||||
uint32_t elapsed = (uint32_t)furi_get_tick() - s_state->tx_start_tick;
|
||||
if(elapsed >= MIN_TX_TICKS) {
|
||||
if(
|
||||
elapsed >= MIN_TX_TICKS &&
|
||||
subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
@@ -431,6 +459,7 @@ bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
if(subghz->state_notifications == SubGhzNotificationStateTx) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
}
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSavedMenu);
|
||||
consumed = true;
|
||||
@@ -450,6 +479,8 @@ bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
||||
s_state->is_transmitting = false;
|
||||
s_state->stop_pending = false;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
} else {
|
||||
car_emulate_restart_tx(subghz);
|
||||
}
|
||||
} else {
|
||||
/* Still transmitting – blink LED */
|
||||
@@ -485,6 +516,7 @@ void subghz_scene_car_emulate_on_exit(void* context) {
|
||||
car_emulate_stop_tx(subghz);
|
||||
}
|
||||
|
||||
subghz_block_generic_global.endless_tx = false;
|
||||
subghz->state_notifications = SubGhzNotificationStateIDLE;
|
||||
notification_message(subghz->notifications, &sequence_blink_stop);
|
||||
|
||||
|
||||
@@ -187,12 +187,15 @@ bool subghz_scene_keeloq_decrypt_on_event(void* context, SceneManagerEvent event
|
||||
if(!subghz->keeloq_keys_manager) {
|
||||
subghz->keeloq_keys_manager = subghz_keeloq_keys_alloc();
|
||||
}
|
||||
uint16_t learning_type = ctx->recovered_type ?
|
||||
ctx->recovered_type :
|
||||
KEELOQ_LEARNING_SIMPLE;
|
||||
char key_name[24];
|
||||
snprintf(key_name, sizeof(key_name), "BF_%07lX", ctx->serial);
|
||||
subghz_keeloq_keys_add(
|
||||
subghz->keeloq_keys_manager,
|
||||
ctx->recovered_mfkey,
|
||||
KEELOQ_LEARNING_SIMPLE,
|
||||
learning_type,
|
||||
key_name);
|
||||
subghz_keeloq_keys_save(subghz->keeloq_keys_manager);
|
||||
|
||||
@@ -202,7 +205,7 @@ bool subghz_scene_keeloq_decrypt_on_event(void* context, SceneManagerEvent event
|
||||
SubGhzKey* entry = SubGhzKeyArray_push_raw(*env_arr);
|
||||
entry->name = furi_string_alloc_set(key_name);
|
||||
entry->key = ctx->recovered_mfkey;
|
||||
entry->type = KEELOQ_LEARNING_SIMPLE;
|
||||
entry->type = learning_type;
|
||||
return true;
|
||||
|
||||
} else if(event.event == KL_DECRYPT_EVENT_DONE) {
|
||||
|
||||
@@ -407,7 +407,7 @@ LevelDuration subghz_protocol_encoder_fiat_spa_yield(void* context) {
|
||||
}
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -364,7 +364,7 @@ LevelDuration subghz_protocol_encoder_ford_v0_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1278,8 +1278,9 @@ LevelDuration subghz_protocol_encoder_ford_v1_yield(void* context) {
|
||||
"Encoder yield: finished one full %lu-word frame (all %u bursts); repeats_left=%u",
|
||||
(unsigned long)instance->encoder.size_upload,
|
||||
(unsigned)FORD_V1_ENC_BURST_COUNT,
|
||||
(unsigned)instance->encoder.repeat - 1U);
|
||||
instance->encoder.repeat--;
|
||||
subghz_block_generic_global.endless_tx ? (unsigned)instance->encoder.repeat :
|
||||
(unsigned)instance->encoder.repeat - 1U);
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
} else if(instance->encoder.front <= 4U) {
|
||||
uint32_t raw_word;
|
||||
|
||||
@@ -615,7 +615,7 @@ LevelDuration subghz_protocol_encoder_ford_v2_yield(void* context) {
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.front = 0U;
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -154,7 +154,7 @@ LevelDuration subghz_protocol_encoder_kia_yield(void* context) {
|
||||
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
@@ -594,4 +594,3 @@ void subghz_protocol_decoder_kia_get_string(void* context, FuriString* output) {
|
||||
received_crc,
|
||||
crc_valid ? "(OK)" : "(FAIL)");
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ LevelDuration subghz_protocol_encoder_kia_v1_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ LevelDuration subghz_protocol_encoder_kia_v2_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -648,7 +648,7 @@ LevelDuration subghz_protocol_encoder_kia_v3_v4_yield(void* context) {
|
||||
instance->crc_iter = (uint8_t)((instance->crc_iter + 1U) & 0x0FU);
|
||||
subghz_protocol_encoder_kia_v3_v4_patch_crc(instance);
|
||||
instance->encoder.front = 0;
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
if(instance->bursts_sent < 16U) {
|
||||
instance->bursts_sent++;
|
||||
}
|
||||
|
||||
@@ -95,8 +95,7 @@ static uint16_t mixer_decode(uint32_t encrypted) {
|
||||
return (s0 + (s1 << 8)) & 0xFFFF;
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t mixer_encode(
|
||||
uint32_t serial, uint16_t counter, uint8_t button) {
|
||||
static uint32_t mixer_encode(uint32_t serial, uint16_t counter, uint8_t button) {
|
||||
uint8_t s0 = (uint8_t)(((serial >> 8) & 0x0FU) | ((button & 0x0FU) << 4));
|
||||
uint8_t s1 = (uint8_t)((counter >> 8) & 0xFFU);
|
||||
uint8_t s2 = (uint8_t)(serial & 0xFFU);
|
||||
@@ -156,6 +155,17 @@ static __attribute__((unused)) uint32_t mixer_encode(
|
||||
return ((uint32_t)s0 << 24) | ((uint32_t)s2 << 16) | ((uint32_t)s1 << 8) | (uint32_t)s3;
|
||||
}
|
||||
|
||||
static uint64_t kia_v5_encode_data(uint32_t serial, uint16_t counter, uint8_t button) {
|
||||
serial &= 0x0FFFFFFFU;
|
||||
button &= 0x0FU;
|
||||
|
||||
const uint32_t encrypted = mixer_encode(serial, counter, button);
|
||||
const uint64_t yek =
|
||||
((uint64_t)button << 60) | ((uint64_t)serial << 32) | (uint64_t)encrypted;
|
||||
|
||||
return bit_reverse_64(yek);
|
||||
}
|
||||
|
||||
struct SubGhzProtocolDecoderKiaV5 {
|
||||
SubGhzProtocolDecoderBase base;
|
||||
SubGhzBlockDecoder decoder;
|
||||
@@ -326,6 +336,8 @@ SubGhzProtocolStatus
|
||||
}
|
||||
subghz_custom_btn_set_max(4);
|
||||
|
||||
instance->generic.data = kia_v5_encode_data(
|
||||
instance->generic.serial, instance->generic.cnt, instance->generic.btn);
|
||||
instance->replay_data = instance->generic.data;
|
||||
instance->replay_crc = kia_v5_calculate_crc(instance->replay_data);
|
||||
|
||||
@@ -444,7 +456,7 @@ LevelDuration subghz_protocol_encoder_kia_v5_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
@@ -675,10 +687,13 @@ SubGhzProtocolStatus
|
||||
furi_assert(context);
|
||||
SubGhzProtocolDecoderKiaV5* instance = context;
|
||||
|
||||
SubGhzProtocolStatus ret = subghz_block_generic_deserialize_check_count_bit(
|
||||
&instance->generic,
|
||||
flipper_format,
|
||||
subghz_protocol_kia_v5_const.min_count_bit_for_found);
|
||||
SubGhzProtocolStatus ret = subghz_block_generic_deserialize(&instance->generic, flipper_format);
|
||||
|
||||
if((ret == SubGhzProtocolStatusOk) &&
|
||||
(instance->generic.data_count_bit <
|
||||
subghz_protocol_kia_v5_const.min_count_bit_for_found)) {
|
||||
ret = SubGhzProtocolStatusErrorParserBitCount;
|
||||
}
|
||||
|
||||
if(ret == SubGhzProtocolStatusOk) {
|
||||
flipper_format_rewind(flipper_format);
|
||||
|
||||
@@ -791,7 +791,7 @@ LevelDuration subghz_protocol_encoder_kia_v6_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
instance->encoder.front++;
|
||||
if(instance->encoder.front >= instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -431,7 +431,7 @@ LevelDuration kia_protocol_encoder_v7_yield(void* context) {
|
||||
LevelDuration duration = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -969,7 +969,7 @@ LevelDuration subghz_protocol_encoder_land_rover_v0_yield(void* context) {
|
||||
|
||||
if(instance->encoder.front >= instance->encoder.size_upload) {
|
||||
/* One full repetition done; count it down */
|
||||
if(instance->encoder.repeat > 0) {
|
||||
if(instance->encoder.repeat > 0 && !subghz_block_generic_global.endless_tx) {
|
||||
instance->encoder.repeat--;
|
||||
}
|
||||
instance->encoder.front = 0;
|
||||
|
||||
@@ -499,7 +499,7 @@ LevelDuration subghz_protocol_encoder_mazda_v0_yield(void* context) {
|
||||
LevelDuration out = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ LevelDuration subghz_protocol_encoder_mitsubishi_v0_yield(void* context) {
|
||||
if(!instance->encoder.is_running || instance->encoder.repeat == 0) return level_duration_reset();
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -621,7 +621,7 @@ LevelDuration subghz_protocol_encoder_porsche_cayenne_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1932,7 +1932,7 @@ LevelDuration subghz_protocol_encoder_psa_yield(void* context) {
|
||||
instance->encoder.front++;
|
||||
if(instance->encoder.front >= instance->encoder.size_upload) {
|
||||
instance->encoder.front = 0;
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
if(instance->encoder.repeat <= 0) instance->is_running = false;
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -622,7 +622,7 @@ LevelDuration subghz_protocol_encoder_scher_khan_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ LevelDuration subghz_protocol_encoder_sheriff_cfm_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -556,7 +556,7 @@ LevelDuration subghz_protocol_encoder_star_line_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ LevelDuration subghz_protocol_encoder_subaru_yield(void* context) {
|
||||
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
|
||||
|
||||
if(++instance->encoder.front == instance->encoder.size_upload) {
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@ LevelDuration subghz_protocol_encoder_suzuki_yield(void *context)
|
||||
|
||||
if (++instance->encoder.front == instance->encoder.size_upload)
|
||||
{
|
||||
instance->encoder.repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->encoder.repeat--;
|
||||
instance->encoder.front = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1358,7 +1358,7 @@ LevelDuration subghz_protocol_encoder_vag_yield(void* context) {
|
||||
|
||||
if(instance->front >= instance->size_upload) {
|
||||
instance->front = 0;
|
||||
instance->repeat--;
|
||||
if(!subghz_block_generic_global.endless_tx) instance->repeat--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user