[FL-3040] Audio support for SubGhz (#2131)
* Furi_hal_speaker: multiple resource usage * Furi_hal_speaker: fix multiple resource usage * Furi_hal_speaker: fix music_player_worker * Furi_hal_speaker: fix mutex release queue handling * SubGhz: add furi_hal_subghz_set_debug_pin * SubGhz: add sound SubGhz Read, SubGhz Read RAW * furi_hal_speaker: add __attribute__((warn_unused_result)) for furi_hal_speaker_acquire() * Furi_hal_speaker: fix review comments * SubGhz: cleanup naming and locking timings * SubGhz,FuriHal: fix speaker deinit logic and subghz speaker release sequence * FuriHal: crash on speaker acquire/release from IRQ * Furi, FuriHal: FURI_WARN_UNUSED and documentation update * Bump api symbols version: fix broken speaker Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									3681a5478c
								
							
						
					
					
						commit
						2dea6969fe
					
				| @ -28,6 +28,13 @@ typedef enum { | |||||||
|     SubGhzHopperStateRSSITimeOut, |     SubGhzHopperStateRSSITimeOut, | ||||||
| } SubGhzHopperState; | } SubGhzHopperState; | ||||||
| 
 | 
 | ||||||
|  | /** SubGhzSpeakerState state */ | ||||||
|  | typedef enum { | ||||||
|  |     SubGhzSpeakerStateDisable, | ||||||
|  |     SubGhzSpeakerStateShutdown, | ||||||
|  |     SubGhzSpeakerStateEnable, | ||||||
|  | } SubGhzSpeakerState; | ||||||
|  | 
 | ||||||
| /** SubGhzRxKeyState state */ | /** SubGhzRxKeyState state */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     SubGhzRxKeyStateIDLE, |     SubGhzRxKeyStateIDLE, | ||||||
|  | |||||||
| @ -259,6 +259,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|         case SubGhzCustomEventViewReadRAWSendStop: |         case SubGhzCustomEventViewReadRAWSendStop: | ||||||
|             subghz->state_notifications = SubGhzNotificationStateIDLE; |             subghz->state_notifications = SubGhzNotificationStateIDLE; | ||||||
|             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|  |                 subghz_speaker_unmute(subghz); | ||||||
|                 subghz_tx_stop(subghz); |                 subghz_tx_stop(subghz); | ||||||
|                 subghz_sleep(subghz); |                 subghz_sleep(subghz); | ||||||
|             } |             } | ||||||
| @ -376,10 +377,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); |                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false); | ||||||
|                     subghz_protocol_raw_save_to_file_pause( |                     subghz_protocol_raw_save_to_file_pause( | ||||||
|                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); |                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true); | ||||||
|  |                     subghz_speaker_mute(subghz); | ||||||
|                 } else { |                 } else { | ||||||
|                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); |                     subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); | ||||||
|                     subghz_protocol_raw_save_to_file_pause( |                     subghz_protocol_raw_save_to_file_pause( | ||||||
|                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); |                         (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); | ||||||
|  |                     subghz_speaker_unmute(subghz); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ enum SubGhzSettingIndex { | |||||||
|     SubGhzSettingIndexFrequency, |     SubGhzSettingIndexFrequency, | ||||||
|     SubGhzSettingIndexHopping, |     SubGhzSettingIndexHopping, | ||||||
|     SubGhzSettingIndexModulation, |     SubGhzSettingIndexModulation, | ||||||
|  |     SubGhzSettingIndexSound, | ||||||
|     SubGhzSettingIndexLock, |     SubGhzSettingIndexLock, | ||||||
|     SubGhzSettingIndexRAWThesholdRSSI, |     SubGhzSettingIndexRAWThesholdRSSI, | ||||||
| }; | }; | ||||||
| @ -48,6 +49,16 @@ const uint32_t hopping_value[HOPPING_COUNT] = { | |||||||
|     SubGhzHopperStateRunnig, |     SubGhzHopperStateRunnig, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define SPEAKER_COUNT 2 | ||||||
|  | const char* const speaker_text[SPEAKER_COUNT] = { | ||||||
|  |     "OFF", | ||||||
|  |     "ON", | ||||||
|  | }; | ||||||
|  | const uint32_t speaker_value[SPEAKER_COUNT] = { | ||||||
|  |     SubGhzSpeakerStateShutdown, | ||||||
|  |     SubGhzSpeakerStateEnable, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { | uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| @ -167,6 +178,14 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) | |||||||
|     subghz->txrx->hopper_state = hopping_value[index]; |     subghz->txrx->hopper_state = hopping_value[index]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void subghz_scene_receiver_config_set_speaker(VariableItem* item) { | ||||||
|  |     SubGhz* subghz = variable_item_get_context(item); | ||||||
|  |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
|  | 
 | ||||||
|  |     variable_item_set_current_value_text(item, speaker_text[index]); | ||||||
|  |     subghz->txrx->speaker_state = speaker_value[index]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { | static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) { | ||||||
|     SubGhz* subghz = variable_item_get_context(item); |     SubGhz* subghz = variable_item_get_context(item); | ||||||
|     uint8_t index = variable_item_get_current_value_index(item); |     uint8_t index = variable_item_get_current_value_index(item); | ||||||
| @ -235,6 +254,16 @@ void subghz_scene_receiver_config_on_enter(void* context) { | |||||||
|     variable_item_set_current_value_text( |     variable_item_set_current_value_text( | ||||||
|         item, subghz_setting_get_preset_name(subghz->setting, value_index)); |         item, subghz_setting_get_preset_name(subghz->setting, value_index)); | ||||||
| 
 | 
 | ||||||
|  |     item = variable_item_list_add( | ||||||
|  |         subghz->variable_item_list, | ||||||
|  |         "Sound:", | ||||||
|  |         SPEAKER_COUNT, | ||||||
|  |         subghz_scene_receiver_config_set_speaker, | ||||||
|  |         subghz); | ||||||
|  |     value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT); | ||||||
|  |     variable_item_set_current_value_index(item, value_index); | ||||||
|  |     variable_item_set_current_value_text(item, speaker_text[value_index]); | ||||||
|  | 
 | ||||||
|     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != |     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) != | ||||||
|        SubGhzCustomEventManagerSet) { |        SubGhzCustomEventManagerSet) { | ||||||
|         variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL); |         variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL); | ||||||
|  | |||||||
| @ -177,6 +177,7 @@ SubGhz* subghz_alloc() { | |||||||
| 
 | 
 | ||||||
|     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; |     subghz->txrx->txrx_state = SubGhzTxRxStateSleep; | ||||||
|     subghz->txrx->hopper_state = SubGhzHopperStateOFF; |     subghz->txrx->hopper_state = SubGhzHopperStateOFF; | ||||||
|  |     subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; | ||||||
|     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; |     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE; | ||||||
|     subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; |     subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; | ||||||
|     subghz->txrx->history = subghz_history_alloc(); |     subghz->txrx->history = subghz_history_alloc(); | ||||||
|  | |||||||
| @ -86,6 +86,7 @@ uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) { | |||||||
|     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); |     uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); | ||||||
|     furi_hal_subghz_flush_rx(); |     furi_hal_subghz_flush_rx(); | ||||||
|  |     subghz_speaker_on(subghz); | ||||||
|     furi_hal_subghz_rx(); |     furi_hal_subghz_rx(); | ||||||
| 
 | 
 | ||||||
