[FL-3093, FL-3087] SubGhz: Fix Raw write, add short duration filter setting (#2300)
* SubGhz: Fix recording RAW files, sometimes could not start at a high level * SubGhz: subghz_worker, add short duration filter setting * SubGhz: capture raw timings in cli. Furi: clear pending interrupts on ISR set/reset * SubGhz: fix start duration in furi_hal_subghz_start_async_rx * [FL-3093] SubGhz: hopping issue in some regions * [FL-3087] SubGhz: fix delete-ok issue * SubGhz: remove copypasta from rx_raw cli command Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
parent
cee9b640b3
commit
99253a0e28
@ -28,13 +28,8 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event
|
||||
if(event.event == SubGhzCustomEventSceneDeleteSuccess) {
|
||||
if(scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW)) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
|
||||
} else if(scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneSaved)) {
|
||||
// Commented so that the user doesn't have to press
|
||||
// back twice to get to the main SubGhz menu after
|
||||
// deleting a file.
|
||||
//scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
subghz->scene_manager, SubGhzSceneStart);
|
||||
|
@ -129,6 +129,21 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
|
||||
subghz_history_get_raw_data(
|
||||
subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
|
||||
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
|
||||
subghz_tx_stop(subghz);
|
||||
}
|
||||
if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
|
||||
subghz_begin(
|
||||
subghz,
|
||||
subghz_setting_get_preset_data_by_name(
|
||||
subghz->setting,
|
||||
furi_string_get_cstr(subghz->txrx->preset->name)));
|
||||
subghz_rx(subghz, subghz->txrx->preset->frequency);
|
||||
}
|
||||
if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
|
||||
subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
|
||||
}
|
||||
subghz->state_notifications = SubGhzNotificationStateRx;
|
||||
} else {
|
||||
subghz->state_notifications = SubGhzNotificationStateTx;
|
||||
}
|
||||
|
@ -309,6 +309,81 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) {
|
||||
free(instance);
|
||||
}
|
||||
|
||||
void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
uint32_t frequency = 433920000;
|
||||
|
||||
if(furi_string_size(args)) {
|
||||
int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency);
|
||||
if(ret != 1) {
|
||||
printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency);
|
||||
cli_print_usage("subghz rx", "<Frequency: in Hz>", furi_string_get_cstr(args));
|
||||
return;
|
||||
}
|
||||
if(!furi_hal_subghz_is_frequency_valid(frequency)) {
|
||||
printf(
|
||||
"Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n",
|
||||
frequency);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate context and buffers
|
||||
SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx));
|
||||
instance->stream =
|
||||
furi_stream_buffer_alloc(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
|
||||
furi_check(instance->stream);
|
||||
|
||||
// Configure radio
|
||||
furi_hal_subghz_reset();
|
||||
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async);
|
||||
frequency = furi_hal_subghz_set_frequency_and_path(frequency);
|
||||
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
// Prepare and start RX
|
||||
furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance);
|
||||
|
||||
// Wait for packets to arrive
|
||||
printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency);
|
||||
LevelDuration level_duration;
|
||||
size_t counter = 0;
|
||||
while(!cli_cmd_interrupt_received(cli)) {
|
||||
int ret = furi_stream_buffer_receive(
|
||||
instance->stream, &level_duration, sizeof(LevelDuration), 10);
|
||||
if(ret == 0) {
|
||||
continue;
|
||||
}
|
||||
if(ret != sizeof(LevelDuration)) {
|
||||
puts("stream corrupt");
|
||||
break;
|
||||
}
|
||||
if(level_duration_is_reset(level_duration)) {
|
||||
puts(". ");
|
||||
} else {
|
||||
bool level = level_duration_get_level(level_duration);
|
||||
uint32_t duration = level_duration_get_duration(level_duration);
|
||||
printf("%c%lu ", level ? '+' : '-', duration);
|
||||
}
|
||||
furi_thread_stdout_flush();
|
||||
counter++;
|
||||
if(counter > 255) {
|
||||
puts("\r\n");
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown radio
|
||||
furi_hal_subghz_stop_async_rx();
|
||||
furi_hal_subghz_sleep();
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
// Cleanup
|
||||
furi_stream_buffer_free(instance->stream);
|
||||
free(instance);
|
||||
}
|
||||
void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(context);
|
||||
FuriString* file_name;
|
||||
@ -431,7 +506,8 @@ static void subghz_cli_command_print_usage() {
|
||||
printf("\tchat <frequency:in Hz>\t - Chat with other Flippers\r\n");
|
||||
printf(
|
||||
"\ttx <3 byte Key: in hex> <frequency: in Hz> <te: us> <repeat: count>\t - Transmitting key\r\n");
|
||||
printf("\trx <frequency:in Hz>\t - Reception key\r\n");
|
||||
printf("\trx <frequency:in Hz>\t - Receive\r\n");
|
||||
printf("\trx_raw <frequency:in Hz>\t - Receive RAW\r\n");
|
||||
printf("\tdecode_raw <file_name: path_RAW_file>\t - Testing\r\n");
|
||||
|
||||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
|
||||
@ -733,6 +809,11 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "rx_raw") == 0) {
|
||||
subghz_cli_command_rx_raw(cli, args, context);
|
||||
break;
|
||||
}
|
||||
|
||||
if(furi_string_cmp_str(cmd, "decode_raw") == 0) {
|
||||
subghz_cli_command_decode_raw(cli, args, context);
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
entry,status,name,type,params
|
||||
Version,+,13.0,,
|
||||
Version,+,13.1,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
@ -2675,6 +2675,7 @@ Function,+,subghz_worker_free,void,SubGhzWorker*
|
||||
Function,+,subghz_worker_is_running,_Bool,SubGhzWorker*
|
||||
Function,+,subghz_worker_rx_callback,void,"_Bool, uint32_t, void*"
|
||||
Function,+,subghz_worker_set_context,void,"SubGhzWorker*, void*"
|
||||
Function,+,subghz_worker_set_filter,void,"SubGhzWorker*, uint16_t"
|
||||
Function,+,subghz_worker_set_overrun_callback,void,"SubGhzWorker*, SubGhzWorkerOverrunCallback"
|
||||
Function,+,subghz_worker_set_pair_callback,void,"SubGhzWorker*, SubGhzWorkerPairCallback"
|
||||
Function,+,subghz_worker_start,void,SubGhzWorker*
|
||||
|
|
@ -74,6 +74,21 @@ __attribute__((always_inline)) static inline void
|
||||
NVIC_EnableIRQ(furi_hal_interrupt_irqn[index]);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
furi_hal_interrupt_clear_pending(FuriHalInterruptId index) {
|
||||
NVIC_ClearPendingIRQ(furi_hal_interrupt_irqn[index]);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
furi_hal_interrupt_get_pending(FuriHalInterruptId index) {
|
||||
NVIC_GetPendingIRQ(furi_hal_interrupt_irqn[index]);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
furi_hal_interrupt_set_pending(FuriHalInterruptId index) {
|
||||
NVIC_SetPendingIRQ(furi_hal_interrupt_irqn[index]);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void
|
||||
furi_hal_interrupt_disable(FuriHalInterruptId index) {
|
||||
NVIC_DisableIRQ(furi_hal_interrupt_irqn[index]);
|
||||
@ -123,6 +138,7 @@ void furi_hal_interrupt_set_isr_ex(
|
||||
// Pre ISR clear
|
||||
furi_assert(furi_hal_interrupt_isr[index].isr != NULL);
|
||||
furi_hal_interrupt_disable(index);
|
||||
furi_hal_interrupt_clear_pending(index);
|
||||
}
|
||||
|
||||
furi_hal_interrupt_isr[index].isr = isr;
|
||||
@ -131,6 +147,7 @@ void furi_hal_interrupt_set_isr_ex(
|
||||
|
||||
if(isr) {
|
||||
// Post ISR set
|
||||
furi_hal_interrupt_clear_pending(index);
|
||||
furi_hal_interrupt_enable(index, priority);
|
||||
} else {
|
||||
// Post ISR clear
|
||||
|
@ -438,7 +438,7 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
|
||||
TIM_InitStruct.Prescaler = 64 - 1;
|
||||
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
|
||||
TIM_InitStruct.Autoreload = 0x7FFFFFFE;
|
||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4;
|
||||
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV4; // Clock division for capture filter
|
||||
LL_TIM_Init(TIM2, &TIM_InitStruct);
|
||||
|
||||
// Timer: advanced
|
||||
@ -455,13 +455,15 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
|
||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_INDIRECTTI);
|
||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
|
||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_FALLING);
|
||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
|
||||
|
||||
// Timer: channel 2 direct
|
||||
LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_DIRECTTI);
|
||||
LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1);
|
||||
LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_RISING);
|
||||
LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV32_N8);
|
||||
LL_TIM_IC_SetFilter(
|
||||
TIM2,
|
||||
LL_TIM_CHANNEL_CH2,
|
||||
LL_TIM_IC_FILTER_FDIV32_N8); // Capture filter: 1/(64000000/64/4/32*8) = 16us
|
||||
|
||||
// ISR setup
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_subghz_capture_ISR, NULL);
|
||||
@ -481,6 +483,9 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
|
||||
|
||||
// Switch to RX
|
||||
furi_hal_subghz_rx();
|
||||
|
||||
//Clear the variable after the end of the session
|
||||
furi_hal_subghz_capture_delta_duration = 0;
|
||||
}
|
||||
|
||||
void furi_hal_subghz_stop_async_rx() {
|
||||
|
@ -159,6 +159,7 @@ bool subghz_protocol_raw_save_to_file_init(
|
||||
instance->upload_raw = malloc(SUBGHZ_DOWNLOAD_MAX_SIZE * sizeof(int32_t));
|
||||
instance->file_is_open = RAWFileIsOpenWrite;
|
||||
instance->sample_write = 0;
|
||||
instance->last_level = false;
|
||||
instance->pause = false;
|
||||
init = true;
|
||||
} while(0);
|
||||
|
@ -12,7 +12,6 @@ struct SubGhzWorker {
|
||||
volatile bool overrun;
|
||||
|
||||
LevelDuration filter_level_duration;
|
||||
bool filter_running;
|
||||
uint16_t filter_duration;
|
||||
|
||||
SubGhzWorkerOverrunCallback overrun_callback;
|
||||
@ -59,24 +58,19 @@ static int32_t subghz_worker_thread_callback(void* context) {
|
||||
bool level = level_duration_get_level(level_duration);
|
||||
uint32_t duration = level_duration_get_duration(level_duration);
|
||||
|
||||
if(instance->filter_running) {
|
||||
if((duration < instance->filter_duration) ||
|
||||
(instance->filter_level_duration.level == level)) {
|
||||
instance->filter_level_duration.duration += duration;
|
||||
if((duration < instance->filter_duration) ||
|
||||
(instance->filter_level_duration.level == level)) {
|
||||
instance->filter_level_duration.duration += duration;
|
||||
|
||||
} else if(instance->filter_level_duration.level != level) {
|
||||
if(instance->pair_callback)
|
||||
instance->pair_callback(
|
||||
instance->context,
|
||||
instance->filter_level_duration.level,
|
||||
instance->filter_level_duration.duration);
|
||||
|
||||
instance->filter_level_duration.duration = duration;
|
||||
instance->filter_level_duration.level = level;
|
||||
}
|
||||
} else {
|
||||
} else if(instance->filter_level_duration.level != level) {
|
||||
if(instance->pair_callback)
|
||||
instance->pair_callback(instance->context, level, duration);
|
||||
instance->pair_callback(
|
||||
instance->context,
|
||||
instance->filter_level_duration.level,
|
||||
instance->filter_level_duration.duration);
|
||||
|
||||
instance->filter_level_duration.duration = duration;
|
||||
instance->filter_level_duration.level = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +88,7 @@ SubGhzWorker* subghz_worker_alloc() {
|
||||
instance->stream =
|
||||
furi_stream_buffer_alloc(sizeof(LevelDuration) * 4096, sizeof(LevelDuration));
|
||||
|
||||
//setting filter
|
||||
instance->filter_running = true;
|
||||
//setting default filter in us
|
||||
instance->filter_duration = 30;
|
||||
|
||||
return instance;
|
||||
@ -149,3 +142,8 @@ bool subghz_worker_is_running(SubGhzWorker* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->running;
|
||||
}
|
||||
|
||||
void subghz_worker_set_filter(SubGhzWorker* instance, uint16_t timeout) {
|
||||
furi_assert(instance);
|
||||
instance->filter_duration = timeout;
|
||||
}
|
@ -67,6 +67,14 @@ void subghz_worker_stop(SubGhzWorker* instance);
|
||||
*/
|
||||
bool subghz_worker_is_running(SubGhzWorker* instance);
|
||||
|
||||
/**
|
||||
* Short duration filter setting.
|
||||
* glues short durations into 1. The default setting is 30 us, if set to 0 the filter will be disabled
|
||||
* @param instance Pointer to a SubGhzWorker instance
|
||||
* @param timeout time in us
|
||||
*/
|
||||
void subghz_worker_set_filter(SubGhzWorker* instance, uint16_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user