2023-05-09 12:07:36 +03:00
|
|
|
#include "subghz_radio.h"
|
|
|
|
|
|
|
|
#define TAG "SubGhz"
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
void subghz_set_preset(
|
2023-05-09 12:07:36 +03:00
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint8_t* preset_data,
|
|
|
|
size_t preset_data_size) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_string_set(txrx->preset->name, preset_name);
|
|
|
|
txrx->preset->frequency = frequency;
|
|
|
|
txrx->preset->data = preset_data;
|
|
|
|
txrx->preset->data_size = preset_data_size;
|
|
|
|
}
|
|
|
|
|
2023-05-09 13:34:54 +03:00
|
|
|
void subghz_get_frequency_modulation(
|
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
FuriString* frequency,
|
|
|
|
FuriString* modulation,
|
|
|
|
bool long_name) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(frequency != NULL) {
|
|
|
|
furi_string_printf(
|
|
|
|
frequency,
|
|
|
|
"%03ld.%02ld",
|
|
|
|
txrx->preset->frequency / 1000000 % 1000,
|
|
|
|
txrx->preset->frequency / 10000 % 100);
|
|
|
|
}
|
|
|
|
if(modulation != NULL) {
|
|
|
|
if(long_name) {
|
|
|
|
furi_string_printf(modulation, "%s", furi_string_get_cstr(txrx->preset->name));
|
|
|
|
} else {
|
|
|
|
furi_string_printf(modulation, "%.2s", furi_string_get_cstr(txrx->preset->name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
const char* subghz_get_name_preset(SubGhzTxRx* txrx, const char* preset) {
|
2023-05-09 13:34:54 +03:00
|
|
|
UNUSED(txrx);
|
|
|
|
const char* preset_name = NULL;
|
2023-05-09 12:07:36 +03:00
|
|
|
if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
|
2023-05-09 13:34:54 +03:00
|
|
|
preset_name = "AM270";
|
2023-05-09 12:07:36 +03:00
|
|
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
|
2023-05-09 13:34:54 +03:00
|
|
|
preset_name = "AM650";
|
2023-05-09 12:07:36 +03:00
|
|
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
|
2023-05-09 13:34:54 +03:00
|
|
|
preset_name = "FM238";
|
2023-05-09 12:07:36 +03:00
|
|
|
} else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
|
2023-05-09 13:34:54 +03:00
|
|
|
preset_name = "FM476";
|
2023-05-09 12:07:36 +03:00
|
|
|
} else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
|
2023-05-09 13:34:54 +03:00
|
|
|
preset_name = "CUSTOM";
|
2023-05-09 12:07:36 +03:00
|
|
|
} else {
|
|
|
|
FURI_LOG_E(TAG, "Unknown preset");
|
|
|
|
}
|
2023-05-09 13:34:54 +03:00
|
|
|
return preset_name;
|
2023-05-09 12:07:36 +03:00
|
|
|
}
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
SubGhzRadioPreset subghz_get_preset(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return *txrx->preset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subghz_begin(SubGhzTxRx* txrx, uint8_t* preset_data) {
|
2023-05-09 12:07:36 +03:00
|
|
|
furi_assert(txrx);
|
|
|
|
furi_hal_subghz_reset();
|
|
|
|
furi_hal_subghz_idle();
|
|
|
|
furi_hal_subghz_load_custom_preset(preset_data);
|
|
|
|
furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
|
|
}
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
static uint32_t subghz_rx(SubGhzTxRx* txrx, uint32_t frequency) {
|
2023-05-09 12:07:36 +03:00
|
|
|
furi_assert(txrx);
|
|
|
|
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
|
|
|
furi_crash("SubGhz: Incorrect RX frequency.");
|
|
|
|
}
|
|
|
|
furi_assert(txrx->txrx_state != SubGhzTxRxStateRx && txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
|
|
|
|
|
|
furi_hal_subghz_idle();
|
|
|
|
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
|
|
|
|
furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
|
|
|
furi_hal_subghz_flush_rx();
|
|
|
|
subghz_speaker_on(txrx);
|
|
|
|
furi_hal_subghz_rx();
|
|
|
|
|
|
|
|
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, txrx->worker);
|
|
|
|
subghz_worker_start(txrx->worker);
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateRx;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subghz_idle(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
|
|
furi_hal_subghz_idle();
|
|
|
|
subghz_speaker_off(txrx);
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subghz_rx_end(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_assert(txrx->txrx_state == SubGhzTxRxStateRx);
|
|
|
|
|
|
|
|
if(subghz_worker_is_running(txrx->worker)) {
|
|
|
|
subghz_worker_stop(txrx->worker);
|
|
|
|
furi_hal_subghz_stop_async_rx();
|
|
|
|
}
|
|
|
|
furi_hal_subghz_idle();
|
|
|
|
subghz_speaker_off(txrx);
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateIDLE;
|
|
|
|
}
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
void subghz_sleep(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_hal_subghz_sleep();
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateSleep;
|
|
|
|
}
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
static bool subghz_tx(SubGhzTxRx* txrx, uint32_t frequency) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
|
|
|
furi_crash("SubGhz: Incorrect TX frequency.");
|
|
|
|
}
|
|
|
|
furi_assert(txrx->txrx_state != SubGhzTxRxStateSleep);
|
|
|
|
furi_hal_subghz_idle();
|
|
|
|
furi_hal_subghz_set_frequency_and_path(frequency);
|
|
|
|
furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false);
|
|
|
|
furi_hal_gpio_init(
|
|
|
|
furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
|
|
|
bool ret = furi_hal_subghz_tx();
|
|
|
|
if(ret) {
|
|
|
|
subghz_speaker_on(txrx);
|
|
|
|
txrx->txrx_state = SubGhzTxRxStateTx;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_tx_start(SubGhzTxRx* txrx, FlipperFormat* flipper_format) {
|
|
|
|
furi_assert(txrx);
|
2023-05-09 15:11:54 +03:00
|
|
|
furi_assert(flipper_format);
|
|
|
|
|
|
|
|
subghz_txrx_stop(txrx);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
FuriString* temp_str = furi_string_alloc();
|
|
|
|
uint32_t repeat = 200;
|
|
|
|
do {
|
|
|
|
if(!flipper_format_rewind(flipper_format)) {
|
|
|
|
FURI_LOG_E(TAG, "Rewind error");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
|
|
|
|
FURI_LOG_E(TAG, "Missing Protocol");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
|
|
|
|
FURI_LOG_E(TAG, "Unable Repeat");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, furi_string_get_cstr(temp_str));
|
|
|
|
|
|
|
|
if(txrx->transmitter) {
|
|
|
|
if(subghz_transmitter_deserialize(txrx->transmitter, flipper_format) ==
|
|
|
|
SubGhzProtocolStatusOk) {
|
|
|
|
if(strcmp(furi_string_get_cstr(txrx->preset->name), "") != 0) {
|
|
|
|
subghz_begin(
|
|
|
|
txrx,
|
|
|
|
subghz_setting_get_preset_data_by_name(
|
|
|
|
txrx->setting, furi_string_get_cstr(txrx->preset->name)));
|
|
|
|
} else {
|
|
|
|
FURI_LOG_E(
|
|
|
|
TAG,
|
|
|
|
"Unknown name preset \" %s \"",
|
|
|
|
furi_string_get_cstr(txrx->preset->name));
|
|
|
|
subghz_begin(
|
|
|
|
txrx, subghz_setting_get_preset_data_by_name(txrx->setting, "AM650"));
|
|
|
|
}
|
|
|
|
if(txrx->preset->frequency) {
|
|
|
|
ret = subghz_tx(txrx, txrx->preset->frequency);
|
|
|
|
} else {
|
|
|
|
ret = subghz_tx(txrx, 433920000);
|
|
|
|
}
|
|
|
|
if(ret) {
|
|
|
|
//Start TX
|
|
|
|
furi_hal_subghz_start_async_tx(subghz_transmitter_yield, txrx->transmitter);
|
|
|
|
} else {
|
|
|
|
//Todo: Show error
|
|
|
|
//subghz_dialog_message_show_only_rx(subghz);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//Todo: Show error
|
|
|
|
// dialog_message_show_storage_error(
|
|
|
|
// dialogs, "Error in protocol\nparameters\ndescription");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!ret) {
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
if(txrx->txrx_state != SubGhzTxRxStateSleep) {
|
|
|
|
subghz_idle(txrx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} while(false);
|
|
|
|
furi_string_free(temp_str);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
void subghz_rx_start(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
subghz_txrx_stop(txrx);
|
|
|
|
subghz_begin(
|
|
|
|
txrx,
|
|
|
|
subghz_setting_get_preset_data_by_name(
|
|
|
|
subghz_txrx_get_setting(txrx), furi_string_get_cstr(txrx->preset->name)));
|
|
|
|
subghz_rx(txrx, txrx->preset->frequency);
|
|
|
|
}
|
|
|
|
|
2023-05-09 12:07:36 +03:00
|
|
|
void subghz_txrx_need_save_callback_set(
|
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
SubGhzTxRxNeedSaveCallback callback,
|
|
|
|
void* context) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
txrx->need_save_callback = callback;
|
|
|
|
txrx->need_save_context = context;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subghz_tx_stop(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_assert(txrx->txrx_state == SubGhzTxRxStateTx);
|
|
|
|
//Stop TX
|
|
|
|
furi_hal_subghz_stop_async_tx();
|
|
|
|
subghz_transmitter_stop(txrx->transmitter);
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
//if protocol dynamic then we save the last upload
|
|
|
|
if(txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
|
|
|
|
if(txrx->need_save_callback) {
|
|
|
|
txrx->need_save_callback(txrx->need_save_context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
subghz_idle(txrx);
|
|
|
|
subghz_speaker_off(txrx);
|
|
|
|
//Todo: Show message
|
|
|
|
// notification_message(notifications, &sequence_reset_red);
|
|
|
|
}
|
|
|
|
|
|
|
|
FlipperFormat* subghz_txtx_get_fff_data(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->fff_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->setting;
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_txrx_stop(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
|
|
|
|
switch(txrx->txrx_state) {
|
|
|
|
case SubGhzTxRxStateTx:
|
|
|
|
subghz_tx_stop(txrx);
|
|
|
|
subghz_speaker_unmute(txrx);
|
|
|
|
//subghz_sleep(txrx);
|
|
|
|
break;
|
|
|
|
case SubGhzTxRxStateRx:
|
|
|
|
subghz_rx_end(txrx);
|
|
|
|
subghz_speaker_mute(txrx);
|
|
|
|
//subghz_sleep(txrx);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubGhzTxRxState subghz_txrx_get_state(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->txrx_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_hopper_update(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
|
|
|
|
switch(txrx->hopper_state) {
|
|
|
|
case SubGhzHopperStateOFF:
|
|
|
|
case SubGhzHopperStatePause:
|
|
|
|
return;
|
|
|
|
case SubGhzHopperStateRSSITimeOut:
|
|
|
|
if(txrx->hopper_timeout != 0) {
|
|
|
|
txrx->hopper_timeout--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
float rssi = -127.0f;
|
|
|
|
if(txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
|
|
|
|
// See RSSI Calculation timings in CC1101 17.3 RSSI
|
|
|
|
rssi = furi_hal_subghz_get_rssi();
|
|
|
|
|
|
|
|
// Stay if RSSI is high enough
|
|
|
|
if(rssi > -90.0f) {
|
|
|
|
txrx->hopper_timeout = 10;
|
|
|
|
txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
txrx->hopper_state = SubGhzHopperStateRunning;
|
|
|
|
}
|
|
|
|
// Select next frequency
|
|
|
|
if(txrx->hopper_idx_frequency < subghz_setting_get_hopper_frequency_count(txrx->setting) - 1) {
|
|
|
|
txrx->hopper_idx_frequency++;
|
|
|
|
} else {
|
|
|
|
txrx->hopper_idx_frequency = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(txrx->txrx_state == SubGhzTxRxStateRx) {
|
|
|
|
subghz_rx_end(txrx);
|
|
|
|
};
|
|
|
|
if(txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
|
|
|
subghz_receiver_reset(txrx->receiver);
|
|
|
|
txrx->preset->frequency =
|
|
|
|
subghz_setting_get_hopper_frequency(txrx->setting, txrx->hopper_idx_frequency);
|
|
|
|
subghz_rx(txrx, txrx->preset->frequency);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubGhzHopperState subghz_hopper_get_state(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->hopper_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_hopper_set_state(SubGhzTxRx* txrx, SubGhzHopperState state) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
txrx->hopper_state = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_hopper_remove_pause(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->hopper_state == SubGhzHopperStatePause) {
|
|
|
|
txrx->hopper_state = SubGhzHopperStateRunning;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_subghz_hopper_set_pause(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->hopper_state == SubGhzHopperStateRunning) {
|
|
|
|
txrx->hopper_state = SubGhzHopperStatePause;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_speaker_on(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
|
|
|
if(furi_hal_speaker_acquire(30)) {
|
|
|
|
if(!txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
txrx->speaker_state = SubGhzSpeakerStateDisable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_speaker_off(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
|
|
}
|
|
|
|
if(txrx->speaker_state != SubGhzSpeakerStateDisable) {
|
|
|
|
if(furi_hal_speaker_is_mine()) {
|
|
|
|
if(!txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
|
|
}
|
|
|
|
furi_hal_speaker_release();
|
|
|
|
if(txrx->speaker_state == SubGhzSpeakerStateShutdown)
|
|
|
|
txrx->speaker_state = SubGhzSpeakerStateDisable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_speaker_mute(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
|
|
}
|
|
|
|
if(txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
|
|
|
if(furi_hal_speaker_is_mine()) {
|
|
|
|
if(!txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_speaker_unmute(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
if(txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton);
|
|
|
|
}
|
|
|
|
if(txrx->speaker_state == SubGhzSpeakerStateEnable) {
|
|
|
|
if(furi_hal_speaker_is_mine()) {
|
|
|
|
if(!txrx->debug_pin_state) {
|
|
|
|
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void subghz_speaker_set_state(SubGhzTxRx* txrx, SubGhzSpeakerState state) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
txrx->speaker_state = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubGhzSpeakerState subghz_speaker_get_state(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->speaker_state;
|
|
|
|
}
|
|
|
|
|
2023-05-09 13:34:54 +03:00
|
|
|
bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* txrx, const char* name_protocol) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
furi_assert(name_protocol);
|
|
|
|
bool res = false;
|
|
|
|
txrx->decoder_result = NULL;
|
|
|
|
txrx->decoder_result =
|
|
|
|
subghz_receiver_search_decoder_base_by_name(txrx->receiver, name_protocol);
|
|
|
|
if(txrx->decoder_result) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* txrx) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
return txrx->decoder_result;
|
|
|
|
}
|
|
|
|
|
2023-05-09 12:07:36 +03:00
|
|
|
//#############Create new Key##############
|
|
|
|
#include <lib/subghz/protocols/protocol_items.h>
|
|
|
|
#include <lib/subghz/protocols/keeloq.h>
|
|
|
|
#include <lib/subghz/protocols/secplus_v1.h>
|
|
|
|
#include <lib/subghz/protocols/secplus_v2.h>
|
|
|
|
#include <lib/subghz/protocols/nice_flor_s.h>
|
|
|
|
|
|
|
|
#include <flipper_format/flipper_format_i.h>
|
|
|
|
#include <lib/toolbox/stream/stream.h>
|
|
|
|
#include <lib/subghz/protocols/raw.h>
|
|
|
|
|
|
|
|
bool subghz_gen_data_protocol(
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
const char* protocol_name,
|
|
|
|
uint64_t key,
|
|
|
|
uint32_t bit) {
|
|
|
|
furi_assert(context);
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
txrx->decoder_result =
|
|
|
|
subghz_receiver_search_decoder_base_by_name(txrx->receiver, protocol_name);
|
|
|
|
|
|
|
|
if(txrx->decoder_result == NULL) {
|
|
|
|
//TODO: Error
|
|
|
|
// furi_string_set(error_str, "Protocol not\nfound!");
|
|
|
|
// scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
Stream* fff_data_stream = flipper_format_get_raw_stream(txrx->fff_data);
|
|
|
|
stream_clean(fff_data_stream);
|
|
|
|
if(subghz_protocol_decoder_base_serialize(
|
|
|
|
txrx->decoder_result, txrx->fff_data, txrx->preset) != SubGhzProtocolStatusOk) {
|
|
|
|
FURI_LOG_E(TAG, "Unable to serialize");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(!flipper_format_update_uint32(txrx->fff_data, "Bit", &bit, 1)) {
|
|
|
|
FURI_LOG_E(TAG, "Unable to update Bit");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t key_data[sizeof(uint64_t)] = {0};
|
|
|
|
for(size_t i = 0; i < sizeof(uint64_t); i++) {
|
|
|
|
key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
|
|
|
|
}
|
|
|
|
if(!flipper_format_update_hex(txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
|
|
|
|
FURI_LOG_E(TAG, "Unable to update Key");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
res = true;
|
|
|
|
} while(false);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_gen_data_protocol_and_te(
|
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
const char* protocol_name,
|
|
|
|
uint64_t key,
|
|
|
|
uint32_t bit,
|
|
|
|
uint32_t te) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
bool ret = false;
|
|
|
|
if(subghz_gen_data_protocol(txrx, preset_name, frequency, protocol_name, key, bit)) {
|
|
|
|
if(!flipper_format_update_uint32(txrx->fff_data, "TE", (uint32_t*)&te, 1)) {
|
|
|
|
FURI_LOG_E(TAG, "Unable to update Te");
|
|
|
|
} else {
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_keeloq( //TODO rename
|
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt,
|
|
|
|
const char* manufacture_name) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_keeloq_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
manufacture_name,
|
|
|
|
txrx->preset)) {
|
|
|
|
flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", manufacture_name);
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_keeloq_bft( //TODO rename
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt,
|
|
|
|
uint32_t seed,
|
|
|
|
const char* manufacture_name) {
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_keeloq_bft_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
seed,
|
|
|
|
manufacture_name,
|
|
|
|
txrx->preset)) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(res) {
|
|
|
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
|
|
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
|
|
|
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
|
|
|
|
|
|
|
flipper_format_write_string_cstr(txrx->fff_data, "Manufacture", "BFT");
|
|
|
|
}
|
|
|
|
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_nice_flor( //TODO rename
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt,
|
|
|
|
bool nice_one) {
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_nice_flor_s_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
txrx->preset,
|
|
|
|
nice_one)) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_faac_slh( //TODO rename
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt,
|
|
|
|
uint32_t seed,
|
|
|
|
const char* manufacture_name) {
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_FAAC_SLH_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_faac_slh_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
seed,
|
|
|
|
manufacture_name,
|
|
|
|
txrx->preset)) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(res) {
|
|
|
|
uint8_t seed_data[sizeof(uint32_t)] = {0};
|
|
|
|
for(size_t i = 0; i < sizeof(uint32_t); i++) {
|
|
|
|
seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
flipper_format_write_hex(txrx->fff_data, "Seed", seed_data, sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_alutech_at_4n( //TODO rename
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt) {
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_alutech_at_4n_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
txrx->preset)) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_scene_set_type_submenu_gen_data_somfy_telis( //TODO rename
|
|
|
|
void* context,
|
|
|
|
const char* preset_name,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint16_t cnt) {
|
|
|
|
SubGhzTxRx* txrx = context;
|
|
|
|
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, preset_name, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
|
|
|
|
if(txrx->transmitter && subghz_protocol_somfy_telis_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
txrx->preset)) {
|
|
|
|
res = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
subghz_transmitter_free(txrx->transmitter);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_gen_secplus_v2_protocol(
|
|
|
|
SubGhzTxRx* txrx,
|
|
|
|
const char* name_preset,
|
|
|
|
uint32_t frequency,
|
|
|
|
uint32_t serial,
|
|
|
|
uint8_t btn,
|
|
|
|
uint32_t cnt) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
txrx->transmitter =
|
|
|
|
subghz_transmitter_alloc_init(txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
|
2023-05-09 15:11:54 +03:00
|
|
|
subghz_set_preset(txrx, name_preset, frequency, NULL, 0);
|
2023-05-09 12:07:36 +03:00
|
|
|
if(txrx->transmitter) {
|
|
|
|
subghz_protocol_secplus_v2_create_data(
|
|
|
|
subghz_transmitter_get_protocol_instance(txrx->transmitter),
|
|
|
|
txrx->fff_data,
|
|
|
|
serial,
|
|
|
|
btn,
|
|
|
|
cnt,
|
|
|
|
txrx->preset);
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool subghz_gen_secplus_v1_protocol(SubGhzTxRx* txrx, const char* name_preset, uint32_t frequency) {
|
|
|
|
furi_assert(txrx);
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
uint32_t serial = (uint32_t)rand();
|
|
|
|
while(!subghz_protocol_secplus_v1_check_fixed(serial)) {
|
|
|
|
serial = (uint32_t)rand();
|
|
|
|
}
|
|
|
|
if(subghz_gen_data_protocol(
|
|
|
|
txrx,
|
|
|
|
name_preset,
|
|
|
|
frequency,
|
|
|
|
SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
|
|
|
|
(uint64_t)serial << 32 | 0xE6000000,
|
|
|
|
42)) {
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|