|     furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); |     furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker); | ||||||
| @ -104,6 +105,7 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) { | |||||||
|     furi_hal_subghz_set_frequency_and_path(frequency); |     furi_hal_subghz_set_frequency_and_path(frequency); | ||||||
|     furi_hal_gpio_write(&gpio_cc1101_g0, false); |     furi_hal_gpio_write(&gpio_cc1101_g0, false); | ||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); | ||||||
|  |     subghz_speaker_on(subghz); | ||||||
|     bool ret = furi_hal_subghz_tx(); |     bool ret = furi_hal_subghz_tx(); | ||||||
|     subghz->txrx->txrx_state = SubGhzTxRxStateTx; |     subghz->txrx->txrx_state = SubGhzTxRxStateTx; | ||||||
|     return ret; |     return ret; | ||||||
| @ -119,11 +121,13 @@ void subghz_idle(SubGhz* subghz) { | |||||||
| void subghz_rx_end(SubGhz* subghz) { | void subghz_rx_end(SubGhz* subghz) { | ||||||
|     furi_assert(subghz); |     furi_assert(subghz); | ||||||
|     furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); |     furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx); | ||||||
|  | 
 | ||||||
|     if(subghz_worker_is_running(subghz->txrx->worker)) { |     if(subghz_worker_is_running(subghz->txrx->worker)) { | ||||||
|         subghz_worker_stop(subghz->txrx->worker); |         subghz_worker_stop(subghz->txrx->worker); | ||||||
|         furi_hal_subghz_stop_async_rx(); |         furi_hal_subghz_stop_async_rx(); | ||||||
|     } |     } | ||||||
|     furi_hal_subghz_idle(); |     furi_hal_subghz_idle(); | ||||||
|  |     subghz_speaker_off(subghz); | ||||||
|     subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; |     subghz->txrx->txrx_state = SubGhzTxRxStateIDLE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -212,6 +216,7 @@ void subghz_tx_stop(SubGhz* subghz) { | |||||||
|             subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); |             subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path)); | ||||||
|     } |     } | ||||||
|     subghz_idle(subghz); |     subghz_idle(subghz); | ||||||
|  |     subghz_speaker_off(subghz); | ||||||
|     notification_message(subghz->notifications, &sequence_reset_red); |     notification_message(subghz->notifications, &sequence_reset_red); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -585,3 +590,40 @@ void subghz_hopper_update(SubGhz* subghz) { | |||||||
|         subghz_rx(subghz, subghz->txrx->preset->frequency); |         subghz_rx(subghz, subghz->txrx->preset->frequency); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void subghz_speaker_on(SubGhz* subghz) { | ||||||
|  |     if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { | ||||||
|  |         if(furi_hal_speaker_acquire(30)) { | ||||||
|  |             furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); | ||||||
|  |         } else { | ||||||
|  |             subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_speaker_off(SubGhz* subghz) { | ||||||
|  |     if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) { | ||||||
|  |         if(furi_hal_speaker_is_mine()) { | ||||||
|  |             furi_hal_subghz_set_async_mirror_pin(NULL); | ||||||
|  |             furi_hal_speaker_release(); | ||||||
|  |             if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown) | ||||||
|  |                 subghz->txrx->speaker_state = SubGhzSpeakerStateDisable; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_speaker_mute(SubGhz* subghz) { | ||||||
|  |     if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { | ||||||
|  |         if(furi_hal_speaker_is_mine()) { | ||||||
|  |             furi_hal_subghz_set_async_mirror_pin(NULL); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_speaker_unmute(SubGhz* subghz) { | ||||||
|  |     if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) { | ||||||
|  |         if(furi_hal_speaker_is_mine()) { | ||||||
|  |             furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -53,6 +53,7 @@ struct SubGhzTxRx { | |||||||
|     uint16_t idx_menu_chosen; |     uint16_t idx_menu_chosen; | ||||||
|     SubGhzTxRxState txrx_state; |     SubGhzTxRxState txrx_state; | ||||||
|     SubGhzHopperState hopper_state; |     SubGhzHopperState hopper_state; | ||||||
|  |     SubGhzSpeakerState speaker_state; | ||||||
|     uint8_t hopper_timeout; |     uint8_t hopper_timeout; | ||||||
|     uint8_t hopper_idx_frequency; |     uint8_t hopper_idx_frequency; | ||||||
|     SubGhzRxKeyState rx_key_state; |     SubGhzRxKeyState rx_key_state; | ||||||
| @ -131,3 +132,7 @@ void subghz_file_name_clear(SubGhz* subghz); | |||||||
| bool subghz_path_is_file(FuriString* path); | bool subghz_path_is_file(FuriString* path); | ||||||
| uint32_t subghz_random_serial(void); | uint32_t subghz_random_serial(void); | ||||||
| void subghz_hopper_update(SubGhz* subghz); | void subghz_hopper_update(SubGhz* subghz); | ||||||
|  | void subghz_speaker_on(SubGhz* subghz); | ||||||
|  | void subghz_speaker_off(SubGhz* subghz); | ||||||
|  | void subghz_speaker_mute(SubGhz* subghz); | ||||||
|  | void subghz_speaker_unmute(SubGhz* subghz); | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ static int32_t music_player_worker_thread_callback(void* context) { | |||||||
| 
 | 
 | ||||||
|     NoteBlockArray_it_t it; |     NoteBlockArray_it_t it; | ||||||
|     NoteBlockArray_it(it, instance->notes); |     NoteBlockArray_it(it, instance->notes); | ||||||
| 
 |     if(furi_hal_speaker_acquire(1000)) { | ||||||
|         while(instance->should_work) { |         while(instance->should_work) { | ||||||
|             if(NoteBlockArray_end_p(it)) { |             if(NoteBlockArray_end_p(it)) { | ||||||
|                 NoteBlockArray_it(it, instance->notes); |                 NoteBlockArray_it(it, instance->notes); | ||||||
| @ -57,8 +57,8 @@ static int32_t music_player_worker_thread_callback(void* context) { | |||||||
| 
 | 
 | ||||||
|                 float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE; |                 float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE; | ||||||
|                 float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4); |                 float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4); | ||||||
|             float duration = |                 float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / | ||||||
|                 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / note_block->duration; |                                  note_block->duration; | ||||||
|                 uint32_t dots = note_block->dots; |                 uint32_t dots = note_block->dots; | ||||||
|                 while(dots > 0) { |                 while(dots > 0) { | ||||||
|                     duration += duration / 2; |                     duration += duration / 2; | ||||||
| @ -88,6 +88,10 @@ static int32_t music_player_worker_thread_callback(void* context) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         furi_hal_speaker_stop(); |         furi_hal_speaker_stop(); | ||||||
|  |         furi_hal_speaker_release(); | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_E(TAG, "Speaker system is busy with another process."); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -150,11 +150,16 @@ void notification_vibro_off() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void notification_sound_on(float freq, float volume) { | void notification_sound_on(float freq, float volume) { | ||||||
|  |     if(furi_hal_speaker_acquire(30)) { | ||||||
|         furi_hal_speaker_start(freq, volume); |         furi_hal_speaker_start(freq, volume); | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void notification_sound_off() { | void notification_sound_off() { | ||||||
|  |     if(furi_hal_speaker_is_mine()) { | ||||||
|         furi_hal_speaker_stop(); |         furi_hal_speaker_stop(); | ||||||
|  |         furi_hal_speaker_release(); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // display timer
 | // display timer
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,10.1,, | Version,+,11.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -1282,7 +1282,11 @@ Function,+,furi_hal_rtc_set_log_level,void,uint8_t | |||||||
| Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t | Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t | ||||||
| Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" | Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t" | ||||||
| Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime* | ||||||
|  | Function,+,furi_hal_speaker_acquire,_Bool,uint32_t | ||||||
|  | Function,-,furi_hal_speaker_deinit,void, | ||||||
| Function,-,furi_hal_speaker_init,void, | Function,-,furi_hal_speaker_init,void, | ||||||
|  | Function,+,furi_hal_speaker_is_mine,_Bool, | ||||||
|  | Function,+,furi_hal_speaker_release,void, | ||||||
| Function,+,furi_hal_speaker_set_volume,void,float | Function,+,furi_hal_speaker_set_volume,void,float | ||||||
| Function,+,furi_hal_speaker_start,void,"float, float" | Function,+,furi_hal_speaker_start,void,"float, float" | ||||||
| Function,+,furi_hal_speaker_stop,void, | Function,+,furi_hal_speaker_stop,void, | ||||||
| @ -1316,6 +1320,7 @@ Function,+,furi_hal_subghz_read_packet,void,"uint8_t*, uint8_t*" | |||||||
| Function,+,furi_hal_subghz_reset,void, | Function,+,furi_hal_subghz_reset,void, | ||||||
| Function,+,furi_hal_subghz_rx,void, | Function,+,furi_hal_subghz_rx,void, | ||||||
| Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, | Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, | ||||||
|  | Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* | ||||||
| Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t | Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t | ||||||
| Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t | Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t | ||||||
| Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath | Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath | ||||||
|  | |||||||
| 
 | 
| @ -1,23 +1,66 @@ | |||||||
| #include <furi_hal_speaker.h> | #include <furi_hal_speaker.h> | ||||||
| #include <furi_hal_gpio.h> | #include <furi_hal_gpio.h> | ||||||
| #include <furi_hal_resources.h> | #include <furi_hal_resources.h> | ||||||
|  | #include <furi_hal_power.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx_ll_tim.h> | #include <stm32wbxx_ll_tim.h> | ||||||
|  | #include <furi_hal_cortex.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "FuriHalSpeaker" | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_SPEAKER_TIMER TIM16 | #define FURI_HAL_SPEAKER_TIMER TIM16 | ||||||
| #define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1 | #define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1 | ||||||
| #define FURI_HAL_SPEAKER_PRESCALER 500 | #define FURI_HAL_SPEAKER_PRESCALER 500 | ||||||
| #define FURI_HAL_SPEAKER_MAX_VOLUME 60 | #define FURI_HAL_SPEAKER_MAX_VOLUME 60 | ||||||
| 
 | 
 | ||||||
|  | static FuriMutex* furi_hal_speaker_mutex = NULL; | ||||||
|  | 
 | ||||||
| // #define FURI_HAL_SPEAKER_NEW_VOLUME
 | // #define FURI_HAL_SPEAKER_NEW_VOLUME
 | ||||||
| 
 | 
 | ||||||
| void furi_hal_speaker_init() { | void furi_hal_speaker_init() { | ||||||
|  |     furi_assert(furi_hal_speaker_mutex == NULL); | ||||||
|  |     furi_hal_speaker_mutex = furi_mutex_alloc(FuriMutexTypeNormal); | ||||||
|     FURI_CRITICAL_ENTER(); |     FURI_CRITICAL_ENTER(); | ||||||
|     LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); |     LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); | ||||||
|     FURI_CRITICAL_EXIT(); |     FURI_CRITICAL_EXIT(); | ||||||
|  |     FURI_LOG_I(TAG, "Init OK"); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | void furi_hal_speaker_deinit() { | ||||||
|  |     furi_check(furi_hal_speaker_mutex != NULL); | ||||||
|  |     LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); | ||||||
|  |     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|  |     furi_mutex_free(furi_hal_speaker_mutex); | ||||||
|  |     furi_hal_speaker_mutex = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_speaker_acquire(uint32_t timeout) { | ||||||
|  |     furi_check(!FURI_IS_IRQ_MODE()); | ||||||
|  | 
 | ||||||
|  |     if(furi_mutex_acquire(furi_hal_speaker_mutex, timeout) == FuriStatusOk) { | ||||||
|  |         furi_hal_power_insomnia_enter(); | ||||||
|         furi_hal_gpio_init_ex( |         furi_hal_gpio_init_ex( | ||||||
|             &gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16); |             &gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16); | ||||||
|  |         return true; | ||||||
|  |     } else { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_speaker_release() { | ||||||
|  |     furi_check(!FURI_IS_IRQ_MODE()); | ||||||
|  |     furi_check(furi_hal_speaker_is_mine()); | ||||||
|  | 
 | ||||||
|  |     furi_hal_speaker_stop(); | ||||||
|  |     furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|  |     furi_hal_power_insomnia_exit(); | ||||||
|  | 
 | ||||||
|  |     furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_speaker_is_mine() { | ||||||
|  |     return (FURI_IS_IRQ_MODE()) || | ||||||
|  |            (furi_mutex_get_owner(furi_hal_speaker_mutex) == furi_thread_get_current_id()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline uint32_t furi_hal_speaker_calculate_autoreload(float frequency) { | static inline uint32_t furi_hal_speaker_calculate_autoreload(float frequency) { | ||||||
| @ -54,6 +97,8 @@ static inline uint32_t furi_hal_speaker_calculate_compare(float volume) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_speaker_start(float frequency, float volume) { | void furi_hal_speaker_start(float frequency, float volume) { | ||||||
|  |     furi_check(furi_hal_speaker_is_mine()); | ||||||
|  | 
 | ||||||
|     if(volume <= 0) { |     if(volume <= 0) { | ||||||
|         furi_hal_speaker_stop(); |         furi_hal_speaker_stop(); | ||||||
|         return; |         return; | ||||||
| @ -75,6 +120,7 @@ void furi_hal_speaker_start(float frequency, float volume) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_speaker_set_volume(float volume) { | void furi_hal_speaker_set_volume(float volume) { | ||||||
|  |     furi_check(furi_hal_speaker_is_mine()); | ||||||
|     if(volume <= 0) { |     if(volume <= 0) { | ||||||
|         furi_hal_speaker_stop(); |         furi_hal_speaker_stop(); | ||||||
|         return; |         return; | ||||||
| @ -88,6 +134,7 @@ void furi_hal_speaker_set_volume(float volume) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_speaker_stop() { | void furi_hal_speaker_stop() { | ||||||
|  |     furi_check(furi_hal_speaker_is_mine()); | ||||||
|     LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER); |     LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER); | ||||||
|     LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER); |     LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER); | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
| #include <furi_hal_region.h> | #include <furi_hal_region.h> | ||||||
| #include <furi_hal_version.h> | #include <furi_hal_version.h> | ||||||
| #include <furi_hal_rtc.h> | #include <furi_hal_rtc.h> | ||||||
| #include <furi_hal_gpio.h> |  | ||||||
| #include <furi_hal_spi.h> | #include <furi_hal_spi.h> | ||||||
| #include <furi_hal_interrupt.h> | #include <furi_hal_interrupt.h> | ||||||
| #include <furi_hal_resources.h> | #include <furi_hal_resources.h> | ||||||
| @ -17,39 +16,26 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "FuriHalSubGhz" | #define TAG "FuriHalSubGhz" | ||||||
| 
 | 
 | ||||||
| /*
 | static uint32_t furi_hal_subghz_debug_gpio_buff[2]; | ||||||
|  * Uncomment define to enable duplication of |  | ||||||
|  * IO GO0 CC1101 to an external comb. |  | ||||||
|  * Debug pin can be assigned |  | ||||||
|  *      gpio_ext_pc0 |  | ||||||
|  *      gpio_ext_pc1 |  | ||||||
|  *      gpio_ext_pc3 |  | ||||||
|  *      gpio_ext_pb2 |  | ||||||
|  *      gpio_ext_pb3 |  | ||||||
|  *      gpio_ext_pa4 |  | ||||||
|  *      gpio_ext_pa6 |  | ||||||
|  *      gpio_ext_pa7 |  | ||||||
|  * Attention this setting switches pin to output.  |  | ||||||
|  * Make sure it is not connected directly to power or ground |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| //#define SUBGHZ_DEBUG_CC1101_PIN gpio_ext_pa7
 |  | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |  | ||||||
| uint32_t subghz_debug_gpio_buff[2]; |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     volatile SubGhzState state; |     volatile SubGhzState state; | ||||||
|     volatile SubGhzRegulation regulation; |     volatile SubGhzRegulation regulation; | ||||||
|     volatile FuriHalSubGhzPreset preset; |     volatile FuriHalSubGhzPreset preset; | ||||||
|  |     const GpioPin* async_mirror_pin; | ||||||
| } FuriHalSubGhz; | } FuriHalSubGhz; | ||||||
| 
 | 
 | ||||||
| volatile FuriHalSubGhz furi_hal_subghz = { | volatile FuriHalSubGhz furi_hal_subghz = { | ||||||
|     .state = SubGhzStateInit, |     .state = SubGhzStateInit, | ||||||
|     .regulation = SubGhzRegulationTxRx, |     .regulation = SubGhzRegulationTxRx, | ||||||
|     .preset = FuriHalSubGhzPresetIDLE, |     .preset = FuriHalSubGhzPresetIDLE, | ||||||
|  |     .async_mirror_pin = NULL, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { | ||||||
|  |     furi_hal_subghz.async_mirror_pin = pin; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void furi_hal_subghz_init() { | void furi_hal_subghz_init() { | ||||||
|     furi_assert(furi_hal_subghz.state == SubGhzStateInit); |     furi_assert(furi_hal_subghz.state == SubGhzStateInit); | ||||||
|     furi_hal_subghz.state = SubGhzStateIdle; |     furi_hal_subghz.state = SubGhzStateIdle; | ||||||
| @ -372,6 +358,29 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) { | |||||||
|     furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); |     furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool furi_hal_subghz_start_debug() { | ||||||
|  |     bool ret = false; | ||||||
|  |     if(furi_hal_subghz.async_mirror_pin != NULL) { | ||||||
|  |         furi_hal_gpio_init( | ||||||
|  |             furi_hal_subghz.async_mirror_pin, | ||||||
|  |             GpioModeOutputPushPull, | ||||||
|  |             GpioPullNo, | ||||||
|  |             GpioSpeedVeryHigh); | ||||||
|  |         ret = true; | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool furi_hal_subghz_stop_debug() { | ||||||
|  |     bool ret = false; | ||||||
|  |     if(furi_hal_subghz.async_mirror_pin != NULL) { | ||||||
|  |         furi_hal_gpio_init( | ||||||
|  |             furi_hal_subghz.async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
|  |         ret = true; | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| volatile uint32_t furi_hal_subghz_capture_delta_duration = 0; | volatile uint32_t furi_hal_subghz_capture_delta_duration = 0; | ||||||
| volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL; | volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL; | ||||||
| volatile void* furi_hal_subghz_capture_callback_context = NULL; | volatile void* furi_hal_subghz_capture_callback_context = NULL; | ||||||
| @ -382,9 +391,9 @@ static void furi_hal_subghz_capture_ISR() { | |||||||
|         LL_TIM_ClearFlag_CC1(TIM2); |         LL_TIM_ClearFlag_CC1(TIM2); | ||||||
|         furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); |         furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2); | ||||||
|         if(furi_hal_subghz_capture_callback) { |         if(furi_hal_subghz_capture_callback) { | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |             if(furi_hal_subghz.async_mirror_pin != NULL) | ||||||
|             furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, false); |                 furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false); | ||||||
| #endif | 
 | ||||||
|             furi_hal_subghz_capture_callback( |             furi_hal_subghz_capture_callback( | ||||||
|                 true, |                 true, | ||||||
|                 furi_hal_subghz_capture_delta_duration, |                 furi_hal_subghz_capture_delta_duration, | ||||||
| @ -395,9 +404,9 @@ static void furi_hal_subghz_capture_ISR() { | |||||||
|     if(LL_TIM_IsActiveFlag_CC2(TIM2)) { |     if(LL_TIM_IsActiveFlag_CC2(TIM2)) { | ||||||
|         LL_TIM_ClearFlag_CC2(TIM2); |         LL_TIM_ClearFlag_CC2(TIM2); | ||||||
|         if(furi_hal_subghz_capture_callback) { |         if(furi_hal_subghz_capture_callback) { | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |             if(furi_hal_subghz.async_mirror_pin != NULL) | ||||||
|             furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, true); |                 furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true); | ||||||
| #endif | 
 | ||||||
|             furi_hal_subghz_capture_callback( |             furi_hal_subghz_capture_callback( | ||||||
|                 false, |                 false, | ||||||
|                 LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, |                 LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration, | ||||||
| @ -459,10 +468,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* | |||||||
|     LL_TIM_SetCounter(TIM2, 0); |     LL_TIM_SetCounter(TIM2, 0); | ||||||
|     LL_TIM_EnableCounter(TIM2); |     LL_TIM_EnableCounter(TIM2); | ||||||
| 
 | 
 | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |     // Start debug
 | ||||||
|     furi_hal_gpio_init( |     furi_hal_subghz_start_debug(); | ||||||
|         &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     // Switch to RX
 |     // Switch to RX
 | ||||||
|     furi_hal_subghz_rx(); |     furi_hal_subghz_rx(); | ||||||
| @ -478,9 +485,8 @@ void furi_hal_subghz_stop_async_rx() { | |||||||
|     FURI_CRITICAL_ENTER(); |     FURI_CRITICAL_ENTER(); | ||||||
|     LL_TIM_DeInit(TIM2); |     LL_TIM_DeInit(TIM2); | ||||||
| 
 | 
 | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |     // Stop debug
 | ||||||
|     furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_subghz_stop_debug(); | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     FURI_CRITICAL_EXIT(); |     FURI_CRITICAL_EXIT(); | ||||||
|     furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); |     furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); | ||||||
| @ -673,15 +679,13 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|     LL_TIM_SetCounter(TIM2, 0); |     LL_TIM_SetCounter(TIM2, 0); | ||||||
|     LL_TIM_EnableCounter(TIM2); |     LL_TIM_EnableCounter(TIM2); | ||||||
| 
 | 
 | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |     // Start debug
 | ||||||
|     furi_hal_gpio_init( |     if(furi_hal_subghz_start_debug()) { | ||||||
|         &SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); |         const GpioPin* gpio = furi_hal_subghz.async_mirror_pin; | ||||||
|  |         furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; | ||||||
|  |         furi_hal_subghz_debug_gpio_buff[1] = gpio->pin; | ||||||
| 
 | 
 | ||||||
|     const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN; |         dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff; | ||||||
|     subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; |  | ||||||
|     subghz_debug_gpio_buff[1] = gpio->pin; |  | ||||||
| 
 |  | ||||||
|     dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff; |  | ||||||
|         dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); |         dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR); | ||||||
|         dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; |         dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; | ||||||
|         dma_config.Mode = LL_DMA_MODE_CIRCULAR; |         dma_config.Mode = LL_DMA_MODE_CIRCULAR; | ||||||
| @ -695,8 +699,7 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* | |||||||
|         LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); |         LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); | ||||||
|         LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2); |         LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2); | ||||||
|         LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); |         LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); | ||||||
| 
 |     } | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| @ -730,10 +733,10 @@ void furi_hal_subghz_stop_async_tx() { | |||||||
|     // Deinitialize GPIO
 |     // Deinitialize GPIO
 | ||||||
|     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||||
| 
 | 
 | ||||||
| #ifdef SUBGHZ_DEBUG_CC1101_PIN |     // Stop debug
 | ||||||
|  |     if(furi_hal_subghz_stop_debug()) { | ||||||
|         LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); |         LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); | ||||||
|     furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow); |     } | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|     FURI_CRITICAL_EXIT(); |     FURI_CRITICAL_EXIT(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,16 +4,63 @@ | |||||||
|  */ |  */ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | /** Init speaker */ | ||||||
| void furi_hal_speaker_init(); | void furi_hal_speaker_init(); | ||||||
| 
 | 
 | ||||||
|  | /** Deinit speaker */ | ||||||
|  | void furi_hal_speaker_deinit(); | ||||||
|  | 
 | ||||||
|  | /** Acquire speaker ownership
 | ||||||
|  |  * | ||||||
|  |  * @warning    You must acquire speaker ownership before use | ||||||
|  |  * | ||||||
|  |  * @param      timeout  Timeout during which speaker ownership must be acquired | ||||||
|  |  * | ||||||
|  |  * @return     bool  returns true on success | ||||||
|  |  */ | ||||||
|  | FURI_WARN_UNUSED bool furi_hal_speaker_acquire(uint32_t timeout); | ||||||
|  | 
 | ||||||
|  | /** Release speaker ownership
 | ||||||
|  |  * | ||||||
|  |  * @warning    You must release speaker ownership after use | ||||||
|  |  */ | ||||||
|  | void furi_hal_speaker_release(); | ||||||
|  | 
 | ||||||
|  | /** Check current process speaker ownership
 | ||||||
|  |  * | ||||||
|  |  * @warning    always returns true if called from ISR | ||||||
|  |  * | ||||||
|  |  * @return     bool returns true if process owns speaker | ||||||
|  |  */ | ||||||
|  | bool furi_hal_speaker_is_mine(); | ||||||
|  | 
 | ||||||
|  | /** Play a note
 | ||||||
|  |  * | ||||||
|  |  * @warning    no ownership check if called from ISR | ||||||
|  |  * | ||||||
|  |  * @param      frequency  The frequency | ||||||
|  |  * @param      volume     The volume | ||||||
|  |  */ | ||||||
| void furi_hal_speaker_start(float frequency, float volume); | void furi_hal_speaker_start(float frequency, float volume); | ||||||
| 
 | 
 | ||||||
|  | /** Set volume
 | ||||||
|  |  * | ||||||
|  |  * @warning    no ownership check if called from ISR | ||||||
|  |  * | ||||||
|  |  * @param      volume  The volume | ||||||
|  |  */ | ||||||
| void furi_hal_speaker_set_volume(float volume); | void furi_hal_speaker_set_volume(float volume); | ||||||
| 
 | 
 | ||||||
|  | /** Stop playback
 | ||||||
|  |  * | ||||||
|  |  * @warning    no ownership check if called from ISR | ||||||
|  |  */ | ||||||
| void furi_hal_speaker_stop(); | void furi_hal_speaker_stop(); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ | |||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stddef.h> | #include <stddef.h> | ||||||
| #include <toolbox/level_duration.h> | #include <toolbox/level_duration.h> | ||||||
|  | #include <furi_hal_gpio.h> | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" { | extern "C" { | ||||||
| @ -34,9 +35,9 @@ typedef enum { | |||||||
| /** Switchable Radio Paths */ | /** Switchable Radio Paths */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     FuriHalSubGhzPathIsolate, /**< Isolate Radio from antenna */ |     FuriHalSubGhzPathIsolate, /**< Isolate Radio from antenna */ | ||||||
|     FuriHalSubGhzPath433, /**< Center Frquency: 433MHz. Path 1: SW1RF1-SW2RF2, LCLCL */ |     FuriHalSubGhzPath433, /**< Center Frequency: 433MHz. Path 1: SW1RF1-SW2RF2, LCLCL */ | ||||||
|     FuriHalSubGhzPath315, /**< Center Frquency: 315MHz. Path 2: SW1RF2-SW2RF1, LCLCLCL */ |     FuriHalSubGhzPath315, /**< Center Frequency: 315MHz. Path 2: SW1RF2-SW2RF1, LCLCLCL */ | ||||||
|     FuriHalSubGhzPath868, /**< Center Frquency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */ |     FuriHalSubGhzPath868, /**< Center Frequency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */ | ||||||
| } FuriHalSubGhzPath; | } FuriHalSubGhzPath; | ||||||
| 
 | 
 | ||||||
| /** SubGhz state */ | /** SubGhz state */ | ||||||
| @ -60,8 +61,17 @@ typedef enum { | |||||||
|     SubGhzRegulationTxRx, /**TxRx*/ |     SubGhzRegulationTxRx, /**TxRx*/ | ||||||
| } SubGhzRegulation; | } SubGhzRegulation; | ||||||
| 
 | 
 | ||||||
|  | /* Mirror RX/TX async modulation signal to specified pin
 | ||||||
|  |  * | ||||||
|  |  * @warning    Configures pin to output mode. Make sure it is not connected | ||||||
|  |  *             directly to power or ground. | ||||||
|  |  * | ||||||
|  |  * @param[in]  pin   pointer to the gpio pin structure or NULL to disable | ||||||
|  |  */ | ||||||
|  | void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin); | ||||||
|  | 
 | ||||||
| /** Initialize and switch to power save mode Used by internal API-HAL
 | /** Initialize and switch to power save mode Used by internal API-HAL
 | ||||||
|  * initalization routine Can be used to reinitialize device to safe state and |  * initialization routine Can be used to reinitialize device to safe state and | ||||||
|  * send it to sleep |  * send it to sleep | ||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_init(); | void furi_hal_subghz_init(); | ||||||
| @ -105,13 +115,13 @@ void furi_hal_subghz_load_patable(const uint8_t data[8]); | |||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size); | void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size); | ||||||
| 
 | 
 | ||||||
| /** Check if recieve pipe is not empty
 | /** Check if receive pipe is not empty
 | ||||||
|  * |  * | ||||||
|  * @return     true if not empty |  * @return     true if not empty | ||||||
|  */ |  */ | ||||||
| bool furi_hal_subghz_rx_pipe_not_empty(); | bool furi_hal_subghz_rx_pipe_not_empty(); | ||||||
| 
 | 
 | ||||||
| /** Check if recieved data crc is valid
 | /** Check if received data crc is valid
 | ||||||
|  * |  * | ||||||
|  * @return     true if valid |  * @return     true if valid | ||||||
|  */ |  */ | ||||||
| @ -132,7 +142,7 @@ void furi_hal_subghz_flush_rx(); | |||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_flush_tx(); | void furi_hal_subghz_flush_tx(); | ||||||
| 
 | 
 | ||||||
| /** Shutdown Issue spwd command
 | /** Shutdown Issue SPWD command
 | ||||||
|  * @warning    registers content will be lost |  * @warning    registers content will be lost | ||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_shutdown(); | void furi_hal_subghz_shutdown(); | ||||||
| @ -146,7 +156,7 @@ void furi_hal_subghz_reset(); | |||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_idle(); | void furi_hal_subghz_idle(); | ||||||
| 
 | 
 | ||||||
| /** Switch to Recieve
 | /** Switch to Receive
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_subghz_rx(); | void furi_hal_subghz_rx(); | ||||||
| 
 | 
 | ||||||
| @ -172,7 +182,7 @@ uint8_t furi_hal_subghz_get_lqi(); | |||||||
|  * |  * | ||||||
|  * @param      value  frequency in Hz |  * @param      value  frequency in Hz | ||||||
|  * |  * | ||||||
|  * @return     true if frequncy is valid, otherwise false |  * @return     true if frequency is valid, otherwise false | ||||||
|  */ |  */ | ||||||
| bool furi_hal_subghz_is_frequency_valid(uint32_t value); | bool furi_hal_subghz_is_frequency_valid(uint32_t value); | ||||||
| 
 | 
 | ||||||
| @ -181,7 +191,7 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value); | |||||||
|  * |  * | ||||||
|  * @param      value  frequency in Hz |  * @param      value  frequency in Hz | ||||||
|  * |  * | ||||||
|  * @return     real frequency in herz |  * @return     real frequency in Hz | ||||||
|  */ |  */ | ||||||
| uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); | uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); | ||||||
| 
 | 
 | ||||||
| @ -189,7 +199,7 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value); | |||||||
|  * |  * | ||||||
|  * @param      value  frequency in Hz |  * @param      value  frequency in Hz | ||||||
|  * |  * | ||||||
|  * @return     real frequency in herz |  * @return     real frequency in Hz | ||||||
|  */ |  */ | ||||||
| uint32_t furi_hal_subghz_set_frequency(uint32_t value); | uint32_t furi_hal_subghz_set_frequency(uint32_t value); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,6 +11,10 @@ extern "C" { | |||||||
| 
 | 
 | ||||||
| #include <cmsis_compiler.h> | #include <cmsis_compiler.h> | ||||||
| 
 | 
 | ||||||
|  | #ifndef FURI_WARN_UNUSED | ||||||
|  | #define FURI_WARN_UNUSED __attribute__((warn_unused_result)) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifndef FURI_IS_IRQ_MASKED | #ifndef FURI_IS_IRQ_MASKED | ||||||
| #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) | #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Skorpionm
						Skorpionm