mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-07-18 11:36:14 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d8b0e646 | ||
|
|
36483ec07d | ||
|
|
807e74b7d6 | ||
|
|
f4fe2d48c1 |
@@ -0,0 +1,100 @@
|
|||||||
|
#include "subghz_button_labels.h"
|
||||||
|
|
||||||
|
#include <furi.h>
|
||||||
|
#include <lib/subghz/blocks/custom_btn.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char* const button_default_labels[SUBGHZ_BUTTON_LABEL_COUNT] = {
|
||||||
|
"Original",
|
||||||
|
"Up",
|
||||||
|
"Down",
|
||||||
|
"Left",
|
||||||
|
"Right",
|
||||||
|
"Button 5",
|
||||||
|
"Button 6",
|
||||||
|
"Button 7",
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* protocol;
|
||||||
|
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"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
void subghz_button_labels_reset(const char* labels[SUBGHZ_BUTTON_LABEL_COUNT]) {
|
||||||
|
for(uint8_t i = 0; i < SUBGHZ_BUTTON_LABEL_COUNT; i++) {
|
||||||
|
labels[i] = button_default_labels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_button_labels_apply_protocol(
|
||||||
|
const char* protocol,
|
||||||
|
const char* labels[SUBGHZ_BUTTON_LABEL_COUNT]) {
|
||||||
|
if(!protocol) return;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < COUNT_OF(protocol_button_labels); i++) {
|
||||||
|
if(strcmp(protocol, protocol_button_labels[i].protocol) == 0) {
|
||||||
|
for(uint8_t btn = 0; btn < SUBGHZ_BUTTON_LABEL_COUNT; btn++) {
|
||||||
|
if(protocol_button_labels[i].labels[btn]) {
|
||||||
|
labels[btn] = protocol_button_labels[i].labels[btn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* subghz_button_labels_get(
|
||||||
|
const char* const labels[SUBGHZ_BUTTON_LABEL_COUNT],
|
||||||
|
uint8_t custom_btn_id,
|
||||||
|
uint8_t original_custom_btn) {
|
||||||
|
if(custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) {
|
||||||
|
if((original_custom_btn != SUBGHZ_CUSTOM_BTN_OK) &&
|
||||||
|
(original_custom_btn < SUBGHZ_BUTTON_LABEL_COUNT)) {
|
||||||
|
return labels[original_custom_btn];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(custom_btn_id < SUBGHZ_BUTTON_LABEL_COUNT) {
|
||||||
|
return labels[custom_btn_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Button";
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SUBGHZ_BUTTON_LABEL_COUNT 8
|
||||||
|
|
||||||
|
void subghz_button_labels_reset(const char* labels[SUBGHZ_BUTTON_LABEL_COUNT]);
|
||||||
|
|
||||||
|
void subghz_button_labels_apply_protocol(
|
||||||
|
const char* protocol,
|
||||||
|
const char* labels[SUBGHZ_BUTTON_LABEL_COUNT]);
|
||||||
|
|
||||||
|
const char* subghz_button_labels_get(
|
||||||
|
const char* const labels[SUBGHZ_BUTTON_LABEL_COUNT],
|
||||||
|
uint8_t custom_btn_id,
|
||||||
|
uint8_t original_custom_btn);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include "../views/subghz_car_emulate.h"
|
#include "../views/subghz_car_emulate.h"
|
||||||
|
#include "../helpers/subghz_button_labels.h"
|
||||||
#include "../helpers/subghz_custom_event.h"
|
#include "../helpers/subghz_custom_event.h"
|
||||||
#include <lib/subghz/blocks/generic.h>
|
#include <lib/subghz/blocks/generic.h>
|
||||||
#include <notification/notification_messages.h>
|
#include <notification/notification_messages.h>
|
||||||
@@ -36,6 +37,7 @@ typedef struct {
|
|||||||
|
|
||||||
/* Resolved custom button repeated while the physical key is held */
|
/* Resolved custom button repeated while the physical key is held */
|
||||||
uint8_t pending_button;
|
uint8_t pending_button;
|
||||||
|
uint8_t max_custom_button;
|
||||||
} CarEmulateState;
|
} CarEmulateState;
|
||||||
|
|
||||||
static CarEmulateState* s_state = NULL;
|
static CarEmulateState* s_state = NULL;
|
||||||
@@ -202,7 +204,7 @@ static void car_emulate_read_freq_preset(SubGhz* subghz, CarEmulateState* st) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Update Btn and Cnt fields in fff_data so the transmitter re-serialises them. */
|
/** Update Btn and Cnt fields in fff_data so the transmitter re-serialises them. */
|
||||||
static void car_emulate_apply_button(SubGhz* subghz, InputKey key) {
|
static bool car_emulate_apply_button(SubGhz* subghz, InputKey key) {
|
||||||
UNUSED(subghz);
|
UNUSED(subghz);
|
||||||
|
|
||||||
uint8_t custom_btn_id;
|
uint8_t custom_btn_id;
|
||||||
@@ -215,7 +217,11 @@ static void car_emulate_apply_button(SubGhz* subghz, InputKey key) {
|
|||||||
default: custom_btn_id = SUBGHZ_CUSTOM_BTN_OK; break;
|
default: custom_btn_id = SUBGHZ_CUSTOM_BTN_OK; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz_custom_btn_set(custom_btn_id);
|
if(custom_btn_id > s_state->max_custom_button) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subghz_custom_btn_set(custom_btn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -361,19 +367,43 @@ void subghz_scene_car_emulate_on_enter(void* context) {
|
|||||||
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
|
||||||
if(decoder && fff) {
|
if(decoder && fff) {
|
||||||
flipper_format_rewind(fff);
|
flipper_format_rewind(fff);
|
||||||
subghz_protocol_decoder_base_deserialize(decoder, fff);
|
if(subghz_protocol_decoder_base_deserialize(decoder, fff) == SubGhzProtocolStatusOk) {
|
||||||
|
FuriString* decoded_text = furi_string_alloc();
|
||||||
|
subghz_protocol_decoder_base_get_string(decoder, decoded_text);
|
||||||
|
furi_string_free(decoded_text);
|
||||||
|
}
|
||||||
/* Rewind again so subsequent reads in car_emulate_read_freq_preset()
|
/* Rewind again so subsequent reads in car_emulate_read_freq_preset()
|
||||||
* start from the beginning of the file. */
|
* start from the beginning of the file. */
|
||||||
flipper_format_rewind(fff);
|
flipper_format_rewind(fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
subghz_car_emulate_view_set_labels(
|
s_state->max_custom_button =
|
||||||
|
subghz_custom_btn_is_allowed() ? subghz_custom_btn_get_max() : SUBGHZ_CUSTOM_BTN_OK;
|
||||||
|
|
||||||
|
const char* button_labels[SUBGHZ_BUTTON_LABEL_COUNT];
|
||||||
|
subghz_button_labels_reset(button_labels);
|
||||||
|
subghz_button_labels_apply_protocol(s_state->protocol_name, button_labels);
|
||||||
|
|
||||||
|
subghz_car_emulate_view_set_labels(
|
||||||
subghz->car_emulate_view,
|
subghz->car_emulate_view,
|
||||||
"UNLOCK", /* OK */
|
subghz_button_labels_get(
|
||||||
"LOCK", /* Up */
|
button_labels, SUBGHZ_CUSTOM_BTN_OK, subghz_custom_btn_get_original()),
|
||||||
"TRUNK", /* Down */
|
s_state->max_custom_button >= SUBGHZ_CUSTOM_BTN_UP ?
|
||||||
"PANIC", /* Left */
|
subghz_button_labels_get(
|
||||||
"START" /* Right */
|
button_labels, SUBGHZ_CUSTOM_BTN_UP, subghz_custom_btn_get_original()) :
|
||||||
|
"",
|
||||||
|
s_state->max_custom_button >= SUBGHZ_CUSTOM_BTN_DOWN ?
|
||||||
|
subghz_button_labels_get(
|
||||||
|
button_labels, SUBGHZ_CUSTOM_BTN_DOWN, subghz_custom_btn_get_original()) :
|
||||||
|
"",
|
||||||
|
s_state->max_custom_button >= SUBGHZ_CUSTOM_BTN_LEFT ?
|
||||||
|
subghz_button_labels_get(
|
||||||
|
button_labels, SUBGHZ_CUSTOM_BTN_LEFT, subghz_custom_btn_get_original()) :
|
||||||
|
"",
|
||||||
|
s_state->max_custom_button >= SUBGHZ_CUSTOM_BTN_RIGHT ?
|
||||||
|
subghz_button_labels_get(
|
||||||
|
button_labels, SUBGHZ_CUSTOM_BTN_RIGHT, subghz_custom_btn_get_original()) :
|
||||||
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
car_emulate_read_freq_preset(subghz, s_state);
|
car_emulate_read_freq_preset(subghz, s_state);
|
||||||
@@ -407,14 +437,18 @@ bool subghz_scene_car_emulate_on_event(void* context, SceneManagerEvent event) {
|
|||||||
car_emulate_stop_tx(subghz);
|
car_emulate_stop_tx(subghz);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bump counter */
|
|
||||||
s_state->current_counter++;
|
|
||||||
|
|
||||||
/* Set the custom button BEFORE deserialize() is called inside
|
/* Set the custom button BEFORE deserialize() is called inside
|
||||||
* subghz_tx_start() → subghz_txrx_tx_start().
|
* subghz_tx_start() → subghz_txrx_tx_start().
|
||||||
* The protocol's deserialize() will call subghz_custom_btn_get()
|
* The protocol's deserialize() will call subghz_custom_btn_get()
|
||||||
* to pick the right button code. */
|
* to pick the right button code. */
|
||||||
car_emulate_apply_button(subghz, key);
|
if(!car_emulate_apply_button(subghz, key)) {
|
||||||
|
notification_message(subghz->notifications, &sequence_error);
|
||||||
|
car_emulate_refresh_view(subghz);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bump counter */
|
||||||
|
s_state->current_counter++;
|
||||||
|
|
||||||
/* Only update the counter in fff_data; the protocol handles Btn. */
|
/* Only update the counter in fff_data; the protocol handles Btn. */
|
||||||
car_emulate_update_fff(subghz, s_state->current_counter);
|
car_emulate_update_fff(subghz, s_state->current_counter);
|
||||||
|
|||||||
@@ -1,105 +1,68 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include <lib/subghz/subghz_protocol_registry.h>
|
#include <lib/subghz/subghz_protocol_registry.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define TAG "SubGhzSceneProtocolList"
|
#define TAG "SubGhzSceneProtocolList"
|
||||||
|
|
||||||
/* ── helpers ──────────────────────────────────────────────────────────────── */
|
typedef struct {
|
||||||
|
SubGhz* subghz;
|
||||||
|
const char* protocol_name;
|
||||||
|
} SubGhzProtocolListItemContext;
|
||||||
|
|
||||||
static bool proto_filter_contains(const char* filter, const char* name) {
|
static SubGhzProtocolListItemContext* protocol_list_item_contexts = NULL;
|
||||||
const char* p = filter;
|
|
||||||
while(*p) {
|
static void subghz_scene_protocol_list_free_contexts(void) {
|
||||||
const char* comma = strchr(p, ',');
|
free(protocol_list_item_contexts);
|
||||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
protocol_list_item_contexts = NULL;
|
||||||
if(len == strlen(name) && strncmp(p, name, len) == 0) return true;
|
|
||||||
if(!comma) break;
|
|
||||||
p = comma + 1;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proto_filter_toggle(char* filter, size_t filter_size, const char* name) {
|
|
||||||
if(proto_filter_contains(filter, name)) {
|
|
||||||
/* remove it */
|
|
||||||
char tmp[256] = {0};
|
|
||||||
const char* p = filter;
|
|
||||||
bool first = true;
|
|
||||||
while(*p) {
|
|
||||||
const char* comma = strchr(p, ',');
|
|
||||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
|
||||||
if(!(len == strlen(name) && strncmp(p, name, len) == 0)) {
|
|
||||||
if(!first) strncat(tmp, ",", sizeof(tmp) - strlen(tmp) - 1);
|
|
||||||
strncat(tmp, p, len < sizeof(tmp) - strlen(tmp) - 1 ? len : 0);
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
if(!comma) break;
|
|
||||||
p = comma + 1;
|
|
||||||
}
|
|
||||||
strncpy(filter, tmp, filter_size - 1);
|
|
||||||
filter[filter_size - 1] = '\0';
|
|
||||||
} else {
|
|
||||||
/* add it */
|
|
||||||
if(filter[0] != '\0') strncat(filter, ",", filter_size - strlen(filter) - 1);
|
|
||||||
strncat(filter, name, filter_size - strlen(filter) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── callbacks ────────────────────────────────────────────────────────────── */
|
|
||||||
|
|
||||||
static void subghz_scene_protocol_list_item_changed(VariableItem* item) {
|
static void subghz_scene_protocol_list_item_changed(VariableItem* item) {
|
||||||
SubGhz* subghz = variable_item_get_context(item);
|
SubGhzProtocolListItemContext* item_context = variable_item_get_context(item);
|
||||||
uint8_t value_index = variable_item_get_current_value_index(item);
|
if(!item_context || !item_context->subghz || !item_context->protocol_name) return;
|
||||||
|
|
||||||
uint32_t proto_idx =
|
SubGhz* subghz = item_context->subghz;
|
||||||
scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneProtocolList);
|
bool should_disable = variable_item_get_current_value_index(item) == 1;
|
||||||
size_t selected =
|
|
||||||
variable_item_list_get_selected_item_index(subghz->variable_item_list);
|
|
||||||
UNUSED(proto_idx);
|
|
||||||
|
|
||||||
const SubGhzProtocol* protocol =
|
bool changed = subghz_last_settings_protocol_filter_set(
|
||||||
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, selected);
|
subghz->last_settings, item_context->protocol_name, should_disable);
|
||||||
if(!protocol) return;
|
bool is_disabled = subghz_last_settings_protocol_filter_contains(
|
||||||
|
subghz->last_settings, item_context->protocol_name);
|
||||||
|
|
||||||
const char* name = protocol->name;
|
variable_item_set_current_value_index(item, is_disabled ? 1 : 0);
|
||||||
|
variable_item_set_current_value_text(item, is_disabled ? "OFF" : "ON");
|
||||||
bool currently_in =
|
if(changed) subghz_last_settings_save(subghz->last_settings);
|
||||||
proto_filter_contains(subghz->last_settings->protocol_filter, name);
|
|
||||||
|
|
||||||
if((value_index == 1) != currently_in) {
|
|
||||||
proto_filter_toggle(
|
|
||||||
subghz->last_settings->protocol_filter,
|
|
||||||
sizeof(subghz->last_settings->protocol_filter),
|
|
||||||
name);
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, value_index ? "ONLY" : "---");
|
|
||||||
subghz_last_settings_save(subghz->last_settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── scene callbacks ──────────────────────────────────────────────────────── */
|
|
||||||
|
|
||||||
void subghz_scene_protocol_list_on_enter(void* context) {
|
void subghz_scene_protocol_list_on_enter(void* context) {
|
||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
VariableItemList* list = subghz->variable_item_list;
|
VariableItemList* list = subghz->variable_item_list;
|
||||||
variable_item_list_reset(list);
|
variable_item_list_reset(list);
|
||||||
|
subghz_scene_protocol_list_free_contexts();
|
||||||
|
|
||||||
size_t protocol_count = subghz_protocol_registry_count(&subghz_protocol_registry);
|
size_t protocol_count = subghz_protocol_registry_count(&subghz_protocol_registry);
|
||||||
|
protocol_list_item_contexts =
|
||||||
|
malloc(sizeof(SubGhzProtocolListItemContext) * protocol_count);
|
||||||
|
furi_check(protocol_list_item_contexts);
|
||||||
|
|
||||||
for(size_t i = 0; i < protocol_count; i++) {
|
for(size_t i = 0; i < protocol_count; i++) {
|
||||||
const SubGhzProtocol* protocol =
|
const SubGhzProtocol* protocol =
|
||||||
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, i);
|
subghz_protocol_registry_get_by_index(&subghz_protocol_registry, i);
|
||||||
if(!protocol) continue;
|
if(!protocol) continue;
|
||||||
|
|
||||||
|
protocol_list_item_contexts[i].subghz = subghz;
|
||||||
|
protocol_list_item_contexts[i].protocol_name = protocol->name;
|
||||||
|
|
||||||
VariableItem* item = variable_item_list_add(
|
VariableItem* item = variable_item_list_add(
|
||||||
list,
|
list,
|
||||||
protocol->name,
|
protocol->name,
|
||||||
2,
|
2,
|
||||||
subghz_scene_protocol_list_item_changed,
|
subghz_scene_protocol_list_item_changed,
|
||||||
subghz);
|
&protocol_list_item_contexts[i]);
|
||||||
|
|
||||||
bool enabled = proto_filter_contains(
|
bool is_disabled =
|
||||||
subghz->last_settings->protocol_filter, protocol->name);
|
subghz_last_settings_protocol_filter_contains(subghz->last_settings, protocol->name);
|
||||||
variable_item_set_current_value_index(item, enabled ? 1 : 0);
|
variable_item_set_current_value_index(item, is_disabled ? 1 : 0);
|
||||||
variable_item_set_current_value_text(item, enabled ? "ONLY" : "---");
|
variable_item_set_current_value_text(item, is_disabled ? "OFF" : "ON");
|
||||||
}
|
}
|
||||||
|
|
||||||
variable_item_list_set_selected_item(
|
variable_item_list_set_selected_item(
|
||||||
@@ -132,4 +95,5 @@ void subghz_scene_protocol_list_on_exit(void* context) {
|
|||||||
SubGhzSceneProtocolList,
|
SubGhzSceneProtocolList,
|
||||||
variable_item_list_get_selected_item_index(subghz->variable_item_list));
|
variable_item_list_get_selected_item_index(subghz->variable_item_list));
|
||||||
variable_item_list_reset(subghz->variable_item_list);
|
variable_item_list_reset(subghz->variable_item_list);
|
||||||
|
subghz_scene_protocol_list_free_contexts();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,27 +105,10 @@ static void subghz_scene_add_to_history_callback(
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
// The check can be moved to /lib/subghz/receiver.c, but may result in false positives
|
// The check can be moved to /lib/subghz/receiver.c, but may result in false positives
|
||||||
/* Protocol name allowlist filter — if non-empty, drop anything not in the list */
|
if(subghz_last_settings_protocol_filter_contains(
|
||||||
if(subghz->last_settings->protocol_filter[0] != '\0') {
|
subghz->last_settings, decoder_base->protocol->name)) {
|
||||||
const char* proto_name = decoder_base->protocol->name;
|
FURI_LOG_D(TAG, "%s filtered by protocol OFF list", decoder_base->protocol->name);
|
||||||
const char* filter = subghz->last_settings->protocol_filter;
|
return;
|
||||||
bool allowed = false;
|
|
||||||
/* Walk the comma-separated list */
|
|
||||||
const char* p = filter;
|
|
||||||
while(*p) {
|
|
||||||
const char* comma = strchr(p, ',');
|
|
||||||
size_t len = comma ? (size_t)(comma - p) : strlen(p);
|
|
||||||
if(len == strlen(proto_name) && strncmp(p, proto_name, len) == 0) {
|
|
||||||
allowed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!comma) break;
|
|
||||||
p = comma + 1;
|
|
||||||
}
|
|
||||||
if(!allowed) {
|
|
||||||
FURI_LOG_D(TAG, "%s filtered by allowlist", proto_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if((decoder_base->protocol->flag & subghz->ignore_filter) == 0) {
|
if((decoder_base->protocol->flag & subghz->ignore_filter) == 0) {
|
||||||
|
|||||||
@@ -679,15 +679,13 @@ void subghz_scene_receiver_config_on_enter(void* context) {
|
|||||||
1,
|
1,
|
||||||
NULL,
|
NULL,
|
||||||
subghz);
|
subghz);
|
||||||
if(subghz->last_settings->protocol_filter[0] == '\0') {
|
uint8_t protocol_filter_count =
|
||||||
variable_item_set_current_value_text(item, "All");
|
subghz_last_settings_protocol_filter_count(subghz->last_settings);
|
||||||
|
if(protocol_filter_count == 0) {
|
||||||
|
variable_item_set_current_value_text(item, "All ON");
|
||||||
} else {
|
} else {
|
||||||
uint8_t count = 1;
|
|
||||||
for(const char* p = subghz->last_settings->protocol_filter; *p; p++) {
|
|
||||||
if(*p == ',') count++;
|
|
||||||
}
|
|
||||||
static char filter_count_str[8];
|
static char filter_count_str[8];
|
||||||
snprintf(filter_count_str, sizeof(filter_count_str), "%u set", count);
|
snprintf(filter_count_str, sizeof(filter_count_str), "%u OFF", protocol_filter_count);
|
||||||
variable_item_set_current_value_text(item, filter_count_str);
|
variable_item_set_current_value_text(item, filter_count_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,17 +121,7 @@ bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
|
|||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
subghz->scene_manager, SubGhzSceneSavedMenu, SubmenuIndexEmulate);
|
subghz->scene_manager, SubGhzSceneSavedMenu, SubmenuIndexEmulate);
|
||||||
|
|
||||||
bool use_custom = subghz->last_settings->custom_car_emulate;
|
if(subghz->last_settings->custom_car_emulate) {
|
||||||
if(use_custom) {
|
|
||||||
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
|
||||||
uint32_t cnt_tmp = 0;
|
|
||||||
flipper_format_rewind(fff);
|
|
||||||
if(!flipper_format_read_uint32(fff, "Cnt", &cnt_tmp, 1)) {
|
|
||||||
use_custom = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(use_custom) {
|
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneCarEmulate);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneCarEmulate);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
|
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "../subghz_i.h"
|
#include "../subghz_i.h"
|
||||||
#include "subghz/types.h"
|
#include "subghz/types.h"
|
||||||
|
#include "../helpers/subghz_button_labels.h"
|
||||||
#include "../helpers/subghz_custom_event.h"
|
#include "../helpers/subghz_custom_event.h"
|
||||||
#include <lib/toolbox/value_index.h>
|
#include <lib/toolbox/value_index.h>
|
||||||
#include <machine/endian.h>
|
#include <machine/endian.h>
|
||||||
@@ -7,6 +8,7 @@
|
|||||||
#include <lib/subghz/blocks/generic.h>
|
#include <lib/subghz/blocks/generic.h>
|
||||||
#include <lib/subghz/blocks/custom_btn_i.h>
|
#include <lib/subghz/blocks/custom_btn_i.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define TAG "SubGhzSceneSignalSettings"
|
#define TAG "SubGhzSceneSignalSettings"
|
||||||
|
|
||||||
@@ -15,6 +17,8 @@ static uint32_t counter32 = 0x0;
|
|||||||
static uint16_t counter16 = 0x0;
|
static uint16_t counter16 = 0x0;
|
||||||
static uint8_t cnt_byte_count = 0;
|
static uint8_t cnt_byte_count = 0;
|
||||||
static uint8_t* cnt_byte_ptr = NULL;
|
static uint8_t* cnt_byte_ptr = NULL;
|
||||||
|
static uint32_t counter_value = 0;
|
||||||
|
static uint32_t counter_mask = 0xffffffffUL;
|
||||||
|
|
||||||
static FuriString* byte_input_text;
|
static FuriString* byte_input_text;
|
||||||
|
|
||||||
@@ -26,12 +30,24 @@ static uint8_t submenu_called = 0;
|
|||||||
static bool button_uses_custom_btn = false;
|
static bool button_uses_custom_btn = false;
|
||||||
static uint8_t button_custom_id = SUBGHZ_CUSTOM_BTN_OK;
|
static uint8_t button_custom_id = SUBGHZ_CUSTOM_BTN_OK;
|
||||||
|
|
||||||
|
static bool subghz_scene_signal_settings_rebuild_save_reload(
|
||||||
|
SubGhz* subghz,
|
||||||
|
bool use_custom_btn,
|
||||||
|
uint8_t custom_btn_id);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SignalSettingsIndexCounterMode,
|
SignalSettingsIndexCounterMode,
|
||||||
SignalSettingsIndexCounter,
|
SignalSettingsIndexCounter,
|
||||||
SignalSettingsIndexButton,
|
SignalSettingsIndexButton,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SignalSettingsCounterStepDown,
|
||||||
|
SignalSettingsCounterStepValue,
|
||||||
|
SignalSettingsCounterStepUp,
|
||||||
|
SignalSettingsCounterStepCount,
|
||||||
|
};
|
||||||
|
|
||||||
#define COUNTER_MODE_COUNT 8
|
#define COUNTER_MODE_COUNT 8
|
||||||
static const char* const counter_mode_text[COUNTER_MODE_COUNT] = {
|
static const char* const counter_mode_text[COUNTER_MODE_COUNT] = {
|
||||||
"System",
|
"System",
|
||||||
@@ -66,18 +82,7 @@ static const uint8_t button_value[] = {
|
|||||||
7,
|
7,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BUTTON_VALUE_COUNT (sizeof(button_value) / sizeof(button_value[0]))
|
#define BUTTON_VALUE_COUNT SUBGHZ_BUTTON_LABEL_COUNT
|
||||||
|
|
||||||
static const char* const button_default_labels[BUTTON_VALUE_COUNT] = {
|
|
||||||
"Original",
|
|
||||||
"Up",
|
|
||||||
"Down",
|
|
||||||
"Left",
|
|
||||||
"Right",
|
|
||||||
"Button 5",
|
|
||||||
"Button 6",
|
|
||||||
"Button 7",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* button_labels[BUTTON_VALUE_COUNT] = {
|
static const char* button_labels[BUTTON_VALUE_COUNT] = {
|
||||||
"Original",
|
"Original",
|
||||||
@@ -90,30 +95,6 @@ static const char* button_labels[BUTTON_VALUE_COUNT] = {
|
|||||||
"Button 7",
|
"Button 7",
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char* protocol;
|
|
||||||
const char* labels[BUTTON_VALUE_COUNT];
|
|
||||||
} ProtocolButtonLabels;
|
|
||||||
|
|
||||||
static const ProtocolButtonLabels 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"}},
|
|
||||||
{"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/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"}},
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* name;
|
char* name;
|
||||||
uint8_t mode_count;
|
uint8_t mode_count;
|
||||||
@@ -131,35 +112,16 @@ static Protocols protocols[] = {
|
|||||||
#define PROTOCOLS_COUNT (sizeof(protocols) / sizeof(Protocols))
|
#define PROTOCOLS_COUNT (sizeof(protocols) / sizeof(Protocols))
|
||||||
|
|
||||||
static void subghz_scene_signal_settings_reset_button_labels(void) {
|
static void subghz_scene_signal_settings_reset_button_labels(void) {
|
||||||
for(uint8_t i = 0; i < BUTTON_VALUE_COUNT; i++) {
|
subghz_button_labels_reset(button_labels);
|
||||||
button_labels[i] = button_default_labels[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subghz_scene_signal_settings_apply_button_labels(const char* protocol) {
|
static void subghz_scene_signal_settings_apply_button_labels(const char* protocol) {
|
||||||
for(uint8_t i = 0; i < COUNT_OF(protocol_button_labels); i++) {
|
subghz_button_labels_apply_protocol(protocol, button_labels);
|
||||||
if(strcmp(protocol, protocol_button_labels[i].protocol) == 0) {
|
|
||||||
for(uint8_t btn = 0; btn < BUTTON_VALUE_COUNT; btn++) {
|
|
||||||
if(protocol_button_labels[i].labels[btn]) {
|
|
||||||
button_labels[btn] = protocol_button_labels[i].labels[btn];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* subghz_scene_signal_settings_get_button_label(uint8_t custom_btn_id) {
|
static const char* subghz_scene_signal_settings_get_button_label(uint8_t custom_btn_id) {
|
||||||
if(custom_btn_id == SUBGHZ_CUSTOM_BTN_OK) {
|
return subghz_button_labels_get(
|
||||||
uint8_t original = subghz_custom_btn_get_original();
|
button_labels, custom_btn_id, subghz_custom_btn_get_original());
|
||||||
if((original != SUBGHZ_CUSTOM_BTN_OK) && (original < BUTTON_VALUE_COUNT)) {
|
|
||||||
return button_labels[original];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(custom_btn_id < BUTTON_VALUE_COUNT) {
|
|
||||||
return button_labels[custom_btn_id];
|
|
||||||
}
|
|
||||||
return "Button";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool subghz_scene_signal_settings_update_uint32_field(
|
static bool subghz_scene_signal_settings_update_uint32_field(
|
||||||
@@ -170,6 +132,60 @@ static bool subghz_scene_signal_settings_update_uint32_field(
|
|||||||
return flipper_format_insert_or_update_uint32(fff, key, &value, 1);
|
return flipper_format_insert_or_update_uint32(fff, key, &value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t subghz_scene_signal_settings_counter_get_mask(void) {
|
||||||
|
uint8_t bits = subghz_block_generic_global.cnt_length_bit;
|
||||||
|
if((bits == 0) || (bits >= 32)) {
|
||||||
|
return 0xffffffffUL;
|
||||||
|
}
|
||||||
|
return (1UL << bits) - 1UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_scene_signal_settings_counter_sync_byte_input(void) {
|
||||||
|
if(cnt_byte_count == 4) {
|
||||||
|
counter32 = __bswap32(counter_value);
|
||||||
|
cnt_byte_ptr = (uint8_t*)&counter32;
|
||||||
|
} else if(cnt_byte_count == 2) {
|
||||||
|
counter16 = __bswap16((uint16_t)counter_value);
|
||||||
|
cnt_byte_ptr = (uint8_t*)&counter16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_scene_signal_settings_counter_set_value(uint32_t value) {
|
||||||
|
counter_value = value & counter_mask;
|
||||||
|
subghz_scene_signal_settings_counter_sync_byte_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_scene_signal_settings_counter_format(FuriString* text) {
|
||||||
|
if(cnt_byte_count == 4) {
|
||||||
|
furi_string_printf(text, "%lX", (unsigned long)counter_value);
|
||||||
|
} else {
|
||||||
|
furi_string_printf(text, "%X", (unsigned int)(counter_value & 0xffffU));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subghz_scene_signal_settings_counter_update_item(VariableItem* item) {
|
||||||
|
char text[9] = {0};
|
||||||
|
variable_item_set_current_value_index(item, SignalSettingsCounterStepValue);
|
||||||
|
if(cnt_byte_count == 4) {
|
||||||
|
snprintf(text, sizeof(text), "%lX", (unsigned long)counter_value);
|
||||||
|
} else {
|
||||||
|
snprintf(text, sizeof(text), "%X", (unsigned int)(counter_value & 0xffffU));
|
||||||
|
}
|
||||||
|
variable_item_set_current_value_text(item, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool subghz_scene_signal_settings_counter_save(SubGhz* subghz) {
|
||||||
|
FlipperFormat* fff = subghz_txrx_get_fff_data(subghz->txrx);
|
||||||
|
if(!subghz_scene_signal_settings_update_uint32_field(fff, "Cnt", counter_value)) {
|
||||||
|
FURI_LOG_E(TAG, "Error update/insert Cnt value");
|
||||||
|
dialog_message_show_storage_error(subghz->dialogs, "Cannot save\ncounter");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
subghz_block_generic_global_counter_override_set(counter_value);
|
||||||
|
return subghz_scene_signal_settings_rebuild_save_reload(subghz, false, SUBGHZ_CUSTOM_BTN_OK);
|
||||||
|
}
|
||||||
|
|
||||||
static bool subghz_scene_signal_settings_hex_digit(char c, uint8_t* value) {
|
static bool subghz_scene_signal_settings_hex_digit(char c, uint8_t* value) {
|
||||||
if(c >= '0' && c <= '9') {
|
if(c >= '0' && c <= '9') {
|
||||||
*value = c - '0';
|
*value = c - '0';
|
||||||
@@ -332,6 +348,28 @@ void subghz_scene_signal_settings_counter_mode_changed(VariableItem* item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void subghz_scene_signal_settings_counter_changed(VariableItem* item) {
|
||||||
|
if(!cnt_byte_ptr || cnt_byte_count == 0) return;
|
||||||
|
|
||||||
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
|
if(index == SignalSettingsCounterStepValue) {
|
||||||
|
subghz_scene_signal_settings_counter_update_item(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index == SignalSettingsCounterStepUp) {
|
||||||
|
subghz_scene_signal_settings_counter_set_value(counter_value + 1);
|
||||||
|
} else {
|
||||||
|
subghz_scene_signal_settings_counter_set_value(counter_value - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
subghz_scene_signal_settings_counter_update_item(item);
|
||||||
|
|
||||||
|
SubGhz* subghz = variable_item_get_context(item);
|
||||||
|
furi_assert(subghz);
|
||||||
|
subghz_scene_signal_settings_counter_save(subghz);
|
||||||
|
}
|
||||||
|
|
||||||
void subghz_scene_signal_settings_button_changed(VariableItem* item) {
|
void subghz_scene_signal_settings_button_changed(VariableItem* item) {
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
uint8_t index = variable_item_get_current_value_index(item);
|
||||||
if(index >= BUTTON_VALUE_COUNT) index = 0;
|
if(index >= BUTTON_VALUE_COUNT) index = 0;
|
||||||
@@ -407,6 +445,8 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
|||||||
counter16 = 0;
|
counter16 = 0;
|
||||||
cnt_byte_count = 0;
|
cnt_byte_count = 0;
|
||||||
cnt_byte_ptr = NULL;
|
cnt_byte_ptr = NULL;
|
||||||
|
counter_value = 0;
|
||||||
|
counter_mask = 0xffffffffUL;
|
||||||
button = 0;
|
button = 0;
|
||||||
btn_byte_count = 1;
|
btn_byte_count = 1;
|
||||||
btn_byte_ptr = NULL;
|
btn_byte_ptr = NULL;
|
||||||
@@ -508,26 +548,26 @@ void subghz_scene_signal_settings_on_enter(void* context) {
|
|||||||
FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol");
|
FURI_LOG_D(TAG, "Counter mode and edit not available for this protocol");
|
||||||
} else {
|
} else {
|
||||||
counter_not_available = false;
|
counter_not_available = false;
|
||||||
|
counter_mask = subghz_scene_signal_settings_counter_get_mask();
|
||||||
|
|
||||||
// Check is there byte_count more than 2 hex bytes long or not
|
// ByteInput stores the visible hex value as big-endian bytes.
|
||||||
// To show hex value we must correct revert bytes for ByteInput view with __bswapХХ
|
|
||||||
if(subghz_block_generic_global.cnt_length_bit > 16) {
|
if(subghz_block_generic_global.cnt_length_bit > 16) {
|
||||||
counter32 = subghz_block_generic_global.current_cnt;
|
|
||||||
furi_string_printf(tmp_text, "%lX", counter32);
|
|
||||||
counter32 = __bswap32(counter32);
|
|
||||||
cnt_byte_ptr = (uint8_t*)&counter32;
|
|
||||||
cnt_byte_count = 4;
|
cnt_byte_count = 4;
|
||||||
} else {
|
} else {
|
||||||
counter16 = subghz_block_generic_global.current_cnt;
|
|
||||||
furi_string_printf(tmp_text, "%X", counter16);
|
|
||||||
counter16 = __bswap16(counter16);
|
|
||||||
cnt_byte_ptr = (uint8_t*)&counter16;
|
|
||||||
cnt_byte_count = 2;
|
cnt_byte_count = 2;
|
||||||
}
|
}
|
||||||
|
subghz_scene_signal_settings_counter_set_value(subghz_block_generic_global.current_cnt);
|
||||||
|
subghz_scene_signal_settings_counter_format(tmp_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
item = variable_item_list_add(variable_item_list, "Edit Counter", 1, NULL, subghz);
|
item = variable_item_list_add(
|
||||||
variable_item_set_current_value_index(item, 0);
|
variable_item_list,
|
||||||
|
"Edit Counter",
|
||||||
|
counter_not_available ? 1 : SignalSettingsCounterStepCount,
|
||||||
|
counter_not_available ? NULL : subghz_scene_signal_settings_counter_changed,
|
||||||
|
subghz);
|
||||||
|
variable_item_set_current_value_index(
|
||||||
|
item, counter_not_available ? 0 : SignalSettingsCounterStepValue);
|
||||||
variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text));
|
variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_text));
|
||||||
variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !");
|
variable_item_set_locked(item, (counter_not_available), "Not available\nfor this\nprotocol !");
|
||||||
//
|
//
|
||||||
@@ -590,17 +630,13 @@ bool subghz_scene_signal_settings_on_event(void* context, SceneManagerEvent even
|
|||||||
switch(cnt_byte_count) {
|
switch(cnt_byte_count) {
|
||||||
case 2:
|
case 2:
|
||||||
counter16 = __bswap16(counter16);
|
counter16 = __bswap16(counter16);
|
||||||
subghz_scene_signal_settings_update_uint32_field(fff, "Cnt", counter16);
|
subghz_scene_signal_settings_counter_set_value(counter16);
|
||||||
subghz_block_generic_global_counter_override_set(counter16);
|
subghz_scene_signal_settings_counter_save(subghz);
|
||||||
subghz_scene_signal_settings_rebuild_save_reload(
|
|
||||||
subghz, false, SUBGHZ_CUSTOM_BTN_OK);
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
counter32 = __bswap32(counter32);
|
counter32 = __bswap32(counter32);
|
||||||
subghz_scene_signal_settings_update_uint32_field(fff, "Cnt", counter32);
|
subghz_scene_signal_settings_counter_set_value(counter32);
|
||||||
subghz_block_generic_global_counter_override_set(counter32);
|
subghz_scene_signal_settings_counter_save(subghz);
|
||||||
subghz_scene_signal_settings_rebuild_save_reload(
|
|
||||||
subghz, false, SUBGHZ_CUSTOM_BTN_OK);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#define SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP "LedAndPowerAmp"
|
#define SUBGHZ_LAST_SETTING_FIELD_LED_AND_POWER_AMP "LedAndPowerAmp"
|
||||||
#define SUBGHZ_LAST_SETTING_FIELD_TX_POWER "TXPower"
|
#define SUBGHZ_LAST_SETTING_FIELD_TX_POWER "TXPower"
|
||||||
#define SUBGHZ_LAST_SETTING_FIELD_CUSTOM_CAR_EMULATE "CustomCarEmulate"
|
#define SUBGHZ_LAST_SETTING_FIELD_CUSTOM_CAR_EMULATE "CustomCarEmulate"
|
||||||
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILTER "ProtocolFilter"
|
#define SUBGHZ_LAST_SETTING_FIELD_PROTOCOL_FILTER "ProtocolFilterOff"
|
||||||
|
|
||||||
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
SubGhzLastSettings* subghz_last_settings_alloc(void) {
|
||||||
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
|
||||||
@@ -187,6 +187,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
|
|||||||
flipper_format_rewind(fff_data_file);
|
flipper_format_rewind(fff_data_file);
|
||||||
}
|
}
|
||||||
furi_string_free(filter_str);
|
furi_string_free(filter_str);
|
||||||
|
subghz_last_settings_protocol_filter_normalize(instance);
|
||||||
|
|
||||||
} while(0);
|
} while(0);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <lib/subghz/types.h>
|
#include <lib/subghz/types.h>
|
||||||
|
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
|
#define SUBGHZ_LAST_SETTING_DEFAULT_FREQUENCY 433920000
|
||||||
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2
|
#define SUBGHZ_LAST_SETTING_FREQUENCY_ANALYZER_FEEDBACK_LEVEL 2
|
||||||
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD (-80.0f)
|
#define SUBGHZ_LAST_SETTING_DEFAULT_PRESET_HOPPING_THRESHOLD (-80.0f)
|
||||||
|
#define SUBGHZ_LAST_SETTINGS_PROTOCOL_FILTER_SIZE 1024
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t frequency;
|
uint32_t frequency;
|
||||||
@@ -31,9 +33,196 @@ typedef struct {
|
|||||||
bool leds_and_amp;
|
bool leds_and_amp;
|
||||||
uint8_t tx_power;
|
uint8_t tx_power;
|
||||||
bool custom_car_emulate;
|
bool custom_car_emulate;
|
||||||
char protocol_filter[256]; /* comma-separated allowlist, empty = disabled */
|
char protocol_filter[SUBGHZ_LAST_SETTINGS_PROTOCOL_FILTER_SIZE]; /* comma-separated disabled protocols, empty = all enabled */
|
||||||
} SubGhzLastSettings;
|
} SubGhzLastSettings;
|
||||||
|
|
||||||
|
static inline void subghz_last_settings_protocol_filter_next_token(
|
||||||
|
const char** cursor,
|
||||||
|
const char** token,
|
||||||
|
size_t* token_len) {
|
||||||
|
const char* start = *cursor;
|
||||||
|
while((*start == ',') || (*start == ' ') || (*start == '\t')) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* end = start;
|
||||||
|
while((*end != '\0') && (*end != ',')) {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* trim_end = end;
|
||||||
|
while((trim_end > start) && ((trim_end[-1] == ' ') || (trim_end[-1] == '\t'))) {
|
||||||
|
trim_end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*token = start;
|
||||||
|
*token_len = (size_t)(trim_end - start);
|
||||||
|
*cursor = (*end == ',') ? end + 1 : end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_token_matches(
|
||||||
|
const char* token,
|
||||||
|
size_t token_len,
|
||||||
|
const char* name,
|
||||||
|
size_t name_len) {
|
||||||
|
return (token_len == name_len) && (strncmp(token, name, token_len) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_contains_token(
|
||||||
|
const char* filter,
|
||||||
|
const char* token,
|
||||||
|
size_t token_len) {
|
||||||
|
const char* cursor = filter;
|
||||||
|
const char* current = NULL;
|
||||||
|
size_t current_len = 0;
|
||||||
|
|
||||||
|
while(*cursor != '\0') {
|
||||||
|
subghz_last_settings_protocol_filter_next_token(&cursor, ¤t, ¤t_len);
|
||||||
|
if((current_len != 0) &&
|
||||||
|
subghz_last_settings_protocol_filter_token_matches(
|
||||||
|
current, current_len, token, token_len)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_append_token(
|
||||||
|
char* filter,
|
||||||
|
size_t filter_size,
|
||||||
|
const char* token,
|
||||||
|
size_t token_len) {
|
||||||
|
if(token_len == 0) return true;
|
||||||
|
|
||||||
|
size_t filter_len = strlen(filter);
|
||||||
|
size_t separator_len = filter_len == 0 ? 0 : 1;
|
||||||
|
if((filter_len + separator_len + token_len) >= filter_size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(separator_len != 0) {
|
||||||
|
filter[filter_len++] = ',';
|
||||||
|
}
|
||||||
|
memcpy(&filter[filter_len], token, token_len);
|
||||||
|
filter[filter_len + token_len] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_contains(
|
||||||
|
const SubGhzLastSettings* instance,
|
||||||
|
const char* protocol) {
|
||||||
|
if((instance == NULL) || (protocol == NULL) || (protocol[0] == '\0')) return false;
|
||||||
|
|
||||||
|
return subghz_last_settings_protocol_filter_contains_token(
|
||||||
|
instance->protocol_filter, protocol, strlen(protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_normalize(
|
||||||
|
SubGhzLastSettings* instance) {
|
||||||
|
if(instance == NULL) return false;
|
||||||
|
|
||||||
|
char normalized[SUBGHZ_LAST_SETTINGS_PROTOCOL_FILTER_SIZE] = {0};
|
||||||
|
const char* cursor = instance->protocol_filter;
|
||||||
|
const char* token = NULL;
|
||||||
|
size_t token_len = 0;
|
||||||
|
|
||||||
|
while(*cursor != '\0') {
|
||||||
|
subghz_last_settings_protocol_filter_next_token(&cursor, &token, &token_len);
|
||||||
|
if((token_len == 0) ||
|
||||||
|
subghz_last_settings_protocol_filter_contains_token(normalized, token, token_len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!subghz_last_settings_protocol_filter_append_token(
|
||||||
|
normalized, sizeof(normalized), token, token_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed = strcmp(instance->protocol_filter, normalized) != 0;
|
||||||
|
if(changed) {
|
||||||
|
memcpy(instance->protocol_filter, normalized, sizeof(instance->protocol_filter));
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool subghz_last_settings_protocol_filter_set(
|
||||||
|
SubGhzLastSettings* instance,
|
||||||
|
const char* protocol,
|
||||||
|
bool disabled) {
|
||||||
|
if((instance == NULL) || (protocol == NULL) || (protocol[0] == '\0')) return false;
|
||||||
|
|
||||||
|
char updated[SUBGHZ_LAST_SETTINGS_PROTOCOL_FILTER_SIZE] = {0};
|
||||||
|
const char* cursor = instance->protocol_filter;
|
||||||
|
const char* token = NULL;
|
||||||
|
size_t token_len = 0;
|
||||||
|
const size_t protocol_len = strlen(protocol);
|
||||||
|
bool protocol_written = false;
|
||||||
|
|
||||||
|
while(*cursor != '\0') {
|
||||||
|
subghz_last_settings_protocol_filter_next_token(&cursor, &token, &token_len);
|
||||||
|
if(token_len == 0) continue;
|
||||||
|
|
||||||
|
bool is_target = subghz_last_settings_protocol_filter_token_matches(
|
||||||
|
token, token_len, protocol, protocol_len);
|
||||||
|
if(is_target) {
|
||||||
|
if(disabled && !protocol_written) {
|
||||||
|
if(!subghz_last_settings_protocol_filter_append_token(
|
||||||
|
updated, sizeof(updated), protocol, protocol_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
protocol_written = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!subghz_last_settings_protocol_filter_contains_token(updated, token, token_len)) {
|
||||||
|
if(!subghz_last_settings_protocol_filter_append_token(
|
||||||
|
updated, sizeof(updated), token, token_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(disabled && !protocol_written) {
|
||||||
|
if(!subghz_last_settings_protocol_filter_append_token(
|
||||||
|
updated, sizeof(updated), protocol, protocol_len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed = strcmp(instance->protocol_filter, updated) != 0;
|
||||||
|
if(changed) {
|
||||||
|
memcpy(instance->protocol_filter, updated, sizeof(instance->protocol_filter));
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t subghz_last_settings_protocol_filter_count(
|
||||||
|
const SubGhzLastSettings* instance) {
|
||||||
|
if(instance == NULL) return 0;
|
||||||
|
|
||||||
|
char seen[SUBGHZ_LAST_SETTINGS_PROTOCOL_FILTER_SIZE] = {0};
|
||||||
|
const char* cursor = instance->protocol_filter;
|
||||||
|
const char* token = NULL;
|
||||||
|
size_t token_len = 0;
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
while(*cursor != '\0') {
|
||||||
|
subghz_last_settings_protocol_filter_next_token(&cursor, &token, &token_len);
|
||||||
|
if((token_len == 0) ||
|
||||||
|
subghz_last_settings_protocol_filter_contains_token(seen, token, token_len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!subghz_last_settings_protocol_filter_append_token(seen, sizeof(seen), token, token_len)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
SubGhzLastSettings* subghz_last_settings_alloc(void);
|
||||||
|
|
||||||
void subghz_last_settings_free(SubGhzLastSettings* instance);
|
void subghz_last_settings_free(SubGhzLastSettings* instance);
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ typedef struct {
|
|||||||
char preset[12];
|
char preset[12];
|
||||||
bool is_transmitting;
|
bool is_transmitting;
|
||||||
uint8_t anim_frame;
|
uint8_t anim_frame;
|
||||||
char label_ok[12];
|
char label_ok[16];
|
||||||
char label_up[12];
|
char label_up[16];
|
||||||
char label_down[12];
|
char label_down[16];
|
||||||
char label_left[12];
|
char label_left[16];
|
||||||
char label_right[12];
|
char label_right[16];
|
||||||
} SubGhzCarEmulateViewModel;
|
} SubGhzCarEmulateViewModel;
|
||||||
|
|
||||||
/* ── Handle ─────────────────────────────────────────────────────────────── */
|
/* ── Handle ─────────────────────────────────────────────────────────────── */
|
||||||
@@ -79,7 +79,7 @@ static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
|||||||
const uint8_t font_h = canvas_current_font_height(canvas);
|
const uint8_t font_h = canvas_current_font_height(canvas);
|
||||||
|
|
||||||
/* Centre → UNLOCK (OK button) */
|
/* Centre → UNLOCK (OK button) */
|
||||||
{
|
if(m->label_ok[0]) {
|
||||||
const char* lbl = m->label_ok;
|
const char* lbl = m->label_ok;
|
||||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||||
canvas_draw_rbox(canvas, 64 - w / 2, 45 - font_h / 2, w, font_h, 3);
|
canvas_draw_rbox(canvas, 64 - w / 2, 45 - font_h / 2, w, font_h, 3);
|
||||||
@@ -89,7 +89,7 @@ static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Up → LOCK */
|
/* Up → LOCK */
|
||||||
{
|
if(m->label_up[0]) {
|
||||||
const char* lbl = m->label_up;
|
const char* lbl = m->label_up;
|
||||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||||
canvas_draw_rbox(canvas, 64 - w / 2, 33 - font_h / 2, w, font_h, 3);
|
canvas_draw_rbox(canvas, 64 - w / 2, 33 - font_h / 2, w, font_h, 3);
|
||||||
@@ -99,7 +99,7 @@ static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Left → PANIC */
|
/* Left → PANIC */
|
||||||
{
|
if(m->label_left[0]) {
|
||||||
const char* lbl = m->label_left;
|
const char* lbl = m->label_left;
|
||||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||||
canvas_draw_rbox(canvas, 0, 46 - font_h / 2, w, font_h, 3);
|
canvas_draw_rbox(canvas, 0, 46 - font_h / 2, w, font_h, 3);
|
||||||
@@ -109,7 +109,7 @@ static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Right → generic extra */
|
/* Right → generic extra */
|
||||||
{
|
if(m->label_right[0]) {
|
||||||
const char* lbl = m->label_right;
|
const char* lbl = m->label_right;
|
||||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||||
canvas_draw_rbox(canvas, 127 - w, 46 - font_h / 2, w, font_h, 3);
|
canvas_draw_rbox(canvas, 127 - w, 46 - font_h / 2, w, font_h, 3);
|
||||||
@@ -119,7 +119,7 @@ static void subghz_car_emulate_view_draw(Canvas* canvas, void* model_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Down → BOOT */
|
/* Down → BOOT */
|
||||||
{
|
if(m->label_down[0]) {
|
||||||
const char* lbl = m->label_down;
|
const char* lbl = m->label_down;
|
||||||
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
uint8_t w = (uint8_t)(canvas_string_width(canvas, lbl) + 8U);
|
||||||
canvas_draw_rbox(canvas, 64 - w / 2, 57 - font_h / 2, w, font_h, 3);
|
canvas_draw_rbox(canvas, 64 - w / 2, 57 - font_h / 2, w, font_h, 3);
|
||||||
@@ -259,6 +259,11 @@ void subghz_car_emulate_view_set_labels(
|
|||||||
strncpy(m->label_down, down ? down : "", sizeof(m->label_down) - 1);
|
strncpy(m->label_down, down ? down : "", sizeof(m->label_down) - 1);
|
||||||
strncpy(m->label_left, left ? left : "", sizeof(m->label_left) - 1);
|
strncpy(m->label_left, left ? left : "", sizeof(m->label_left) - 1);
|
||||||
strncpy(m->label_right, right ? right : "", sizeof(m->label_right) - 1);
|
strncpy(m->label_right, right ? right : "", sizeof(m->label_right) - 1);
|
||||||
|
m->label_ok[sizeof(m->label_ok) - 1] = '\0';
|
||||||
|
m->label_up[sizeof(m->label_up) - 1] = '\0';
|
||||||
|
m->label_down[sizeof(m->label_down) - 1] = '\0';
|
||||||
|
m->label_left[sizeof(m->label_left) - 1] = '\0';
|
||||||
|
m->label_right[sizeof(m->label_right) - 1] = '\0';
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user