mirror of
https://github.com/D4C1-Labs/Flipper-ARF.git
synced 2026-06-14 16:01:38 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3698f93a9 |
@@ -1,9 +1,11 @@
|
||||
#include "subghz_txrx_i.h" // IWYU pragma: keep
|
||||
|
||||
#include <math.h>
|
||||
#include <furi_hal_subghz.h>
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
#include <applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h>
|
||||
#include <lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h>
|
||||
#include "../../../../lib/subghz/devices/subghz_preset_delta.h"
|
||||
#include <lib/subghz/blocks/custom_btn.h>
|
||||
|
||||
#define TAG "SubGhzTxRx"
|
||||
@@ -498,6 +500,36 @@ void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the hop index (0=AM650, 1=FM476, 2=FM95) from the name.
|
||||
// Must match the order defined in subghz_preset_delta.h
|
||||
static int subghz_hop_index_from_name(const char* name) {
|
||||
if(strcmp(name, "AM650") == 0) return 0;
|
||||
if(strcmp(name, "FM476") == 0) return 1;
|
||||
if(strcmp(name, "FM95") == 0) return 2;
|
||||
return -1; // is not part of the fast hopping set
|
||||
}
|
||||
|
||||
// Applies the target preset using delta-patch (without SRES) when possible,
|
||||
// or falls back to the original full reload in any other case.
|
||||
static void subghz_txrx_apply_preset_fast(
|
||||
SubGhzTxRx* instance,
|
||||
const char* old_preset_name,
|
||||
const char* preset_name) {
|
||||
int from_idx = subghz_hop_index_from_name(old_preset_name);
|
||||
int to_idx = subghz_hop_index_from_name(preset_name);
|
||||
|
||||
if(instance->radio_device_type == SubGhzRadioDeviceTypeInternal && from_idx >= 0 &&
|
||||
to_idx >= 0 && from_idx != to_idx) {
|
||||
// Fast path: delta-patch without SRES or full reload (only internal CC1101)
|
||||
const PresetDeltaEntry* e = &preset_delta_table[from_idx][to_idx];
|
||||
furi_hal_subghz_apply_preset_delta(e->delta, e->delta_len, e->needs_scal, e->pa_table);
|
||||
} else {
|
||||
// Fallback: original behavior (full reload)
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device, FuriHalSubGhzPresetCustom, instance->preset->data);
|
||||
}
|
||||
}
|
||||
|
||||
void subghz_txrx_preset_hopper_update(SubGhzTxRx* instance, float stay_threshold) {
|
||||
furi_assert(instance);
|
||||
|
||||
@@ -550,22 +582,7 @@ void subghz_txrx_preset_hopper_update(SubGhzTxRx* instance, float stay_threshold
|
||||
subghz_txrx_set_preset_internal(
|
||||
instance, instance->preset->frequency, actual_preset_idx, 0);
|
||||
|
||||
bool old_is_am = (strstr(old_preset_name, "AM") != NULL);
|
||||
bool new_is_am = (strstr(preset_name, "AM") != NULL);
|
||||
bool modulation_changed = (old_is_am != new_is_am);
|
||||
|
||||
if(modulation_changed) {
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
} else {
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
}
|
||||
subghz_txrx_apply_preset_fast(instance, old_preset_name, preset_name);
|
||||
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
@@ -588,22 +605,7 @@ void subghz_txrx_preset_hopper_update(SubGhzTxRx* instance, float stay_threshold
|
||||
subghz_txrx_set_preset_internal(
|
||||
instance, instance->preset->frequency, instance->preset_hopper_idx, 0);
|
||||
|
||||
bool old_is_am = (strstr(old_preset_name, "AM") != NULL);
|
||||
bool new_is_am = (strstr(preset_name, "AM") != NULL);
|
||||
bool modulation_changed = (old_is_am != new_is_am);
|
||||
|
||||
if(modulation_changed) {
|
||||
subghz_devices_reset(instance->radio_device);
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
} else {
|
||||
subghz_devices_load_preset(
|
||||
instance->radio_device,
|
||||
FuriHalSubGhzPresetCustom,
|
||||
instance->preset->data);
|
||||
}
|
||||
subghz_txrx_apply_preset_fast(instance, old_preset_name, preset_name);
|
||||
|
||||
subghz_txrx_rx(instance, instance->preset->frequency);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "subghz_preset_delta.h"
|
||||
|
||||
static const uint8_t preset_delta_AM650_to_FM476[] = {
|
||||
0x10, 0x67,
|
||||
0x11, 0x83,
|
||||
0x12, 0x04,
|
||||
0x13, 0x02,
|
||||
0x19, 0x16,
|
||||
0x21, 0x56,
|
||||
0x22, 0x10,
|
||||
};
|
||||
static const uint8_t preset_delta_AM650_to_FM476_pa[8] = { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static const uint8_t preset_delta_AM650_to_FM95[] = {
|
||||
0x10, 0x67,
|
||||
0x11, 0x83,
|
||||
0x12, 0x04,
|
||||
0x13, 0x02,
|
||||
0x14, 0xF8,
|
||||
0x15, 0x24,
|
||||
0x19, 0x16,
|
||||
0x21, 0x56,
|
||||
0x22, 0x10,
|
||||
};
|
||||
static const uint8_t preset_delta_AM650_to_FM95_pa[8] = { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static const uint8_t preset_delta_FM476_to_AM650[] = {
|
||||
0x10, 0x17,
|
||||
0x11, 0x32,
|
||||
0x12, 0x30,
|
||||
0x13, 0x00,
|
||||
0x19, 0x18,
|
||||
0x21, 0xB6,
|
||||
0x22, 0x11,
|
||||
};
|
||||
static const uint8_t preset_delta_FM476_to_AM650_pa[8] = { 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static const uint8_t preset_delta_FM476_to_FM95[] = {
|
||||
0x14, 0xF8,
|
||||
0x15, 0x24,
|
||||
};
|
||||
|
||||
static const uint8_t preset_delta_FM95_to_AM650[] = {
|
||||
0x10, 0x17,
|
||||
0x11, 0x32,
|
||||
0x12, 0x30,
|
||||
0x13, 0x00,
|
||||
0x14, 0x00,
|
||||
0x15, 0x47,
|
||||
0x19, 0x18,
|
||||
0x21, 0xB6,
|
||||
0x22, 0x11,
|
||||
};
|
||||
static const uint8_t preset_delta_FM95_to_AM650_pa[8] = { 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
static const uint8_t preset_delta_FM95_to_FM476[] = {
|
||||
0x14, 0x00,
|
||||
0x15, 0x47,
|
||||
};
|
||||
|
||||
const PresetDeltaEntry preset_delta_table[HOP_PRESET_COUNT][HOP_PRESET_COUNT] = {
|
||||
{
|
||||
{0},
|
||||
{ .delta = preset_delta_AM650_to_FM476, .delta_len = 14, .needs_scal = false, .pa_table = preset_delta_AM650_to_FM476_pa },
|
||||
{ .delta = preset_delta_AM650_to_FM95, .delta_len = 18, .needs_scal = false, .pa_table = preset_delta_AM650_to_FM95_pa },
|
||||
},
|
||||
{
|
||||
{ .delta = preset_delta_FM476_to_AM650, .delta_len = 14, .needs_scal = false, .pa_table = preset_delta_FM476_to_AM650_pa },
|
||||
{0},
|
||||
{ .delta = preset_delta_FM476_to_FM95, .delta_len = 4, .needs_scal = false, .pa_table = NULL },
|
||||
},
|
||||
{
|
||||
{ .delta = preset_delta_FM95_to_AM650, .delta_len = 18, .needs_scal = false, .pa_table = preset_delta_FM95_to_AM650_pa },
|
||||
{ .delta = preset_delta_FM95_to_FM476, .delta_len = 4, .needs_scal = false, .pa_table = NULL },
|
||||
{0},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
const uint8_t* delta;
|
||||
size_t delta_len;
|
||||
bool needs_scal;
|
||||
const uint8_t* pa_table;
|
||||
} PresetDeltaEntry;
|
||||
|
||||
typedef enum {
|
||||
HOP_AM650 = 0,
|
||||
HOP_FM476 = 1,
|
||||
HOP_FM95 = 2,
|
||||
HOP_PRESET_COUNT,
|
||||
} SubghzHopPreset;
|
||||
|
||||
extern const PresetDeltaEntry preset_delta_table[HOP_PRESET_COUNT][HOP_PRESET_COUNT];
|
||||
@@ -56,6 +56,7 @@ class FlipperApplication:
|
||||
name: Optional[str] = ""
|
||||
entry_point: Optional[str] = None
|
||||
flags: List[str] = field(default_factory=lambda: ["Default"])
|
||||
cflags: List[str] = field(default_factory=list)
|
||||
cdefines: List[str] = field(default_factory=list)
|
||||
requires: List[str] = field(default_factory=list)
|
||||
conflicts: List[str] = field(default_factory=list)
|
||||
|
||||
@@ -61,6 +61,7 @@ class AppBuilder:
|
||||
("FAP_VERSION", f'\\"{".".join(map(str, self.app.fap_version))}\\"'),
|
||||
*self.app.cdefines,
|
||||
],
|
||||
CCFLAGS=self.app.cflags,
|
||||
)
|
||||
self.app_env.VariantDir(self.app_work_dir, self.app._appdir, duplicate=False)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,89.1,,
|
||||
Version,+,89.2,,
|
||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||
Header,+,applications/services/applications.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
@@ -1783,6 +1783,7 @@ Function,-,furi_hal_spi_config_init,void,
|
||||
Function,-,furi_hal_spi_config_init_early,void,
|
||||
Function,-,furi_hal_spi_dma_init,void,
|
||||
Function,+,furi_hal_spi_release,void,const FuriHalSpiBusHandle*
|
||||
Function,+,furi_hal_subghz_apply_preset_delta,void,"const uint8_t*, size_t, _Bool, const uint8_t*"
|
||||
Function,-,furi_hal_subghz_dump_state,void,
|
||||
Function,+,furi_hal_subghz_flush_rx,void,
|
||||
Function,+,furi_hal_subghz_flush_tx,void,
|
||||
@@ -3462,8 +3463,8 @@ Function,+,subghz_block_generic_global_reset,void,void*
|
||||
Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*"
|
||||
Function,+,subghz_custom_btn_get,uint8_t,
|
||||
Function,-,subghz_custom_btn_get_long,_Bool,
|
||||
Function,+,subghz_custom_btn_get_original,uint8_t,
|
||||
Function,+,subghz_custom_btn_get_max_pages,uint8_t,
|
||||
Function,+,subghz_custom_btn_get_original,uint8_t,
|
||||
Function,+,subghz_custom_btn_get_page,uint8_t,
|
||||
Function,+,subghz_custom_btn_has_pages,_Bool,
|
||||
Function,+,subghz_custom_btn_is_allowed,_Bool,
|
||||
|
||||
|
@@ -218,6 +218,59 @@ void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies only to the registers that change between the current preset
|
||||
* and the destination preset, without SRES or a full reload.
|
||||
*
|
||||
* Requires the chip state to be RX/TX or IDLE before calling;
|
||||
* the function itself forces IDLE (without SRES) before writing.
|
||||
*
|
||||
* @param delta array of {reg, val} pairs (exact length given by delta_len)
|
||||
* @param delta_len number of bytes in delta (multiple of 2)
|
||||
* @param needs_scal if true, forces SCAL after writing to the delta
|
||||
* @param pa_table 8 bytes of new PA table, or NULL if not changing
|
||||
*/
|
||||
void furi_hal_subghz_apply_preset_delta(
|
||||
const uint8_t* delta,
|
||||
size_t delta_len,
|
||||
bool needs_scal,
|
||||
const uint8_t* pa_table) {
|
||||
|
||||
furi_check(delta);
|
||||
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
// Ensure IDLE (not SRES!) before touching records
|
||||
cc1101_switch_to_idle(&furi_hal_spi_bus_handle_subghz);
|
||||
furi_check(cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
|
||||
|
||||
// Write only the records that change
|
||||
for(size_t i = 0; i + 1 < delta_len; i += 2) {
|
||||
cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, delta[i], delta[i + 1]);
|
||||
}
|
||||
|
||||
if(needs_scal) {
|
||||
cc1101_calibrate(&furi_hal_spi_bus_handle_subghz);
|
||||
furi_check(
|
||||
cc1101_wait_status_state(&furi_hal_spi_bus_handle_subghz, CC1101StateIDLE, 10000));
|
||||
}
|
||||
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
|
||||
|
||||
if(pa_table) {
|
||||
furi_hal_subghz_load_patable(pa_table);
|
||||
}
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Applied preset delta: %u regs, scal=%d, pa=%d",
|
||||
(unsigned)(delta_len / 2),
|
||||
needs_scal,
|
||||
pa_table != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_subghz_load_registers(const uint8_t* data) {
|
||||
furi_check(data);
|
||||
|
||||
|
||||
@@ -66,6 +66,12 @@ void furi_hal_subghz_dump_state(void);
|
||||
*/
|
||||
void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data);
|
||||
|
||||
void furi_hal_subghz_apply_preset_delta(
|
||||
const uint8_t* delta,
|
||||
size_t delta_len,
|
||||
bool needs_scal,
|
||||
const uint8_t* pa_table);
|
||||
|
||||
/** Load registers
|
||||
*
|
||||
* @param data Registers data
|
||||
|
||||
Reference in New Issue
Block a user