[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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm