[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:
Skorpionm 2023-02-08 17:20:42 +04:00 committed by GitHub
parent cee9b640b3
commit 99253a0e28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 150 additions and 29 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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*

1 entry status name type params
2 Version + 13.0 13.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
2675 Function + subghz_worker_is_running _Bool SubGhzWorker*
2676 Function + subghz_worker_rx_callback void _Bool, uint32_t, void*
2677 Function + subghz_worker_set_context void SubGhzWorker*, void*
2678 Function + subghz_worker_set_filter void SubGhzWorker*, uint16_t
2679 Function + subghz_worker_set_overrun_callback void SubGhzWorker*, SubGhzWorkerOverrunCallback
2680 Function + subghz_worker_set_pair_callback void SubGhzWorker*, SubGhzWorkerPairCallback
2681 Function + subghz_worker_start void SubGhzWorker*

View File

@ -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

View File

@ -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() {

View File

@ -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);

View File

@ -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;
}

View File

@ -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